Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ c104a6e9

History | View | Annotate | Download (16.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 "oggdec.h"
35
#include "avformat.h"
36
#include "vorbiscomment.h"
37

    
38
#define MAX_PAGE_SIZE 65307
39
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40

    
41
static const struct ogg_codec * const ogg_codecs[] = {
42
    &ff_skeleton_codec,
43
    &ff_dirac_codec,
44
    &ff_speex_codec,
45
    &ff_vorbis_codec,
46
    &ff_theora_codec,
47
    &ff_flac_codec,
48
    &ff_old_dirac_codec,
49
    &ff_old_flac_codec,
50
    &ff_ogm_video_codec,
51
    &ff_ogm_audio_codec,
52
    &ff_ogm_text_codec,
53
    &ff_ogm_old_codec,
54
    NULL
55
};
56

    
57
//FIXME We could avoid some structure duplication
58
static int
59
ogg_save (AVFormatContext * s)
60
{
61
    struct ogg *ogg = s->priv_data;
62
    struct ogg_state *ost =
63
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64
    int i;
65
    ost->pos = avio_tell (s->pb);
66
    ost->curidx = ogg->curidx;
67
    ost->next = ogg->state;
68
    ost->nstreams = ogg->nstreams;
69
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70

    
71
    for (i = 0; i < ogg->nstreams; i++){
72
        struct ogg_stream *os = ogg->streams + i;
73
        os->buf = av_malloc (os->bufsize);
74
        memset (os->buf, 0, os->bufsize);
75
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
76
    }
77

    
78
    ogg->state = ost;
79

    
80
    return 0;
81
}
82

    
83
static int
84
ogg_restore (AVFormatContext * s, int discard)
85
{
86
    struct ogg *ogg = s->priv_data;
87
    AVIOContext *bc = s->pb;
88
    struct ogg_state *ost = ogg->state;
89
    int i;
90

    
91
    if (!ost)
92
        return 0;
93

    
94
    ogg->state = ost->next;
95

    
96
    if (!discard){
97
        for (i = 0; i < ogg->nstreams; i++)
98
            av_free (ogg->streams[i].buf);
99

    
100
        avio_seek (bc, ost->pos, SEEK_SET);
101
        ogg->curidx = ost->curidx;
102
        ogg->nstreams = ost->nstreams;
103
        memcpy(ogg->streams, ost->streams,
104
               ost->nstreams * sizeof(*ogg->streams));
105
    }
106

    
107
    av_free (ost);
108

    
109
    return 0;
110
}
111

    
112
static int
113
ogg_reset (struct ogg * ogg)
114
{
115
    int i;
116

    
117
    for (i = 0; i < ogg->nstreams; i++){
118
        struct ogg_stream *os = ogg->streams + i;
119
        os->bufpos = 0;
120
        os->pstart = 0;
121
        os->psize = 0;
122
        os->granule = -1;
123
        os->lastpts = AV_NOPTS_VALUE;
124
        os->lastdts = AV_NOPTS_VALUE;
125
        os->sync_pos = -1;
126
        os->page_pos = 0;
127
        os->nsegs = 0;
128
        os->segp = 0;
129
        os->incomplete = 0;
130
    }
131

    
132
    ogg->curidx = -1;
133

    
134
    return 0;
135
}
136

    
137
static const struct ogg_codec *
138
ogg_find_codec (uint8_t * buf, int size)
139
{
140
    int i;
141

    
142
    for (i = 0; ogg_codecs[i]; i++)
143
        if (size >= ogg_codecs[i]->magicsize &&
144
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
145
            return ogg_codecs[i];
146

    
147
    return NULL;
148
}
149

    
150
static int
151
ogg_new_stream (AVFormatContext * s, uint32_t serial)
152
{
153

    
154
    struct ogg *ogg = s->priv_data;
155
    int idx = ogg->nstreams++;
156
    AVStream *st;
157
    struct ogg_stream *os;
158

    
159
    ogg->streams = av_realloc (ogg->streams,
160
                               ogg->nstreams * sizeof (*ogg->streams));
161
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
162
    os = ogg->streams + idx;
163
    os->serial = serial;
164
    os->bufsize = DECODER_BUFFER_SIZE;
165
    os->buf = av_malloc(os->bufsize);
166
    os->header = -1;
167
    os->page_begin = 1;
168

    
169
    st = av_new_stream (s, idx);
170
    if (!st)
171
        return AVERROR(ENOMEM);
172

    
173
    av_set_pts_info(st, 64, 1, 1000000);
174

    
175
    return idx;
176
}
177

    
178
static int
179
ogg_new_buf(struct ogg *ogg, int idx)
180
{
181
    struct ogg_stream *os = ogg->streams + idx;
182
    uint8_t *nb = av_malloc(os->bufsize);
183
    int size = os->bufpos - os->pstart;
184
    if(os->buf){
185
        memcpy(nb, os->buf + os->pstart, size);
186
        av_free(os->buf);
187
    }
188
    os->buf = nb;
189
    os->bufpos = size;
190
    os->pstart = 0;
191

    
192
    return 0;
193
}
194

    
195
static int
196
ogg_read_page (AVFormatContext * s, int *str)
197
{
198
    AVIOContext *bc = s->pb;
199
    struct ogg *ogg = s->priv_data;
200
    struct ogg_stream *os;
201
    int i = 0;
202
    int flags, nsegs;
203
    uint64_t gp;
204
    uint32_t serial;
205
    uint32_t seq;
206
    uint32_t crc;
207
    int size, idx;
208
    uint8_t sync[4];
209
    int sp = 0;
210

    
211
    if (avio_read (bc, sync, 4) < 4)
212
        return -1;
213

    
214
    do{
215
        int c;
216

    
217
        if (sync[sp & 3] == 'O' &&
218
            sync[(sp + 1) & 3] == 'g' &&
219
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
220
            break;
221

    
222
        c = avio_r8(bc);
223
        if (url_feof(bc))
224
            return -1;
225
        sync[sp++ & 3] = c;
226
    }while (i++ < MAX_PAGE_SIZE);
227

    
228
    if (i >= MAX_PAGE_SIZE){
229
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
230
        return -1;
231
    }
232

    
233
    if (avio_r8(bc) != 0)      /* version */
234
        return -1;
235

    
236
    flags = avio_r8(bc);
237
    gp = avio_rl64 (bc);
238
    serial = avio_rl32 (bc);
239
    seq = avio_rl32 (bc);
240
    crc = avio_rl32 (bc);
241
    nsegs = avio_r8(bc);
242

    
243
    idx = ogg_find_stream (ogg, serial);
244
    if (idx < 0){
245
        for (i = 0; i < ogg->nstreams; i++) {
246
            if (!ogg->streams[i].page_begin) {
247
                int n;
248

    
249
                for (n = 0; n < ogg->nstreams; n++) {
250
                    av_freep(&ogg->streams[n].buf);
251
                    av_freep(&ogg->streams[n].private);
252
                }
253
                ogg->curidx   = -1;
254
                ogg->nstreams = 0;
255
                break;
256
            }
257
        }
258
        idx = ogg_new_stream (s, serial);
259
        if (idx < 0)
260
            return -1;
261
    }
262

    
263
    os = ogg->streams + idx;
264
    if (!(flags & OGG_FLAG_BOS))
265
        os->page_begin = 0;
266
    os->page_pos = avio_tell(bc) - 27;
267

    
268
    if(os->psize > 0)
269
        ogg_new_buf(ogg, idx);
270

    
271
    if (avio_read (bc, os->segments, nsegs) < nsegs)
272
        return -1;
273

    
274
    os->nsegs = nsegs;
275
    os->segp = 0;
276

    
277
    size = 0;
278
    for (i = 0; i < nsegs; i++)
279
        size += os->segments[i];
280

    
281
    if (flags & OGG_FLAG_CONT || os->incomplete){
282
        if (!os->psize){
283
            while (os->segp < os->nsegs){
284
                int seg = os->segments[os->segp++];
285
                os->pstart += seg;
286
                if (seg < 255)
287
                    break;
288
            }
289
            os->sync_pos = os->page_pos;
290
        }
291
    }else{
292
        os->psize = 0;
293
        os->sync_pos = os->page_pos;
294
    }
295

    
296
    if (os->bufsize - os->bufpos < size){
297
        uint8_t *nb = av_malloc (os->bufsize *= 2);
298
        memcpy (nb, os->buf, os->bufpos);
299
        av_free (os->buf);
300
        os->buf = nb;
301
    }
302

    
303
    if (avio_read (bc, os->buf + os->bufpos, size) < size)
304
        return -1;
305

    
306
    os->bufpos += size;
307
    os->granule = gp;
308
    os->flags = flags;
309

    
310
    if (str)
311
        *str = idx;
312

    
313
    return 0;
314
}
315

    
316
static int
317
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
318
{
319
    struct ogg *ogg = s->priv_data;
320
    int idx, i;
321
    struct ogg_stream *os;
322
    int complete = 0;
323
    int segp = 0, psize = 0;
324

    
325
#if 0
326
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
327
#endif
328

    
329
    do{
330
        idx = ogg->curidx;
331

    
332
        while (idx < 0){
333
            if (ogg_read_page (s, &idx) < 0)
334
                return -1;
335
        }
336

    
337
        os = ogg->streams + idx;
338

    
339
#if 0
340
        av_log (s, AV_LOG_DEBUG,
341
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
342
                idx, os->pstart, os->psize, os->segp, os->nsegs);
343
#endif
344

    
345
        if (!os->codec){
346
            if (os->header < 0){
347
                os->codec = ogg_find_codec (os->buf, os->bufpos);
348
                if (!os->codec){
349
                    os->header = 0;
350
                    return 0;
351
                }
352
            }else{
353
                return 0;
354
            }
355
        }
356

    
357
        segp = os->segp;
358
        psize = os->psize;
359

    
360
        while (os->segp < os->nsegs){
361
            int ss = os->segments[os->segp++];
362
            os->psize += ss;
363
            if (ss < 255){
364
                complete = 1;
365
                break;
366
            }
367
        }
368

    
369
        if (!complete && os->segp == os->nsegs){
370
            ogg->curidx = -1;
371
            os->incomplete = 1;
372
        }
373
    }while (!complete);
374

    
375
#if 0
376
    av_log (s, AV_LOG_DEBUG,
377
            "ogg_packet: idx %i, frame size %i, start %i\n",
378
            idx, os->psize, os->pstart);
379
#endif
380

    
381
    if (os->granule == -1)
382
        av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
383

    
384
    ogg->curidx = idx;
385
    os->incomplete = 0;
386

    
387
    if (os->header) {
388
        os->header = os->codec->header (s, idx);
389
        if (!os->header){
390
            os->segp = segp;
391
            os->psize = psize;
392

    
393
            // We have reached the first non-header packet in this stream.
394
            // Unfortunately more header packets may still follow for others,
395
            // but if we continue with header parsing we may lose data packets.
396
            ogg->headers = 1;
397

    
398
            // Update the header state for all streams and
399
            // compute the data_offset.
400
            if (!s->data_offset)
401
                s->data_offset = os->sync_pos;
402
            for (i = 0; i < ogg->nstreams; i++) {
403
                struct ogg_stream *cur_os = ogg->streams + i;
404

    
405
                // if we have a partial non-header packet, its start is
406
                // obviously at or after the data start
407
                if (cur_os->incomplete)
408
                    s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
409
            }
410
        }else{
411
            os->pstart += os->psize;
412
            os->psize = 0;
413
        }
414
    } else {
415
        os->pflags = 0;
416
        os->pduration = 0;
417
        if (os->codec && os->codec->packet)
418
            os->codec->packet (s, idx);
419
        if (str)
420
            *str = idx;
421
        if (dstart)
422
            *dstart = os->pstart;
423
        if (dsize)
424
            *dsize = os->psize;
425
        if (fpos)
426
            *fpos = os->sync_pos;
427
        os->pstart += os->psize;
428
        os->psize = 0;
429
        os->sync_pos = os->page_pos;
430
    }
431

    
432
    // determine whether there are more complete packets in this page
433
    // if not, the page's granule will apply to this packet
434
    os->page_end = 1;
435
    for (i = os->segp; i < os->nsegs; i++)
436
        if (os->segments[i] < 255) {
437
            os->page_end = 0;
438
            break;
439
        }
440

    
441
    if (os->segp == os->nsegs)
442
        ogg->curidx = -1;
443

    
444
    return 0;
445
}
446

    
447
static int
448
ogg_get_headers (AVFormatContext * s)
449
{
450
    struct ogg *ogg = s->priv_data;
451

    
452
    do{
453
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
454
            return -1;
455
    }while (!ogg->headers);
456

    
457
#if 0
458
    av_log (s, AV_LOG_DEBUG, "found headers\n");
459
#endif
460

    
461
    return 0;
462
}
463

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

    
471
    if(!s->pb->seekable)
472
        return 0;
473

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

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

    
483
    ogg_save (s);
484
    avio_seek (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
            ogg->streams[i].codec) {
489
            s->streams[i]->duration =
490
                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
491
            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
492
                s->streams[i]->duration -= s->streams[i]->start_time;
493
        }
494
    }
495

    
496
    ogg_restore (s, 0);
497

    
498
    return 0;
499
}
500

    
501

    
502
static int
503
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
504
{
505
    struct ogg *ogg = s->priv_data;
506
    int i;
507
    ogg->curidx = -1;
508
    //linear headers seek from start
509
    if (ogg_get_headers (s) < 0){
510
        return -1;
511
    }
512

    
513
    for (i = 0; i < ogg->nstreams; i++)
514
        if (ogg->streams[i].header < 0)
515
            ogg->streams[i].codec = NULL;
516

    
517
    //linear granulepos seek from end
518
    ogg_get_length (s);
519

    
520
    //fill the extradata in the per codec callbacks
521
    return 0;
522
}
523

    
524
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
525
{
526
    struct ogg *ogg = s->priv_data;
527
    struct ogg_stream *os = ogg->streams + idx;
528
    int64_t pts = AV_NOPTS_VALUE;
529

    
530
    if (dts)
531
        *dts = AV_NOPTS_VALUE;
532

    
533
    if (os->lastpts != AV_NOPTS_VALUE) {
534
        pts = os->lastpts;
535
        os->lastpts = AV_NOPTS_VALUE;
536
    }
537
    if (os->lastdts != AV_NOPTS_VALUE) {
538
        if (dts)
539
            *dts = os->lastdts;
540
        os->lastdts = AV_NOPTS_VALUE;
541
    }
542
    if (os->page_end) {
543
        if (os->granule != -1LL) {
544
            if (os->codec && os->codec->granule_is_start)
545
                pts = ogg_gptopts(s, idx, os->granule, dts);
546
            else
547
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
548
            os->granule = -1LL;
549
        }
550
    }
551
    return pts;
552
}
553

    
554
static int
555
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
556
{
557
    struct ogg *ogg;
558
    struct ogg_stream *os;
559
    int idx = -1;
560
    int pstart, psize;
561
    int64_t fpos, pts, dts;
562

    
563
    //Get an ogg packet
564
retry:
565
    do{
566
        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
567
            return AVERROR(EIO);
568
    }while (idx < 0 || !s->streams[idx]);
569

    
570
    ogg = s->priv_data;
571
    os = ogg->streams + idx;
572

    
573
    // pflags might not be set until after this
574
    pts = ogg_calc_pts(s, idx, &dts);
575

    
576
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
577
        goto retry;
578
    os->keyframe_seek = 0;
579

    
580
    //Alloc a pkt
581
    if (av_new_packet (pkt, psize) < 0)
582
        return AVERROR(EIO);
583
    pkt->stream_index = idx;
584
    memcpy (pkt->data, os->buf + pstart, psize);
585

    
586
    pkt->pts = pts;
587
    pkt->dts = dts;
588
    pkt->flags = os->pflags;
589
    pkt->duration = os->pduration;
590
    pkt->pos = fpos;
591

    
592
    return psize;
593
}
594

    
595

    
596
static int
597
ogg_read_close (AVFormatContext * s)
598
{
599
    struct ogg *ogg = s->priv_data;
600
    int i;
601

    
602
    for (i = 0; i < ogg->nstreams; i++){
603
        av_free (ogg->streams[i].buf);
604
        av_free (ogg->streams[i].private);
605
    }
606
    av_free (ogg->streams);
607
    return 0;
608
}
609

    
610

    
611
static int64_t
612
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
613
                    int64_t pos_limit)
