Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ bec994df

History | View | Annotate | Download (17.2 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_celt_codec,
49
    &ff_old_dirac_codec,
50
    &ff_old_flac_codec,
51
    &ff_ogm_video_codec,
52
    &ff_ogm_audio_codec,
53
    &ff_ogm_text_codec,
54
    &ff_ogm_old_codec,
55
    NULL
56
};
57

    
58
//FIXME We could avoid some structure duplication
59
static int 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 ogg_restore(AVFormatContext *s, int discard)
84
{
85
    struct ogg *ogg = s->priv_data;
86
    AVIOContext *bc = s->pb;
87
    struct ogg_state *ost = ogg->state;
88
    int i;
89

    
90
    if (!ost)
91
        return 0;
92

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

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

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

    
106
    av_free (ost);
107

    
108
    return 0;
109
}
110

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

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

    
130
    ogg->curidx = -1;
131

    
132
    return 0;
133
}
134

    
135
static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
136
{
137
    int i;
138

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

    
144
    return NULL;
145
}
146

    
147
static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
148
{
149

    
150
    struct ogg *ogg = s->priv_data;
151
    int idx = ogg->nstreams++;
152
    AVStream *st;
153
    struct ogg_stream *os;
154

    
155
    ogg->streams = av_realloc (ogg->streams,
156
                               ogg->nstreams * sizeof (*ogg->streams));
157
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
158
    os = ogg->streams + idx;
159
    os->serial = serial;
160
    os->bufsize = DECODER_BUFFER_SIZE;
161
    os->buf = av_malloc(os->bufsize);
162
    os->header = -1;
163

    
164
    if (new_avstream) {
165
        st = av_new_stream(s, idx);
166
        if (!st)
167
            return AVERROR(ENOMEM);
168

    
169
        av_set_pts_info(st, 64, 1, 1000000);
170
    }
171

    
172
    return idx;
173
}
174

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

    
188
    return 0;
189
}
190

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

    
206
    ret = avio_read (bc, sync, 4);
207
    if (ret < 4)
208
        return ret < 0 ? ret : AVERROR_EOF;
209

    
210
    do{
211
        int c;
212

    
213
        if (sync[sp & 3] == 'O' &&
214
            sync[(sp + 1) & 3] == 'g' &&
215
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
216
            break;
217

    
218
        c = avio_r8(bc);
219
        if (url_feof(bc))
220
            return AVERROR_EOF;
221
        sync[sp++ & 3] = c;
222
    }while (i++ < MAX_PAGE_SIZE);
223

    
224
    if (i >= MAX_PAGE_SIZE){
225
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
226
        return AVERROR_INVALIDDATA;
227
    }
228

    
229
    if (avio_r8(bc) != 0)      /* version */
230
        return AVERROR_INVALIDDATA;
231

    
232
    flags = avio_r8(bc);
233
    gp = avio_rl64 (bc);
234
    serial = avio_rl32 (bc);
235
    seq = avio_rl32 (bc);
236
    crc = avio_rl32 (bc);
237
    nsegs = avio_r8(bc);
238

    
239
    idx = ogg_find_stream (ogg, serial);
240
    if (idx < 0){
241
        if (ogg->headers) {
242
            int n;
243

    
244
            for (n = 0; n < ogg->nstreams; n++) {
245
                av_freep(&ogg->streams[n].buf);
246
                av_freep(&ogg->streams[n].private);
247
            }
248
            ogg->curidx   = -1;
249
            ogg->nstreams = 0;
250
            idx = ogg_new_stream(s, serial, 0);
251
        } else {
252
            idx = ogg_new_stream(s, serial, 1);
253
        }
254
        if (idx < 0)
255
            return idx;
256
    }
257

    
258
    os = ogg->streams + idx;
259
    os->page_pos = avio_tell(bc) - 27;
260

    
261
    if(os->psize > 0)
262
        ogg_new_buf(ogg, idx);
263

    
264
    ret = avio_read (bc, os->segments, nsegs);
265
    if (ret < nsegs)
266
        return ret < 0 ? ret : AVERROR_EOF;
267

    
268
    os->nsegs = nsegs;
269
    os->segp = 0;
270

    
271
    size = 0;
272
    for (i = 0; i < nsegs; i++)
273
        size += os->segments[i];
274

    
275
    if (flags & OGG_FLAG_CONT || os->incomplete){
276
        if (!os->psize){
277
            while (os->segp < os->nsegs){
278
                int seg = os->segments[os->segp++];
279
                os->pstart += seg;
280
                if (seg < 255)
281
                    break;
282
            }
283
            os->sync_pos = os->page_pos;
284
        }
285
    }else{
286
        os->psize = 0;
287
        os->sync_pos = os->page_pos;
288
    }
289

    
290
    if (os->bufsize - os->bufpos < size){
291
        uint8_t *nb = av_malloc (os->bufsize *= 2);
292
        memcpy (nb, os->buf, os->bufpos);
293
        av_free (os->buf);
294
        os->buf = nb;
295
    }
296

    
297
    ret = avio_read (bc, os->buf + os->bufpos, size);
298
    if (ret < size)
299
        return ret < 0 ? ret : AVERROR_EOF;
300

    
301
    os->bufpos += size;
302
    os->granule = gp;
303
    os->flags = flags;
304

    
305
    if (str)
306
        *str = idx;
307

    
308
    return 0;
309
}
310

    
311
static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
312
                      int64_t *fpos)
