Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ d8b91fae

History | View | Annotate | Download (15.3 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

    
37
#define MAX_PAGE_SIZE 65307
38
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39

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

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

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

    
77
    ogg->state = ost;
78

    
79
    return 0;
80
}
81

    
82
static int
83
ogg_restore (AVFormatContext * s, int discard)
84
{
85
    struct ogg *ogg = s->priv_data;
86
    ByteIOContext *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
        url_fseek (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
112
ogg_reset (struct ogg * ogg)
113
{
114
    int i;
115

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

    
131
    ogg->curidx = -1;
132

    
133
    return 0;
134
}
135

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

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

    
146
    return NULL;
147
}
148

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

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

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

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

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

    
173
    return idx;
174
}
175

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

    
190
    return 0;
191
}
192

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

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

    
212
    do{
213
        int c;
214

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
296
    return 0;
297
}
298

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

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

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

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

    
320
        os = ogg->streams + idx;
321

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

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

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

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

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

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

    
364
    ogg->curidx = idx;
365
    os->incomplete = 0;
366

    
367
    if (!ogg->headers){
368
        int hdr = os->codec->header (s, idx);
369
        os->header = os->seq;
370
        if (!hdr){
371
            os->segp = segp;
372
            os->psize = psize;
373
            ogg->headers = 1;
374
            s->data_offset = os->sync_pos;
375
        }else{
376
            os->pstart += os->psize;
377
            os->psize = 0;
378
        }
379
    }
380

    
381
    if (os->header > -1 && os->seq > os->header){
382
        os->pflags = 0;
383
        os->pduration = 0;
384
        if (os->codec && os->codec->packet)
385
            os->codec->packet (s, idx);
386
        if (str)
387
            *str = idx;
388
        if (dstart)
389
            *dstart = os->pstart;
390
        if (dsize)
391
            *dsize = os->psize;
392
        if (fpos)
393
            *fpos = os->sync_pos;
394
        os->pstart += os->psize;
395
        os->psize = 0;
396
        os->sync_pos = os->page_pos;
397
    }
398

    
399
    // determine whether there are more complete packets in this page
400
    // if not, the page's granule will apply to this packet
401
    os->page_end = 1;
402
    for (i = os->segp; i < os->nsegs; i++)
403
        if (os->segments[i] < 255) {
404
            os->page_end = 0;
405
            break;
406
        }
407

    
408
    os->seq++;
409
    if (os->segp == os->nsegs)
410
        ogg->curidx = -1;
411

    
412
    return 0;
413
}
414

    
415
static int
416
ogg_get_headers (AVFormatContext * s)
417
{
418
    struct ogg *ogg = s->priv_data;
419

    
420
    do{
421
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
422
            return -1;
423
    }while (!ogg->headers);
424

    
425
#if 0
426
    av_log (s, AV_LOG_DEBUG, "found headers\n");
427
#endif
428

    
429
    return 0;
430
}
431

    
432
static int
433
ogg_get_length (AVFormatContext * s)
434
{
435
    struct ogg *ogg = s->priv_data;
436
    int idx = -1, i;
437
    int64_t size, end;
438

    
439
    if(url_is_streamed(s->pb))
440
        return 0;
441

    
442
// already set
443
    if (s->duration != AV_NOPTS_VALUE)
444
        return 0;
445

    
446
    size = url_fsize(s->pb);
447
    if(size < 0)
448
        return 0;
449
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
450

    
451
    ogg_save (s);
452
    url_fseek (s->pb, end, SEEK_SET);
453

    
454
    while (!ogg_read_page (s, &i)){
455
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
456
            ogg->streams[i].codec)
457
            idx = i;
458
    }
459

    
460
    if (idx != -1){
461
        s->streams[idx]->duration =
462
            ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
463
        if (s->streams[idx]->start_time != AV_NOPTS_VALUE)
464
            s->streams[idx]->duration -= s->streams[idx]->start_time;
465
    }
466

    
467
    ogg->size = size;
468
    ogg_restore (s, 0);
469

    
470
    return 0;
