Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 94dfea71

History | View | Annotate | Download (16.1 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 = url_ftell (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
    ByteIOContext *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
        url_fseek (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

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

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

    
174
    return idx;
175
}
176

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

    
191
    return 0;
192
}
193

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

    
210
    if (get_buffer (bc, sync, 4) < 4)
211
        return -1;
212

    
213
    do{
214
        int c;
215

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

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

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

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

    
235
    flags = url_fgetc (bc);
236
    gp = get_le64 (bc);
237
    serial = get_le32 (bc);
238
    seq = get_le32 (bc);
239
    crc = get_le32 (bc);
240
    nsegs = url_fgetc (bc);
241

    
242
    idx = ogg_find_stream (ogg, serial);
243
    if (idx < 0){
244
        idx = ogg_new_stream (s, serial);
245
        if (idx < 0)
246
            return -1;
247
    }
248

    
249
    os = ogg->streams + idx;
250
    os->page_pos = url_ftell(bc) - 27;
251

    
252
    if(os->psize > 0)
253
        ogg_new_buf(ogg, idx);
254

    
255
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
256
        return -1;
257

    
258
    os->nsegs = nsegs;
259
    os->segp = 0;
260

    
261
    size = 0;
262
    for (i = 0; i < nsegs; i++)
263
        size += os->segments[i];
264

    
265
    if (flags & OGG_FLAG_CONT || os->incomplete){
266
        if (!os->psize){
267
            while (os->segp < os->nsegs){
268
                int seg = os->segments[os->segp++];
269
                os->pstart += seg;
270
                if (seg < 255)
271
                    break;
272
            }
273
            os->sync_pos = os->page_pos;
274
        }
275
    }else{
276
        os->psize = 0;
277
        os->sync_pos = os->page_pos;
278
    }
279

    
280
    if (os->bufsize - os->bufpos < size){
281
        uint8_t *nb = av_malloc (os->bufsize *= 2);
282
        memcpy (nb, os->buf, os->bufpos);
283
        av_free (os->buf);
284
        os->buf = nb;
285
    }
286

    
287
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
288
        return -1;
289

    
290
    os->bufpos += size;
291
    os->granule = gp;
292
    os->flags = flags;
293

    
294
    if (str)
295
        *str = idx;
296

    
297
    return 0;
298
}
299

    
300
static int
301
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
302
{
303
    struct ogg *ogg = s->priv_data;
304
    int idx, i;
305
    struct ogg_stream *os;
306
    int complete = 0;
307
    int segp = 0, psize = 0;
308

    
309
#if 0
310
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
311
#endif
312

    
313
    do{
314
        idx = ogg->curidx;
315

    
316
        while (idx < 0){
317
            if (ogg_read_page (s, &idx) < 0)
318
                return -1;
319
        }
320

    
321
        os = ogg->streams + idx;
322

    
323
#if 0
324
        av_log (s, AV_LOG_DEBUG,
325
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
326
                idx, os->pstart, os->psize, os->segp, os->nsegs);
327
#endif
328

    
329
        if (!os->codec){
330
            if (os->header < 0){
331
                os->codec = ogg_find_codec (os->buf, os->bufpos);
332
                if (!os->codec){
333
                    os->header = 0;
334
                    return 0;
335
                }
336
            }else{
337
                return 0;
338
            }
339
        }
340

    
341
        segp = os->segp;
342
        psize = os->psize;
343

    
344
        while (os->segp < os->nsegs){
345
            int ss = os->segments[os->segp++];
346
            os->psize += ss;
347
            if (ss < 255){
348
                complete = 1;
349
                break;
350
            }
351
        }
352

    
353
        if (!complete && os->segp == os->nsegs){
354
            ogg->curidx = -1;
355
            os->incomplete = 1;
356
        }
357
    }while (!complete);
358

    
359
#if 0
360
    av_log (s, AV_LOG_DEBUG,
361
            "ogg_packet: idx %i, frame size %i, start %i\n",
362
            idx, os->psize, os->pstart);
363
#endif
364

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

    
368
    ogg->curidx = idx;
369
    os->incomplete = 0;
370

    
371
    if (os->header) {
372
        os->header = os->codec->header (s, idx);
373
        if (!os->header){
374
            os->segp = segp;
375
            os->psize = psize;
376

    
377
            // We have reached the first non-header packet in this stream.
378
            // Unfortunately more header packets may still follow for others,
379
            // so we reset this later unless we are done with the headers
380
            // for all streams.
381
            ogg->headers = 1;
382

    
383
            // Update the header state for all streams and
384
            // compute the data_offset.
385
            if (!s->data_offset)
386
                s->data_offset = os->sync_pos;
387
            for (i = 0; i < ogg->nstreams; i++) {
388
                struct ogg_stream *cur_os = ogg->streams + i;
389
                if (cur_os->header > 0)
390
                    ogg->headers = 0;
391

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

    
419
    // determine whether there are more complete packets in this page
420
    // if not, the page's granule will apply to this packet
421
    os->page_end = 1;
422
    for (i = os->segp; i < os->nsegs; i++)
423
        if (os->segments[i] < 255) {
424
            os->page_end = 0;
425
            break;
426
        }
427

    
428
    if (os->segp == os->nsegs)
429
        ogg->curidx = -1;
430

    
431
    return 0;
432
}
433

    
434
static int
435
ogg_get_headers (AVFormatContext * s)
436
{
437
    struct ogg *ogg = s->priv_data;
438

    
439
    do{
440
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
441
            return -1;
442
    }while (!ogg->headers);
443

    
444
#if 0
445
    av_log (s, AV_LOG_DEBUG, "found headers\n");
446
#endif
447

    
448
    return 0;
449
}
450

    
451
static int
452
ogg_get_length (AVFormatContext * s)
453
{
454
    struct ogg *ogg = s->priv_data;
455
    int i;
456
    int64_t size, end;
457

    
458
    if(url_is_streamed(s->pb))
459
        return 0;
460

    
461
// already set
462
    if (s->duration != AV_NOPTS_VALUE)
463
        return 0;
464

    
465
    size = url_fsize(s->pb);
466
    if(size < 0)
467
        return 0;
468
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
469

    
470
    ogg_save (s);
471
    url_fseek (s->pb, end, SEEK_SET);
472

    
473
    while (!ogg_read_page (s, &i)){
474
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
475
            ogg->streams[i].codec) {
476
            s->streams[i]->duration =
477
                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
478
            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
479
                s->streams[i]->duration -= s->streams[i]->start_time;
480
        }
481
    }
482

    
483
    ogg_restore (s, 0);
484

    
485
    return 0;
486
}
487

    
488

    
489
static int
490
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
491
{
492
    struct ogg *ogg = s->priv_data;
493
    int i;
494
    ogg->curidx = -1;
495
    //linear headers seek from start
496
    if (ogg_get_headers (s) < 0){
497
        return -1;
498
    }
499

    
500
    for (i = 0; i < ogg->nstreams; i++)
501
        if (ogg->streams[i].header < 0)
502
            ogg->streams[i].codec = NULL;
503

    
504
    //linear granulepos seek from end
505
    ogg_get_length (s);
506

    
507
    //fill the extradata in the per codec callbacks
508
    return 0;
509
}
510

    
511
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
512
{
513
    struct ogg *ogg = s->priv_data;
514
    struct ogg_stream *os = ogg->streams + idx;
515
    int64_t pts = AV_NOPTS_VALUE;
516

    
517
    if (dts)
518
        *dts = AV_NOPTS_VALUE;
519

    
520
    if (os->lastpts != AV_NOPTS_VALUE) {
521
        pts = os->lastpts;
522
        os->lastpts = AV_NOPTS_VALUE;
523
    }
524
    if (os->lastdts != AV_NOPTS_VALUE) {
525
        if (dts)
526
            *dts = os->lastdts;
527
        os->lastdts = AV_NOPTS_VALUE;
528
    }
529
    if (os->page_end) {
530
        if (os->granule != -1LL) {
531
            if (os->codec && os->codec->granule_is_start)
532
                pts = ogg_gptopts(s, idx, os->granule, dts);
533
            else
534
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
535
            os->granule = -1LL;
536
        }
537
    }
538
    return pts;
539
}
540

    
541
static int
542
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
543
{
544
    struct ogg *ogg;
545
    struct ogg_stream *os;
546
    int idx = -1;
547
    int pstart, psize;
548
    int64_t fpos, pts, dts;
549

    
550
    //Get an ogg packet
551
retry:
552
    do{
553
        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
554
            return AVERROR(EIO);
555
    }while (idx < 0 || !s->streams[idx]);
556

    
557
    ogg = s->priv_data;
558
    os = ogg->streams + idx;
559

    
560
    // pflags might not be set until after this
561
    pts = ogg_calc_pts(s, idx, &dts);
562

    
563
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
564
        goto retry;
565
    os->keyframe_seek = 0;
566

    
567
    //Alloc a pkt
568
    if (av_new_packet (pkt, psize) < 0)
569
        return AVERROR(EIO);
570
    pkt->stream_index = idx;
571
    memcpy (pkt->data, os->buf + pstart, psize);
572

    
573
    pkt->pts = pts;
574
    pkt->dts = dts;
575
    pkt->flags = os->pflags;
576
    pkt->duration = os->pduration;
577
    pkt->pos = fpos;
578

    
579
    return psize;
580
}
581

    
582

    
583
static int
584
ogg_read_close (AVFormatContext * s)
585
{
586
    struct ogg *ogg = s->priv_data;
587
    int i;
588

    
589
    for (i = 0; i < ogg->nstreams; i++){
590
        av_free (ogg->streams[i].buf);
591
        av_free (ogg->streams[i].private);
592
    }
593
    av_free (ogg->streams);
594
    return 0;
595
}
596

    
597

    
598
static int64_t
599
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
600
                    int64_t pos_limit)
601
{
602
    struct ogg *ogg = s->priv_data;
603
    struct ogg_stream *os = ogg->streams + stream_index;
604
    ByteIOContext *bc = s->pb;
605
    int64_t pts = AV_NOPTS_VALUE;
606
    int i;
607
    url_fseek(bc, *pos_arg, SEEK_SET);
608
    ogg_reset(ogg);
609

    
610
    while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
611
        if (i == stream_index) {
612
            pts = ogg_calc_pts(s, i, NULL);
613
            if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
614
                pts = AV_NOPTS_VALUE;
615
        }
616
        if (pts != AV_NOPTS_VALUE)
617
            break;
618
    }
619
    ogg_reset(ogg);
620
    return pts;
621
}
622

    
623
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
624
{
625
    struct ogg *ogg = s->priv_data;
626
    struct ogg_stream *os = ogg->streams + stream_index;
627
    int ret;
628

    
629
    // Try seeking to a keyframe first. If this fails (very possible),
630
    // av_seek_frame will fall back to ignoring keyframes
631
    if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
632
        && !(flags & AVSEEK_FLAG_ANY))
633
        os->keyframe_seek = 1;
634

    
635
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
636
    if (ret < 0)
637
        os->keyframe_seek = 0;
638
    return ret;
639
}
640

    
641
static int ogg_probe(AVProbeData *p)
642
{
643
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
644
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
645
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
646
        return AVPROBE_SCORE_MAX;
647
    else
648
        return 0;
649
}
650

    
651
AVInputFormat ff_ogg_demuxer = {
652
    "ogg",
653
    NULL_IF_CONFIG_SMALL("Ogg"),
654
    sizeof (struct ogg),
655
    ogg_probe,
656
    ogg_read_header,
657
    ogg_read_packet,
658
    ogg_read_close,
659
    ogg_read_seek,
660
    ogg_read_timestamp,
661
    .extensions = "ogg",
662
    .flags = AVFMT_GENERIC_INDEX,
663
};