Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 20be72c8

History | View | Annotate | Download (15.5 KB)

1
/*
2
 * Ogg bitstream support
3
 * Luca Barbato <lu_zero@gentoo.org>
4
 * Based on tcvp implementation
5
 *
6
 */
7

    
8
/**
9
    Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
10

11
    Permission is hereby granted, free of charge, to any person
12
    obtaining a copy of this software and associated documentation
13
    files (the "Software"), to deal in the Software without
14
    restriction, including without limitation the rights to use, copy,
15
    modify, merge, publish, distribute, sublicense, and/or sell copies
16
    of the Software, and to permit persons to whom the Software is
17
    furnished to do so, subject to the following conditions:
18

19
    The above copyright notice and this permission notice shall be
20
    included in all copies or substantial portions of the Software.
21

22
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
    DEALINGS IN THE SOFTWARE.
30
**/
31

    
32

    
33
#include <stdio.h>
34
#include "ogg2.h"
35
#include "avformat.h"
36

    
37
#define MAX_PAGE_SIZE 65307
38
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39

    
40
static ogg_codec_t *ogg_codecs[] = {
41
    &vorbis_codec,
42
    &theora_codec,
43
    &flac_codec,
44
    &ogm_video_codec,
45
    &ogm_audio_codec,
46
    &ogm_old_codec,
47
    NULL
48
};
49

    
50
#if 0                           // CONFIG_MUXERS
51
static int
52
ogg_write_header (AVFormatContext * avfcontext)
53
{
54
}
55

56
static int
57
ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
58
{
59
}
60

61

62
static int
63
ogg_write_trailer (AVFormatContext * avfcontext)
64
{
65
}
66

67