614
{
615
    struct ogg *ogg = s->priv_data;
616
    struct ogg_stream *os = ogg->streams + stream_index;
617
    AVIOContext *bc = s->pb;
618
    int64_t pts = AV_NOPTS_VALUE;
619
    int i;
620
    avio_seek(bc, *pos_arg, SEEK_SET);
621
    ogg_reset(ogg);
622

    
623
    while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
624
        if (i == stream_index) {
625
            pts = ogg_calc_pts(s, i, NULL);
626
            if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
627
                pts = AV_NOPTS_VALUE;
628
        }
629
        if (pts != AV_NOPTS_VALUE)
630
            break;
631
    }
632
    ogg_reset(ogg);
633
    return pts;
634
}
635

    
636
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
637
{
638
    struct ogg *ogg = s->priv_data;
639
    struct ogg_stream *os = ogg->streams + stream_index;
640
    int ret;
641

    
642
    // Try seeking to a keyframe first. If this fails (very possible),
643
    // av_seek_frame will fall back to ignoring keyframes
644
    if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
645
        && !(flags & AVSEEK_FLAG_ANY))
646
        os->keyframe_seek = 1;
647

    
648
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
649
    if (ret < 0)
650
        os->keyframe_seek = 0;
651
    return ret;
652
}
653

    
654
static int ogg_probe(AVProbeData *p)
655
{
656
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
657
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
658
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
659
        return AVPROBE_SCORE_MAX;
660
    else
661
        return 0;
662
}
663

    
664
AVInputFormat ff_ogg_demuxer = {
665
    "ogg",
666
    NULL_IF_CONFIG_SMALL("Ogg"),
667
    sizeof (struct ogg),
668
    ogg_probe,
669
    ogg_read_header,
670
    ogg_read_packet,
671
    ogg_read_close,
672
    ogg_read_seek,
673
    ogg_read_timestamp,
674
    .extensions = "ogg",
675
    .flags = AVFMT_GENERIC_INDEX,
676
};