Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 48b9b7ed

History | View | Annotate | Download (16.6 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
60
ogg_save (AVFormatContext * s)
61
{
62
    struct ogg *ogg = s->priv_data;
63
    struct ogg_state *ost =
64
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
65
    int i;
66
    ost->pos = avio_tell (s->pb);
67
    ost->curidx = ogg->curidx;
68
    ost->next = ogg->state;
69
    ost->nstreams = ogg->nstreams;
70
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
71

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

    
79
    ogg->state = ost;
80

    
81
    return 0;
82
}
83

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

    
92
    if (!ost)
93
        return 0;
94

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

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

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

    
108
    av_free (ost);
109

    
110
    return 0;
111
}
112

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

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

    
133
    ogg->curidx = -1;
134

    
135
    return 0;
136
}
137

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

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

    
148
    return NULL;
149
}
150

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

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

    
160
    ogg->streams = av_realloc (ogg->streams,
161
                               ogg->nstreams * sizeof (*ogg->streams));
162
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
163
    os = ogg->streams + idx;
164
    os->serial = serial;
165
    os->bufsize = DECODER_BUFFER_SIZE;
166
    os->buf = av_malloc(os->bufsize);
167
    os->header = -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
        if (ogg->headers) {
246
            int n;
247

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

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

    
263
    if(os->psize > 0)
264
        ogg_new_buf(ogg, idx);
265

    
266
    if (avio_read (bc, os->segments, nsegs) < nsegs)
267
        return -1;
268

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

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

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

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

    
298
    if (avio_read (bc, os->buf + os->bufpos, size) < size)
299
        return -1;
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
312
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
313
{
314
    struct ogg *ogg = s->priv_data;
315
    int idx, i;
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
            if (ogg_read_page (s, &idx) < 0)
329
                return -1;
330
        }
331

    
332
        os = ogg->streams + idx;
333

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

    
340
        if (!os->codec){
341
            if (os->header < 0){
342
                os->codec = ogg_find_codec (os->buf, os->bufpos);
343
                if (!os->codec){
344
                    os->header = 0;
345
                    return 0;
346
                }
347
            }else{
348
                return 0;
349
            }
350
        }
351

    
352
        segp = os->segp;
353
        psize = os->psize;
354

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

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

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

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

    
379
    ogg->curidx = idx;
380
    os->incomplete = 0;
381

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

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

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

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

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

    
436
    if (os->segp == os->nsegs)
437
        ogg->curidx = -1;
438

    
439
    return 0;
440
}
441

    
442
static int
443
ogg_get_headers (AVFormatContext * s)
444
{
445
    struct ogg *ogg = s->priv_data;
446

    
447
    do{
448
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
449
            return -1;
450
    }while (!ogg->headers);
451

    
452
#if 0
453
    av_log (s, AV_LOG_DEBUG, "found headers\n");
454
#endif
455

    
456
    return 0;
457
}
458

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

    
466
    if(!s->pb->seekable)
467
        return 0;
468

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

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

    
478
    ogg_save (s);
479
    avio_seek (s->pb, end, SEEK_SET);
480

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

    
491
    ogg_restore (s, 0);
492

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

    
505
    return 0;
506
}
507

    
508

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

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

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

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

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

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

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

    
561
static int
562
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

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

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

    
617

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

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

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

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

    
655
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
656
    if (ret < 0)
657
        os->keyframe_seek = 0;
658
    return ret;
659
}
660

    
661
static int ogg_probe(AVProbeData *p)
662
{
663
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
664
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
665
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
666
        return AVPROBE_SCORE_MAX;
667
    else
668
        return 0;
669
}
670

    
671
AVInputFormat ff_ogg_demuxer = {
672
    "ogg",
673
    NULL_IF_CONFIG_SMALL("Ogg"),
674
    sizeof (struct ogg),
675
    ogg_probe,
676
    ogg_read_header,
677
    ogg_read_packet,
678
    ogg_read_close,
679
    ogg_read_seek,
680
    ogg_read_timestamp,
681
    .extensions = "ogg",
682
    .flags = AVFMT_GENERIC_INDEX,
683
};