68
AVOutputFormat ogg_muxer = {
69
    "ogg",
70
    "Ogg Vorbis",
71
    "audio/x-vorbis",
72
    "ogg",
73
    sizeof (OggContext),
74
    CODEC_ID_VORBIS,
75
    0,
76
    ogg_write_header,
77
    ogg_write_packet,
78
    ogg_write_trailer,
79
};
80
#endif //CONFIG_MUXERS
81

    
82
//FIXME We could avoid some structure duplication
83
static int
84
ogg_save (AVFormatContext * s)
85
{
86
    ogg_t *ogg = s->priv_data;
87
    ogg_state_t *ost =
88
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
89
    int i;
90
    ost->pos = url_ftell (&s->pb);;
91
    ost->curidx = ogg->curidx;
92
    ost->next = ogg->state;
93
    ost->nstreams = ogg->nstreams;
94
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
95

    
96
    for (i = 0; i < ogg->nstreams; i++){
97
        ogg_stream_t *os = ogg->streams + i;
98
        os->buf = av_malloc (os->bufsize);
99
        memset (os->buf, 0, os->bufsize);
100
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
101
    }
102

    
103
    ogg->state = ost;
104

    
105
    return 0;
106
}
107

    
108
static int
109
ogg_restore (AVFormatContext * s, int discard)
110
{
111
    ogg_t *ogg = s->priv_data;
112
    ByteIOContext *bc = &s->pb;
113
    ogg_state_t *ost = ogg->state;
114
    int i;
115

    
116
    if (!ost)
117
        return 0;
118

    
119
    ogg->state = ost->next;
120

    
121
    if (!discard){
122
        for (i = 0; i < ogg->nstreams; i++)
123
            av_free (ogg->streams[i].buf);
124

    
125
        url_fseek (bc, ost->pos, SEEK_SET);
126
        ogg->curidx = ost->curidx;
127
        ogg->nstreams = ost->nstreams;
128
        memcpy(ogg->streams, ost->streams,
129
               ost->nstreams * sizeof(*ogg->streams));
130
    }
131

    
132
    av_free (ost);
133

    
134
    return 0;
135
}
136

    
137
static int
138
ogg_reset (ogg_t * ogg)
139
{
140
    int i;
141

    
142
    for (i = 0; i < ogg->nstreams; i++){
143
        ogg_stream_t *os = ogg->streams + i;
144
        os->bufpos = 0;
145
        os->pstart = 0;
146
        os->psize = 0;
147
        os->granule = -1;
148
        os->lastgp = -1;
149
        os->nsegs = 0;
150
        os->segp = 0;
151
    }
152

    
153
    ogg->curidx = -1;
154

    
155
    return 0;
156
}
157

    
158
static ogg_codec_t *
159
ogg_find_codec (uint8_t * buf, int size)
160
{
161
    int i;
162

    
163
    for (i = 0; ogg_codecs[i]; i++)
164
        if (size >= ogg_codecs[i]->magicsize &&
165
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
166
            return ogg_codecs[i];
167

    
168
    return NULL;
169
}
170

    
171
static int
172
ogg_find_stream (ogg_t * ogg, int serial)
173
{
174
    int i;
175

    
176
    for (i = 0; i < ogg->nstreams; i++)
177
        if (ogg->streams[i].serial == serial)
178
            return i;
179

    
180
    return -1;
181
}
182

    
183
static int
184
ogg_new_stream (AVFormatContext * s, uint32_t serial)
185
{
186

    
187
    ogg_t *ogg = s->priv_data;
188
    int idx = ogg->nstreams++;
189
    AVStream *st;
190
    ogg_stream_t *os;
191

    
192
    ogg->streams = av_realloc (ogg->streams,
193
                               ogg->nstreams * sizeof (*ogg->streams));
194
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
195
    os = ogg->streams + idx;
196
    os->serial = serial;
197
    os->bufsize = DECODER_BUFFER_SIZE;
198
    os->buf = av_malloc(os->bufsize);
199
    os->header = -1;
200

    
201
    st = av_new_stream (s, idx);
202
    if (!st)
203
        return AVERROR_NOMEM;
204

    
205
    av_set_pts_info(st, 64, 1, 1000000);
206

    
207
    return idx;
208
}
209

    
210
static int
211
ogg_new_buf(ogg_t *ogg, int idx)
212
{
213
    ogg_stream_t *os = ogg->streams + idx;
214
    uint8_t *nb = av_malloc(os->bufsize);
215
    int size = os->bufpos - os->pstart;
216
    if(os->buf){
217
        memcpy(nb, os->buf + os->pstart, size);
218
        av_free(os->buf);
219
    }
220
    os->buf = nb;
221
    os->bufpos = size;
222
    os->pstart = 0;
223

    
224
    return 0;
225
}
226

    
227
static int
228
ogg_read_page (AVFormatContext * s, int *str)
229
{
230
    ByteIOContext *bc = &s->pb;
231
    ogg_t *ogg = s->priv_data;
232
    ogg_stream_t *os;
233
    int i = 0;
234
    int flags, nsegs;
235
    uint64_t gp;
236
    uint32_t serial;
237
    uint32_t seq;
238
    uint32_t crc;
239
    int size, idx;
240
    uint8_t sync[4];
241
    int sp = 0;
242

    
243
    if (get_buffer (bc, sync, 4) < 4)
244
        return -1;
245

    
246
    do{
247
        int c;
248

    
249
        if (sync[sp & 3] == 'O' &&
250
            sync[(sp + 1) & 3] == 'g' &&
251
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
252
            break;
253

    
254
        c = url_fgetc (bc);
255
        if (c < 0)
256
            return -1;
257
        sync[sp++ & 3] = c;
258
    }while (i++ < MAX_PAGE_SIZE);
259

    
260
    if (i >= MAX_PAGE_SIZE){
261
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
262
        return -1;
263
    }
264

    
265
    if (url_fgetc (bc) != 0)      /* version */
266
        return -1;
267

    
268
    flags = url_fgetc (bc);
269
    gp = get_le64 (bc);
270
    serial = get_le32 (bc);
271
    seq = get_le32 (bc);
272
    crc = get_le32 (bc);
273
    nsegs = url_fgetc (bc);
274

    
275
    idx = ogg_find_stream (ogg, serial);
276
    if (idx < 0){
277
        idx = ogg_new_stream (s, serial);
278
        if (idx < 0)
279
            return -1;
280
    }
281

    
282
    os = ogg->streams + idx;
283

    
284
    if(os->psize > 0)
285
        ogg_new_buf(ogg, idx);
286

    
287
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
288
        return -1;
289

    
290
    os->nsegs = nsegs;
291
    os->segp = 0;
292

    
293
    size = 0;
294
    for (i = 0; i < nsegs; i++)
295
        size += os->segments[i];
296

    
297
    if (flags & OGG_FLAG_CONT){
298
        if (!os->psize){
299
            while (os->segp < os->nsegs){
300
                int seg = os->segments[os->segp++];
301
                os->pstart += seg;
302
                if (seg < 255)
303
                  break;
304
            }
305
        }
306
    }else{
307
      os->psize = 0;
308
    }
309

    
310
    if (os->bufsize - os->bufpos < size){
311
        uint8_t *nb = av_malloc (os->bufsize *= 2);
312
        memcpy (nb, os->buf, os->bufpos);
313
        av_free (os->buf);
314
        os->buf = nb;
315
    }
316

    
317
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
318
        return -1;
319

    
320
    os->lastgp = os->granule;
321
    os->bufpos += size;
322
    os->granule = gp;
323
    os->flags = flags;
324

    
325
    if (str)
326
        *str = idx;
327

    
328
    return 0;
329
}
330

    
331
static int
332
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
333
{
334
    ogg_t *ogg = s->priv_data;
335
    int idx;
336
    ogg_stream_t *os;
337
    int complete = 0;
338
    int segp = 0, psize = 0;
339

    
340
#if 0
341
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
342
#endif
343

    
344
    do{
345
        idx = ogg->curidx;
346

    
347
        while (idx < 0){
348
            if (ogg_read_page (s, &idx) < 0)
349
                return -1;
350
        }
351

    
352
        os = ogg->streams + idx;
353

    
354
#if 0
355
        av_log (s, AV_LOG_DEBUG,
356
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
357
                idx, os->pstart, os->psize, os->segp, os->nsegs);
358
#endif
359

    
360
        if (!os->codec){
361
            if (os->header < 0){
362
                os->codec = ogg_find_codec (os->buf, os->bufpos);
363
                if (!os->codec){
364
                    os->header = 0;
365
                    return 0;
366
                }
367
            }else{
368
                return 0;
369
            }
370
        }
371

    
372
        segp = os->segp;
373
        psize = os->psize;
374

    
375
        while (os->segp < os->nsegs){
376
            int ss = os->segments[os->segp++];
377
            os->psize += ss;
378
            if (ss < 255){
379
                complete = 1;
380
                break;
381
            }
382
        }
383

    
384
        if (!complete && os->segp == os->nsegs){
385
            ogg->curidx = -1;
386
        }
387
    }while (!complete);
388

    
389
#if 0
390
    av_log (s, AV_LOG_DEBUG,
391
            "ogg_packet: idx %i, frame size %i, start %i\n",
392
            idx, os->psize, os->pstart);
393
#endif
394

    
395
    ogg->curidx = idx;
396

    
397
    if (os->header < 0){
398
        int hdr = os->codec->header (s, idx);
399
        if (!hdr){
400
          os->header = os->seq;
401
          os->segp = segp;
402
          os->psize = psize;
403
          ogg->headers = 1;
404
        }else{
405
          os->pstart += os->psize;
406
          os->psize = 0;
407
        }
408
    }
409

    
410
    if (os->header > -1 && os->seq > os->header){
411
        if (os->codec && os->codec->packet)
412
            os->codec->packet (s, idx);
413
        if (str)
414
            *str = idx;
415
        if (dstart)
416
            *dstart = os->pstart;
417
        if (dsize)
418
            *dsize = os->psize;
419
        os->pstart += os->psize;
420
        os->psize = 0;
421
    }
422

    
423
    os->seq++;
424
    if (os->segp == os->nsegs)
425
        ogg->curidx = -1;
426

    
427
    return 0;
428
}
429

    
430
static int
431
ogg_get_headers (AVFormatContext * s)
432
{
433
    ogg_t *ogg = s->priv_data;
434

    
435
    do{
436
        if (ogg_packet (s, NULL, NULL, NULL) < 0)
437
            return -1;
438
    }while (!ogg->headers);
439

    
440
#if 0
441
    av_log (s, AV_LOG_DEBUG, "found headers\n");
442
#endif
443

    
444
    return 0;
445
}
446

    
447
static uint64_t
448
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
449
{
450
    ogg_t *ogg = s->priv_data;
451
    ogg_stream_t *os = ogg->streams + i;
452
    uint64_t pts = AV_NOPTS_VALUE;
453

    
454
    if(os->codec->gptopts){
455
        pts = os->codec->gptopts(s, i, gp);
456
    } else {
457
        pts = gp;
458
    }
459

    
460
    return pts;
461
}
462

    
463

    
464
static int
465
ogg_get_length (AVFormatContext * s)
466
{
467
    ogg_t *ogg = s->priv_data;
468
    int idx = -1, i;
469
    offset_t size, end;
470

    
471
    if(s->pb.is_streamed)
472
        return 0;
473

    
474
// already set
475
    if (s->duration != AV_NOPTS_VALUE)
476
        return 0;
477

    
478
    size = url_fsize(&s->pb);
479
    if(size < 0)
480
        return 0;
481
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
482

    
483
    ogg_save (s);
484
    url_fseek (&s->pb, end, SEEK_SET);
485

    
486
    while (!ogg_read_page (s, &i)){
487
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
488
            idx = i;
489
    }
490

    
491
    if (idx != -1){
492
        s->streams[idx]->duration =
493
            ogg_gptopts (s, idx, ogg->streams[idx].granule);
494
    }
495

    
496
    ogg->size = size;
497
    ogg_restore (s, 0);
498
    ogg_save (s);
499
    while (!ogg_read_page (s, &i)) {
500
        if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
501
            break;
502
    }
503
    if (i == idx) {
504
        s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
505
        s->streams[idx]->duration -= s->streams[idx]->start_time;
506
    }
507
    ogg_restore (s, 0);
508

    
509
    return 0;
510
}
511

    
512

    
513
static int
514
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
515
{
516
    ogg_t *ogg = s->priv_data;
517
    ogg->curidx = -1;
518
    //linear headers seek from start
519
    if (ogg_get_headers (s) < 0){
520
      return -1;
521
    }
522

    
523
    //linear granulepos seek from end
524
    ogg_get_length (s);
525

    
526
    //fill the extradata in the per codec callbacks
527
    return 0;
528
}
529

    
530

    
531
static int
532
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
533
{
534
    ogg_t *ogg;
535
    ogg_stream_t *os;
536
    int idx = -1;
537
    int pstart, psize;
538

    
539
    //Get an ogg packet
540
    do{
541
        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
542
            return AVERROR_IO;
543
    }while (idx < 0 || !s->streams[idx]);
544

    
545
    ogg = s->priv_data;
546
    os = ogg->streams + idx;
547

    
548
    //Alloc a pkt
549
    if (av_new_packet (pkt, psize) < 0)
550
        return AVERROR_IO;
551
    pkt->stream_index = idx;
552
    memcpy (pkt->data, os->buf + pstart, psize);
553
    if (os->lastgp != -1LL){
554
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
555
        os->lastgp = -1;
556
    }
557

    
558
    return psize;
559
}
560

    
561

    
562
static int
563
ogg_read_close (AVFormatContext * s)
564
{
565
    ogg_t *ogg = s->priv_data;
566
    int i;
567

    
568
    for (i = 0; i < ogg->nstreams; i++){
569
        av_free (ogg->streams[i].buf);
570
        av_free (ogg->streams[i].private);
571
    }
572
    av_free (ogg->streams);
573
    return 0;
574
}
575

    
576

    
577
static int
578
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
579
               int flags)
580
{
581
    AVStream *st = s->streams[stream_index];
582
    ogg_t *ogg = s->priv_data;
583
    ByteIOContext *bc = &s->pb;
584
    uint64_t min = 0, max = ogg->size;
585
    uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
586
    int64_t pts = AV_NOPTS_VALUE;
587

    
588
    ogg_save (s);
589

    
590
    if ((uint64_t)target_ts < tmin || target_ts < 0)
591
        target_ts = tmin;
592
    while (min <= max && tmin < tmax){
593
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
594
        int i = -1;
595

    
596
        url_fseek (bc, p, SEEK_SET);
597

    
598
        while (!ogg_read_page (s, &i)){
599
            if (i == stream_index && ogg->streams[i].granule != 0 &&
600
                ogg->streams[i].granule != -1)
601
                break;
602
        }
603

    
604
        if (i == -1)
605
            break;
606

    
607
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
608
        p = url_ftell (bc);
609

    
610
        if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den)
611
            break;
612

    
613
        if (pts > target_ts){
614
            if (max == p && tmax == pts) {
615
                // probably our tmin is wrong, causing us to always end up too late in the file
616
                tmin = (target_ts + tmin + 1) / 2;
617
                if (tmin == target_ts) {
618
                    url_fseek(bc, min, SEEK_SET);
619
                    break;
620
                }
621
            }
622
            max = p;
623
            tmax = pts;
624
        }else{
625
            if (min == p && tmin == pts) {
626
                // probably our tmax is wrong, causing us to always end up too early in the file
627
                tmax = (target_ts + tmax) / 2;
628
                if (tmax == target_ts) {
629
                    url_fseek(bc, max, SEEK_SET);
630
                    break;
631
                }
632
            }
633
            min = p;
634
            tmin = pts;
635
        }
636
    }
637

    
638
    if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den){
639
        ogg_restore (s, 1);
640
        ogg_reset (ogg);
641
    }else{
642
        ogg_restore (s, 0);
643
        pts = AV_NOPTS_VALUE;
644
    }