313
{
314
    struct ogg *ogg = s->priv_data;
315
    int idx, i, ret;
316
    struct ogg_stream *os;
317
    int complete = 0;
318
    int segp = 0, psize = 0;
319

    
320
#if 0
321
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
322
#endif
323

    
324
    do{
325
        idx = ogg->curidx;
326

    
327
        while (idx < 0){
328
            ret = ogg_read_page (s, &idx);
329
            if (ret < 0)
330
                return ret;
331
        }
332

    
333
        os = ogg->streams + idx;
334

    
335
#if 0
336
        av_log (s, AV_LOG_DEBUG,
337
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
338
                idx, os->pstart, os->psize, os->segp, os->nsegs);
339
#endif
340

    
341
        if (!os->codec){
342
            if (os->header < 0){
343
                os->codec = ogg_find_codec (os->buf, os->bufpos);
344
                if (!os->codec){
345
                    av_log(s, AV_LOG_WARNING, "Codec not found\n");
346
                    os->header = 0;
347
                    return 0;
348
                }
349
            }else{
350
                return 0;
351
            }
352
        }
353

    
354
        segp = os->segp;
355
        psize = os->psize;
356

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

    
366
        if (!complete && os->segp == os->nsegs){
367
            ogg->curidx = -1;
368
            os->incomplete = 1;
369
        }
370
    }while (!complete);
371

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

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

    
381
    ogg->curidx = idx;
382
    os->incomplete = 0;
383

    
384
    if (os->header) {
385
        os->header = os->codec->header (s, idx);
386
        if (!os->header){
387
            os->segp = segp;
388
            os->psize = psize;
389

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

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

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

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

    
438
    if (os->segp == os->nsegs)
439
        ogg->curidx = -1;
440

    
441
    return 0;
442
}
443

    
444
static int ogg_get_headers(AVFormatContext *s)
445
{
446
    struct ogg *ogg = s->priv_data;
447
    int ret;
448

    
449
    do{
450
        ret = ogg_packet (s, NULL, NULL, NULL, NULL);
451
        if (ret < 0)
452
            return ret;
453
    }while (!ogg->headers);
454

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

    
459
    return 0;
460
}
461

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

    
468
    if(!s->pb->seekable)
469
        return 0;
470

    
471
// already set
472
    if (s->duration != AV_NOPTS_VALUE)
473
        return 0;
474

    
475
    size = avio_size(s->pb);
476
    if(size < 0)
477
        return 0;
478
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
479

    
480
    ogg_save (s);
481
    avio_seek (s->pb, end, SEEK_SET);
482

    
483
    while (!ogg_read_page (s, &i)){
484
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
485
            ogg->streams[i].codec) {
486
            s->streams[i]->duration =
487
                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
488
            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
489
                s->streams[i]->duration -= s->streams[i]->start_time;
490
        }
491
    }
492

    
493
    ogg_restore (s, 0);
494

    
495
    ogg_save (s);
496
    avio_seek (s->pb, 0, SEEK_SET);
497
    while (!ogg_read_page (s, &i)){
498
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
499
            ogg->streams[i].codec) {
500
            s->streams[i]->duration -=
501
                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
502
            break;
503
        }
504
    }