471
}
472

    
473

    
474
static int
475
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
476
{
477
    struct ogg *ogg = s->priv_data;
478
    int i;
479
    ogg->curidx = -1;
480
    //linear headers seek from start
481
    if (ogg_get_headers (s) < 0){
482
        return -1;
483
    }
484

    
485
    for (i = 0; i < ogg->nstreams; i++)
486
        if (ogg->streams[i].header < 0)
487
            ogg->streams[i].codec = NULL;
488

    
489
    //linear granulepos seek from end
490
    ogg_get_length (s);
491

    
492
    //fill the extradata in the per codec callbacks
493
    return 0;
494
}
495

    
496
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
497
{
498
    struct ogg *ogg = s->priv_data;
499
    struct ogg_stream *os = ogg->streams + idx;
500
    int64_t pts = AV_NOPTS_VALUE;
501

    
502
    if (dts)
503
        *dts = AV_NOPTS_VALUE;
504

    
505
    if (os->lastpts != AV_NOPTS_VALUE) {
506
        pts = os->lastpts;
507
        os->lastpts = AV_NOPTS_VALUE;
508
    }
509
    if (os->lastdts != AV_NOPTS_VALUE) {
510
        if (dts)
511
            *dts = os->lastdts;
512
        os->lastdts = AV_NOPTS_VALUE;
513
    }
514
    if (os->page_end) {
515
        if (os->granule != -1LL) {
516
            if (os->codec && os->codec->granule_is_start)
517
                pts = ogg_gptopts(s, idx, os->granule, dts);
518
            else
519
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
520
            os->granule = -1LL;
521
        } else
522
            av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
523
    }
524
    return pts;
525
}
526

    
527
static int
528
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
529
{
530
    struct ogg *ogg;
531
    struct ogg_stream *os;
532
    int idx = -1;
533
    int pstart, psize;
534
    int64_t fpos, pts, dts;
535

    
536
    //Get an ogg packet
537
retry:
538
    do{
539
        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
540
            return AVERROR(EIO);
541
    }while (idx < 0 || !s->streams[idx]);
542

    
543
    ogg = s->priv_data;
544
    os = ogg->streams + idx;
545

    
546
    // pflags might not be set until after this
547
    pts = ogg_calc_pts(s, idx, &dts);
548

    
549
    if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
550
        goto retry;
551
    os->keyframe_seek = 0;
552

    
553
    //Alloc a pkt
554
    if (av_new_packet (pkt, psize) < 0)
555
        return AVERROR(EIO);
556
    pkt->stream_index = idx;
557
    memcpy (pkt->data, os->buf + pstart, psize);
558

    
559
    pkt->pts = pts;
560
    pkt->dts = dts;
561
    pkt->flags = os->pflags;
562
    pkt->duration = os->pduration;
563
    pkt->pos = fpos;
564

    
565
    return psize;
566
}
567

    
568

    
569
static int
570
ogg_read_close (AVFormatContext * s)
571
{
572
    struct ogg *ogg = s->priv_data;
573
    int i;
574

    
575
    for (i = 0; i < ogg->nstreams; i++){
576
        av_free (ogg->streams[i].buf);
577
        av_free (ogg->streams[i].private);
578
    }
579
    av_free (ogg->streams);
580
    return 0;
581
}
582

    
583

    
584
static int64_t
585
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
586
                    int64_t pos_limit)
587
{
588
    struct ogg *ogg = s->priv_data;
589
    struct ogg_stream *os = ogg->streams + stream_index;
590
    ByteIOContext *bc = s->pb;
591
    int64_t pts = AV_NOPTS_VALUE;
592
    int i;
593
    url_fseek(bc, *pos_arg, SEEK_SET);
594
    ogg_reset(ogg);
595

    
596
    while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
597
        if (i == stream_index) {
598
            pts = ogg_calc_pts(s, i, NULL);
599
            if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
600
                pts = AV_NOPTS_VALUE;
601
        }
602
        if (pts != AV_NOPTS_VALUE)
603
            break;
604
    }
605
    ogg_reset(ogg);
606
    return pts;
607
}
608

    
609
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
610
{
611
    struct ogg *ogg = s->priv_data;
612
    struct ogg_stream *os = ogg->streams + stream_index;
613
    int ret;
614

    
615
    // Try seeking to a keyframe first. If this fails (very possible),
616
    // av_seek_frame will fall back to ignoring keyframes
617
    if (s->streams[stream_index]->codec->codec_type == CODEC_TYPE_VIDEO
618
        && !(flags & AVSEEK_FLAG_ANY))
619
        os->keyframe_seek = 1;
620

    
621
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
622
    if (ret < 0)
623
        os->keyframe_seek = 0;
624
    return ret;
625
}
626

    
627
static int ogg_probe(AVProbeData *p)
628
{
629
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
630
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
631
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
632
        return AVPROBE_SCORE_MAX;
633
    else
634
        return 0;
635
}
636

    
637
AVInputFormat ogg_demuxer = {
638
    "ogg",
639
    NULL_IF_CONFIG_SMALL("Ogg"),
640
    sizeof (struct ogg),
641
    ogg_probe,
642
    ogg_read_header,
643
    ogg_read_packet,
644
    ogg_read_close,
645
    ogg_read_seek,
646
    ogg_read_timestamp,
647
    .extensions = "ogg",
648
    .metadata_conv = ff_vorbiscomment_metadata_conv,
649
};