Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 81b743eb

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 (os->header) {
368
        os->header = os->codec->header (s, idx);
369
        if (!os->header){
370
            os->segp = segp;
371
            os->psize = psize;
372
            if (!ogg->headers)
373
                s->data_offset = os->sync_pos;
374
            ogg->headers = 1;
375
        }else{
376
            os->pstart += os->psize;
377
            os->psize = 0;
378
        }
379
    } else {
380
        os->pflags = 0;
381
        os->pduration = 0;
382
        if (os->codec && os->codec->packet)
383
            os->codec->packet (s, idx);
384
        if (str)
385
            *str = idx;
386
        if (dstart)
387
            *dstart = os->pstart;
388
        if (dsize)
389
            *dsize = os->psize;
390
        if (fpos)
391
            *fpos = os->sync_pos;
392
        os->pstart += os->psize;
393
        os->psize = 0;
394
        os->sync_pos = os->page_pos;
395
    }
396

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

    
406
    if (os->segp == os->nsegs)
407
        ogg->curidx = -1;
408

    
409
    return 0;
410
}
411

    
412
static int
413
ogg_get_headers (AVFormatContext * s)
414
{
415
    struct ogg *ogg = s->priv_data;
416

    
417
    do{
418
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
419
            return -1;
420
    }while (!ogg->headers);
421

    
422
#if 0
423
    av_log (s, AV_LOG_DEBUG, "found headers\n");
424
#endif
425

    
426
    return 0;
427
}
428

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

    
436
    if(url_is_streamed(s->pb))
437
        return 0;
438

    
439
// already set
440
    if (s->duration != AV_NOPTS_VALUE)
441
        return 0;
442

    
443
    size = url_fsize(s->pb);
444
    if(size < 0)
445
        return 0;
446
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
447

    
448
    ogg_save (s);
449
    url_fseek (s->pb, end, SEEK_SET);
450

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

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

    
464
    ogg->size = size;
465
    ogg_restore (s, 0);
466

    
467
    return 0;
468
}
469

    
470

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

    
482
    for (i = 0; i < ogg->nstreams; i++)
483
        if (ogg->streams[i].header < 0)
484
            ogg->streams[i].codec = NULL;
485

    
486
    //linear granulepos seek from end
487
    ogg_get_length (s);
488

    
489
    //fill the extradata in the per codec callbacks
490
    return 0;
491
}
492

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

    
499
    if (dts)
500
        *dts = AV_NOPTS_VALUE;
501

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

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

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

    
540
    ogg = s->priv_data;
541
    os = ogg->streams + idx;
542

    
543
    // pflags might not be set until after this
544
    pts = ogg_calc_pts(s, idx, &dts);
545

    
546
    if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
547
        goto retry;
548
    os->keyframe_seek = 0;
549

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

    
556
    pkt->pts = pts;
557
    pkt->dts = dts;
558
    pkt->flags = os->pflags;
559
    pkt->duration = os->pduration;
560
    pkt->pos = fpos;
561

    
562
    return psize;
563
}
564

    
565

    
566
static int
567
ogg_read_close (AVFormatContext * s)
568
{
569
    struct ogg *ogg = s->priv_data;
570
    int i;
571

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

    
580

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

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

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

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

    
618
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
619
    if (ret < 0)
620
        os->keyframe_seek = 0;
621
    return ret;
622
}
623

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

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