Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 73823cb9

History | View | Annotate | Download (14.7 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_dirac_codec,
42
    &ff_speex_codec,
43
    &ff_vorbis_codec,
44
    &ff_theora_codec,
45
    &ff_flac_codec,
46
    &ff_old_dirac_codec,
47
    &ff_old_flac_codec,
48
    &ff_ogm_video_codec,
49
    &ff_ogm_audio_codec,
50
    &ff_ogm_text_codec,
51
    &ff_ogm_old_codec,
52
    NULL
53
};
54

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

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

    
76
    ogg->state = ost;
77

    
78
    return 0;
79
}
80

    
81
static int
82
ogg_restore (AVFormatContext * s, int discard)
83
{
84
    struct ogg *ogg = s->priv_data;
85
    ByteIOContext *bc = s->pb;
86
    struct ogg_state *ost = ogg->state;
87
    int i;
88

    
89
    if (!ost)
90
        return 0;
91

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

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

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

    
105
    av_free (ost);
106

    
107
    return 0;
108
}
109

    
110
static int
111
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 *
136
ogg_find_codec (uint8_t * buf, int size)
137
{
138
    int i;
139

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

    
145
    return NULL;
146
}
147

    
148
static int
149
ogg_find_stream (struct ogg * ogg, int serial)
150
{
151
    int i;
152

    
153
    for (i = 0; i < ogg->nstreams; i++)
154
        if (ogg->streams[i].serial == serial)
155
            return i;
156

    
157
    return -1;
158
}
159

    
160
static int
161
ogg_new_stream (AVFormatContext * s, uint32_t serial)
162
{
163

    
164
    struct ogg *ogg = s->priv_data;
165
    int idx = ogg->nstreams++;
166
    AVStream *st;
167
    struct ogg_stream *os;
168

    
169
    ogg->streams = av_realloc (ogg->streams,
170
                               ogg->nstreams * sizeof (*ogg->streams));
171
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
172
    os = ogg->streams + idx;
173
    os->serial = serial;
174
    os->bufsize = DECODER_BUFFER_SIZE;
175
    os->buf = av_malloc(os->bufsize);
176
    os->header = -1;
177

    
178
    st = av_new_stream (s, idx);
179
    if (!st)
180
        return AVERROR(ENOMEM);
181

    
182
    av_set_pts_info(st, 64, 1, 1000000);
183

    
184
    return idx;
185
}
186

    
187
static int
188
ogg_new_buf(struct ogg *ogg, int idx)
189
{
190
    struct ogg_stream *os = ogg->streams + idx;
191
    uint8_t *nb = av_malloc(os->bufsize);
192
    int size = os->bufpos - os->pstart;
193
    if(os->buf){
194
        memcpy(nb, os->buf + os->pstart, size);
195
        av_free(os->buf);
196
    }
197
    os->buf = nb;
198
    os->bufpos = size;
199
    os->pstart = 0;
200

    
201
    return 0;
202
}
203

    
204
static int
205
ogg_read_page (AVFormatContext * s, int *str)
206
{
207
    ByteIOContext *bc = s->pb;
208
    struct ogg *ogg = s->priv_data;
209
    struct ogg_stream *os;
210
    int i = 0;
211
    int flags, nsegs;
212
    uint64_t gp;
213
    uint32_t serial;
214
    uint32_t seq;
215
    uint32_t crc;
216
    int size, idx;
217
    uint8_t sync[4];
218
    int sp = 0;
219

    
220
    if (get_buffer (bc, sync, 4) < 4)
221
        return -1;
222

    
223
    do{
224
        int c;
225

    
226
        if (sync[sp & 3] == 'O' &&
227
            sync[(sp + 1) & 3] == 'g' &&
228
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
229
            break;
230

    
231
        c = url_fgetc (bc);
232
        if (c < 0)
233
            return -1;
234
        sync[sp++ & 3] = c;
235
    }while (i++ < MAX_PAGE_SIZE);
236

    
237
    if (i >= MAX_PAGE_SIZE){
238
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
239
        return -1;
240
    }
241

    
242
    if (url_fgetc (bc) != 0)      /* version */
243
        return -1;
244

    
245
    flags = url_fgetc (bc);
246
    gp = get_le64 (bc);
247
    serial = get_le32 (bc);
248
    seq = get_le32 (bc);
249
    crc = get_le32 (bc);
250
    nsegs = url_fgetc (bc);
251

    
252
    idx = ogg_find_stream (ogg, serial);
253
    if (idx < 0){
254
        idx = ogg_new_stream (s, serial);
255
        if (idx < 0)
256
            return -1;
257
    }
258

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

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

    
265
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
266
        return -1;
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
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
298
        return -1;
299

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

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

    
307
    return 0;
308
}
309

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

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

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

    
326
        while (idx < 0){
327
            if (ogg_read_page (s, &idx) < 0)
328
                return -1;
329
        }
330

    
331
        os = ogg->streams + idx;
332

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

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

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

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

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

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

    
375
    ogg->curidx = idx;
376
    os->incomplete = 0;
377

    
378
    if (!ogg->headers){
379
        int hdr = os->codec->header (s, idx);
380
        os->header = os->seq;
381
        if (!hdr){
382
            os->segp = segp;
383
            os->psize = psize;
384
            ogg->headers = 1;
385
        }else{
386
            os->pstart += os->psize;
387
            os->psize = 0;
388
        }
389
    }
390

    
391
    if (os->header > -1 && os->seq > os->header){
392
        os->pflags = 0;
393
        os->pduration = 0;
394
        if (os->codec && os->codec->packet)
395
            os->codec->packet (s, idx);
396
        if (str)
397
            *str = idx;
398
        if (dstart)
399
            *dstart = os->pstart;
400
        if (dsize)
401
            *dsize = os->psize;
402
        if (fpos)
403
            *fpos = os->sync_pos;
404
        os->pstart += os->psize;
405
        os->psize = 0;
406
        os->sync_pos = os->page_pos;
407
    }
408

    
409
    // determine whether there are more complete packets in this page
410
    // if not, the page's granule will apply to this packet
411
    os->page_end = 1;
412
    for (i = os->segp; i < os->nsegs; i++)
413
        if (os->segments[i] < 255) {
414
            os->page_end = 0;
415
            break;
416
        }
417

    
418
    os->seq++;
419
    if (os->segp == os->nsegs)
420
        ogg->curidx = -1;
421

    
422
    return 0;
423
}
424

    
425
static int
426
ogg_get_headers (AVFormatContext * s)
427
{
428
    struct ogg *ogg = s->priv_data;
429

    
430
    do{
431
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
432
            return -1;
433
    }while (!ogg->headers);
434

    
435
#if 0
436
    av_log (s, AV_LOG_DEBUG, "found headers\n");
437
#endif
438

    
439
    return 0;
440
}
441

    
442
static uint64_t
443
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp, int64_t *dts)
444
{
445
    struct ogg *ogg = s->priv_data;
446
    struct ogg_stream *os = ogg->streams + i;
447
    uint64_t pts = AV_NOPTS_VALUE;
448

    
449
    if(os->codec->gptopts){
450
        pts = os->codec->gptopts(s, i, gp, dts);
451
    } else {
452
        pts = gp;
453
        if (dts)
454
            *dts = pts;
455
    }
456

    
457
    return pts;
458
}
459

    
460

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

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

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

    
475
    size = url_fsize(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
    url_fseek (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
            idx = i;
487
    }
488

    
489
    if (idx != -1){
490
        s->streams[idx]->duration =
491
            ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
492
    }
493

    
494
    ogg->size = size;
495
    ogg_restore (s, 0);
496

    
497
    return 0;
498
}
499

    
500

    
501
static int
502
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
503
{
504
    struct ogg *ogg = s->priv_data;
505
    int i;
506
    ogg->curidx = -1;
507
    //linear headers seek from start
508
    if (ogg_get_headers (s) < 0){
509
        return -1;
510
    }
511

    
512
    for (i = 0; i < ogg->nstreams; i++)
513
        if (ogg->streams[i].header < 0)
514
            ogg->streams[i].codec = NULL;
515

    
516
    //linear granulepos seek from end
517
    ogg_get_length (s);
518

    
519
    //fill the extradata in the per codec callbacks
520
    return 0;
521
}
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;
532

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

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

    
542
    //Alloc a pkt