645

    
646
    av_update_cur_dts(s, st, pts);
647
    return 0;
648

    
649
#if 0
650
    //later...
651
    int64_t pos;
652
    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
653
        return -1;
654
    pos = url_ftell (&s->pb);
655
    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
656
#endif
657

    
658
}
659

    
660
#if 0
661
static int64_t
662
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
663
                    int64_t pos_limit)
664
{
665
    ogg_t *ogg = s->priv_data;
666
    ByteIOContext *bc = &s->pb;
667
    int64_t pos, pts;
668

669
    if (*pos_arg < 0)
670
        return AV_NOPTS_VALUE;
671

672
    pos = *pos_arg;
673
}
674
#endif
675

    
676
static int ogg_probe(AVProbeData *p)
677
{
678
    if (p->buf_size < 6)
679
        return 0;
680
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
681
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
682
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
683
        return AVPROBE_SCORE_MAX;
684
    else
685
        return 0;
686
}
687

    
688
AVInputFormat ogg_demuxer = {
689
    "ogg",
690
    "Ogg",
691
    sizeof (ogg_t),
692
    ogg_probe,
693
    ogg_read_header,
694
    ogg_read_packet,
695
    ogg_read_close,
696
    ogg_read_seek,
697
// ogg_read_timestamp,
698
    .extensions = "ogg",
699
};