505
    ogg_restore (s, 0);
506

    
507
    return 0;
508
}
509

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

    
521
    for (i = 0; i < ogg->nstreams; i++)
522
        if (ogg->streams[i].header < 0)
523
            ogg->streams[i].codec = NULL;
524

    
525
    //linear granulepos seek from end
526
    ogg_get_length (s);
527

    
528
    //fill the extradata in the per codec callbacks
529
    return 0;
530
}
531

    
532
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
533
{
534
    struct ogg *ogg = s->priv_data;
535
    struct ogg_stream *os = ogg->streams + idx;
536
    int64_t pts = AV_NOPTS_VALUE;
537

    
538
    if (dts)
539
        *dts = AV_NOPTS_VALUE;
540

    
541
    if (os->lastpts != AV_NOPTS_VALUE) {
542
        pts = os->lastpts;
543
        os->lastpts = AV_NOPTS_VALUE;
544
    }
545
    if (os->lastdts != AV_NOPTS_VALUE) {
546
        if (dts)
547
            *dts = os->lastdts;
548
        os->lastdts = AV_NOPTS_VALUE;
549
    }
550
    if (os->page_end) {
551
        if (os->granule != -1LL) {
552
            if (os->codec && os->codec->granule_is_start)
553
                pts = ogg_gptopts(s, idx, os->granule, dts);
554
            else
555
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
556
            os->granule = -1LL;
557
        }
558
    }
559
    return pts;
560
}
561

    
562
static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
563
{
564
    struct ogg *ogg;
565
    struct ogg_stream *os;
566
    int idx = -1;
567
    int pstart, psize;
568
    int64_t fpos, pts, dts;
569

    
570
    //Get an ogg packet
571
retry:
572
    do{
573
        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
574
            return AVERROR(EIO);
575
    }while (idx < 0 || !s->streams[idx]);
576

    
577
    ogg = s->priv_data;
578
    os = ogg->streams + idx;
579

    
580
    // pflags might not be set until after this
581
    pts = ogg_calc_pts(s, idx, &dts);
582

    
583
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
584
        goto retry;
585
    os->keyframe_seek = 0;
586

    
587
    //Alloc a pkt
588
    if (av_new_packet (pkt, psize) < 0)
589
        return AVERROR(EIO);
590
    pkt->stream_index = idx;
591
    memcpy (pkt->data, os->buf + pstart, psize);
592

    
593
    pkt->pts = pts;
594
    pkt->dts = dts;
595
    pkt->flags = os->pflags;
596
    pkt->duration = os->pduration;
597
    pkt->pos = fpos;
598

    
599
    return psize;
600
}
601

    
602
static int ogg_read_close(AVFormatContext *s)
603
{
604
    struct ogg *ogg = s->priv_data;
605
    int i;
606

    
607
    for (i = 0; i < ogg->nstreams; i++){
608
        av_free (ogg->streams[i].buf);
609
        av_free (ogg->streams[i].private);
610
    }
611
    av_free (ogg->streams);
612
    return 0;
613
}
614

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

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

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

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

    
652
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
653
    if (ret < 0)
654
        os->keyframe_seek = 0;
655
    return ret;
656
}
657

    
658
static int ogg_probe(AVProbeData *p)
659
{
660
    if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
661
        return AVPROBE_SCORE_MAX;
662
    return 0;
663
}
664

    
665
AVInputFormat ff_ogg_demuxer = {
666
    .name           = "ogg",
667
    .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
668
    .priv_data_size = sizeof(struct ogg),
669
    .read_probe     = ogg_probe,
670
    .read_header    = ogg_read_header,
671
    .read_packet    = ogg_read_packet,
672
    .read_close     = ogg_read_close,
673
    .read_seek      = ogg_read_seek,
674
    .read_timestamp = ogg_read_timestamp,
675
    .extensions     = "ogg",
676
    .flags          = AVFMT_GENERIC_INDEX,
677
};