543
    if (av_new_packet (pkt, psize) < 0)
544
        return AVERROR(EIO);
545
    pkt->stream_index = idx;
546
    memcpy (pkt->data, os->buf + pstart, psize);
547

    
548
    if (os->lastpts != AV_NOPTS_VALUE) {
549
        pkt->pts = os->lastpts;
550
        os->lastpts = AV_NOPTS_VALUE;
551
    }
552
    if (os->lastdts != AV_NOPTS_VALUE) {
553
        pkt->dts = os->lastdts;
554
        os->lastdts = AV_NOPTS_VALUE;
555
    }
556
    if (os->page_end) {
557
        if (os->granule != -1LL) {
558
            if (os->codec && os->codec->granule_is_start)
559
                pkt->pts    = ogg_gptopts(s, idx, os->granule, &pkt->dts);
560
            else
561
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
562
            os->granule = -1LL;
563
        } else
564
            av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
565
    }
566

    
567
    pkt->flags = os->pflags;
568
    pkt->duration = os->pduration;
569
    pkt->pos = fpos;
570

    
571
    return psize;
572
}
573

    
574

    
575
static int
576
ogg_read_close (AVFormatContext * s)
577
{
578
    struct ogg *ogg = s->priv_data;
579
    int i;
580

    
581
    for (i = 0; i < ogg->nstreams; i++){
582
        av_free (ogg->streams[i].buf);
583
        av_free (ogg->streams[i].private);
584
    }
585
    av_free (ogg->streams);
586
    return 0;
587
}
588

    
589

    
590
static int64_t
591
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
592
                    int64_t pos_limit)
593
{
594
    struct ogg *ogg = s->priv_data;
595
    ByteIOContext *bc = s->pb;
596
    int64_t pts = AV_NOPTS_VALUE;
597
    int i;
598
    url_fseek(bc, *pos_arg, SEEK_SET);
599
    while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
600
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
601
            ogg->streams[i].codec && i == stream_index) {
602
            pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
603
            // FIXME: this is the position of the packet after the one with above
604
            // pts.
605
            *pos_arg = url_ftell(bc);
606
            break;
607
        }
608
    }
609
    ogg_reset(ogg);
610
    return pts;
611
}
612

    
613
static int ogg_probe(AVProbeData *p)
614
{
615
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
616
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
617
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
618
        return AVPROBE_SCORE_MAX;
619
    else
620
        return 0;
621
}
622

    
623
AVInputFormat ogg_demuxer = {
624
    "ogg",
625
    NULL_IF_CONFIG_SMALL("Ogg"),
626
    sizeof (struct ogg),
627
    ogg_probe,
628
    ogg_read_header,
629
    ogg_read_packet,
630
    ogg_read_close,
631
    NULL,
632
    ogg_read_timestamp,
633
    .extensions = "ogg",
634
    .metadata_conv = ff_vorbiscomment_metadata_conv,
635
};