Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 5f8e0227

History | View | Annotate | Download (12.9 KB)

1 9146ca37 Måns Rullgård
/*
2
 * Ogg bitstream support
3
 * Luca Barbato <lu_zero@gentoo.org>
4
 * Based on tcvp implementation
5 115329f1 Diego Biurrun
 *
6 9146ca37 Måns Rullgård
 */
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 a0ddef24 Diego Biurrun
#include "oggdec.h"
35 9146ca37 Måns Rullgård
#include "avformat.h"
36
37
#define MAX_PAGE_SIZE 65307
38
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40
static ogg_codec_t *ogg_codecs[] = {
41 cb4ddf77 Reimar Döffinger
    &speex_codec,
42 9146ca37 Måns Rullgård
    &vorbis_codec,
43 1ed923ea Måns Rullgård
    &theora_codec,
44 bcfc40ae Måns Rullgård
    &flac_codec,
45 880e3ef4 Michael Niedermayer
    &old_flac_codec,
46 e1203ac0 Måns Rullgård
    &ogm_video_codec,
47
    &ogm_audio_codec,
48 2331e31c Reimar Döffinger
    &ogm_text_codec,
49 e1203ac0 Måns Rullgård
    &ogm_old_codec,
50 9146ca37 Måns Rullgård
    NULL
51
};
52
53
//FIXME We could avoid some structure duplication
54
static int
55
ogg_save (AVFormatContext * s)
56
{
57
    ogg_t *ogg = s->priv_data;
58
    ogg_state_t *ost =
59 ad3aa874 Måns Rullgård
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
60 9146ca37 Måns Rullgård
    int i;
61 899681cd Björn Axelsson
    ost->pos = url_ftell (s->pb);
62 9146ca37 Måns Rullgård
    ost->curidx = ogg->curidx;
63
    ost->next = ogg->state;
64 20be72c8 Måns Rullgård
    ost->nstreams = ogg->nstreams;
65 9146ca37 Måns Rullgård
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
66
67
    for (i = 0; i < ogg->nstreams; i++){
68
        ogg_stream_t *os = ogg->streams + i;
69
        os->buf = av_malloc (os->bufsize);
70
        memset (os->buf, 0, os->bufsize);
71
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
72
    }
73
74
    ogg->state = ost;
75
76
    return 0;
77
}
78
79
static int
80
ogg_restore (AVFormatContext * s, int discard)
81
{
82
    ogg_t *ogg = s->priv_data;
83 899681cd Björn Axelsson
    ByteIOContext *bc = s->pb;
84 9146ca37 Måns Rullgård
    ogg_state_t *ost = ogg->state;
85
    int i;
86
87
    if (!ost)
88
        return 0;
89
90
    ogg->state = ost->next;
91
92
    if (!discard){
93
        for (i = 0; i < ogg->nstreams; i++)
94
            av_free (ogg->streams[i].buf);
95
96
        url_fseek (bc, ost->pos, SEEK_SET);
97
        ogg->curidx = ost->curidx;
98 20be72c8 Måns Rullgård
        ogg->nstreams = ost->nstreams;
99
        memcpy(ogg->streams, ost->streams,
100
               ost->nstreams * sizeof(*ogg->streams));
101 9146ca37 Måns Rullgård
    }
102
103
    av_free (ost);
104
105
    return 0;
106
}
107
108
static int
109
ogg_reset (ogg_t * ogg)
110
{
111
    int i;
112
113
    for (i = 0; i < ogg->nstreams; i++){
114
        ogg_stream_t *os = ogg->streams + i;
115
        os->bufpos = 0;
116
        os->pstart = 0;
117
        os->psize = 0;
118
        os->granule = -1;
119
        os->lastgp = -1;
120
        os->nsegs = 0;
121
        os->segp = 0;
122
    }
123
124
    ogg->curidx = -1;
125
126
    return 0;
127
}
128
129
static ogg_codec_t *
130 2d2f443d Måns Rullgård
ogg_find_codec (uint8_t * buf, int size)
131 9146ca37 Måns Rullgård
{
132
    int i;
133
134
    for (i = 0; ogg_codecs[i]; i++)
135
        if (size >= ogg_codecs[i]->magicsize &&
136
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
137
            return ogg_codecs[i];
138
139
    return NULL;
140
}
141
142
static int
143
ogg_find_stream (ogg_t * ogg, int serial)
144
{
145
    int i;
146
147
    for (i = 0; i < ogg->nstreams; i++)
148
        if (ogg->streams[i].serial == serial)
149
            return i;
150
151
    return -1;
152
}
153
154
static int
155
ogg_new_stream (AVFormatContext * s, uint32_t serial)
156
{
157
158
    ogg_t *ogg = s->priv_data;
159
    int idx = ogg->nstreams++;
160
    AVStream *st;
161
    ogg_stream_t *os;
162
163
    ogg->streams = av_realloc (ogg->streams,
164
                               ogg->nstreams * sizeof (*ogg->streams));
165
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
166
    os = ogg->streams + idx;
167
    os->serial = serial;
168
    os->bufsize = DECODER_BUFFER_SIZE;
169 40c5e1fa Måns Rullgård
    os->buf = av_malloc(os->bufsize);
170 9146ca37 Måns Rullgård
    os->header = -1;
171
172
    st = av_new_stream (s, idx);
173
    if (!st)
174 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
175 9146ca37 Måns Rullgård
176
    av_set_pts_info(st, 64, 1, 1000000);
177
178
    return idx;
179
}
180
181
static int
182 12a195e3 Måns Rullgård
ogg_new_buf(ogg_t *ogg, int idx)
183
{
184
    ogg_stream_t *os = ogg->streams + idx;
185 ea02862a Måns Rullgård
    uint8_t *nb = av_malloc(os->bufsize);
186 12a195e3 Måns Rullgård
    int size = os->bufpos - os->pstart;
187
    if(os->buf){
188
        memcpy(nb, os->buf + os->pstart, size);
189
        av_free(os->buf);
190
    }
191
    os->buf = nb;
192
    os->bufpos = size;
193
    os->pstart = 0;
194
195
    return 0;
196
}
197
198
static int
199 9146ca37 Måns Rullgård
ogg_read_page (AVFormatContext * s, int *str)
200
{
201 899681cd Björn Axelsson
    ByteIOContext *bc = s->pb;
202 9146ca37 Måns Rullgård
    ogg_t *ogg = s->priv_data;
203
    ogg_stream_t *os;
204
    int i = 0;
205
    int flags, nsegs;
206
    uint64_t gp;
207
    uint32_t serial;
208
    uint32_t seq;
209
    uint32_t crc;
210
    int size, idx;
211 191e8ca7 Måns Rullgård
    uint8_t sync[4];
212 9146ca37 Måns Rullgård
    int sp = 0;
213
214
    if (get_buffer (bc, sync, 4) < 4)
215
        return -1;
216
217
    do{
218
        int c;
219
220
        if (sync[sp & 3] == 'O' &&
221
            sync[(sp + 1) & 3] == 'g' &&
222
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
223
            break;
224
225
        c = url_fgetc (bc);
226
        if (c < 0)
227
            return -1;
228
        sync[sp++ & 3] = c;
229
    }while (i++ < MAX_PAGE_SIZE);
230
231
    if (i >= MAX_PAGE_SIZE){
232
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
233
        return -1;
234
    }
235
236
    if (url_fgetc (bc) != 0)      /* version */
237
        return -1;
238
239
    flags = url_fgetc (bc);
240
    gp = get_le64 (bc);
241
    serial = get_le32 (bc);
242
    seq = get_le32 (bc);
243
    crc = get_le32 (bc);
244
    nsegs = url_fgetc (bc);
245
246
    idx = ogg_find_stream (ogg, serial);
247
    if (idx < 0){
248
        idx = ogg_new_stream (s, serial);
249
        if (idx < 0)
250
            return -1;
251
    }
252
253
    os = ogg->streams + idx;
254
255 40c5e1fa Måns Rullgård
    if(os->psize > 0)
256 12a195e3 Måns Rullgård
        ogg_new_buf(ogg, idx);
257
258 9146ca37 Måns Rullgård
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
259
        return -1;
260
261
    os->nsegs = nsegs;
262
    os->segp = 0;
263
264
    size = 0;
265
    for (i = 0; i < nsegs; i++)
266
        size += os->segments[i];
267
268
    if (flags & OGG_FLAG_CONT){
269
        if (!os->psize){
270
            while (os->segp < os->nsegs){
271
                int seg = os->segments[os->segp++];
272
                os->pstart += seg;
273
                if (seg < 255)
274
                  break;
275
            }
276
        }
277
    }else{
278
      os->psize = 0;
279
    }
280
281
    if (os->bufsize - os->bufpos < size){
282 2d2f443d Måns Rullgård
        uint8_t *nb = av_malloc (os->bufsize *= 2);
283 9146ca37 Måns Rullgård
        memcpy (nb, os->buf, os->bufpos);
284
        av_free (os->buf);
285
        os->buf = nb;
286
    }
287
288
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
289
        return -1;
290
291
    os->lastgp = os->granule;
292
    os->bufpos += size;
293
    os->granule = gp;
294
    os->flags = flags;
295
296
    if (str)
297
        *str = idx;
298
299
    return 0;
300
}
301
302
static int
303 12a195e3 Måns Rullgård
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
304 9146ca37 Måns Rullgård
{
305
    ogg_t *ogg = s->priv_data;
306
    int idx;
307
    ogg_stream_t *os;
308
    int complete = 0;
309
    int segp = 0, psize = 0;
310
311
#if 0
312
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
313
#endif
314
315
    do{
316
        idx = ogg->curidx;
317
318
        while (idx < 0){
319
            if (ogg_read_page (s, &idx) < 0)
320
                return -1;
321
        }
322
323
        os = ogg->streams + idx;
324
325
#if 0
326
        av_log (s, AV_LOG_DEBUG,
327
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
328
                idx, os->pstart, os->psize, os->segp, os->nsegs);
329
#endif
330
331
        if (!os->codec){
332
            if (os->header < 0){
333
                os->codec = ogg_find_codec (os->buf, os->bufpos);
334
                if (!os->codec){
335
                    os->header = 0;
336
                    return 0;
337
                }
338
            }else{
339
                return 0;
340
            }
341
        }
342
343
        segp = os->segp;
344
        psize = os->psize;
345
346
        while (os->segp < os->nsegs){
347
            int ss = os->segments[os->segp++];
348
            os->psize += ss;
349
            if (ss < 255){
350
                complete = 1;
351
                break;
352
            }
353
        }
354
355
        if (!complete && os->segp == os->nsegs){
356
            ogg->curidx = -1;
357
        }
358
    }while (!complete);
359
360
#if 0
361
    av_log (s, AV_LOG_DEBUG,
362
            "ogg_packet: idx %i, frame size %i, start %i\n",
363
            idx, os->psize, os->pstart);
364
#endif
365
366
    ogg->curidx = idx;
367
368
    if (os->header < 0){
369
        int hdr = os->codec->header (s, idx);
370
        if (!hdr){
371
          os->header = os->seq;
372
          os->segp = segp;
373
          os->psize = psize;
374
          ogg->headers = 1;
375
        }else{
376
          os->pstart += os->psize;
377
          os->psize = 0;
378
        }
379
    }
380
381
    if (os->header > -1 && os->seq > os->header){
382 e1a794b2 Måns Rullgård
        os->pflags = 0;
383 9146ca37 Måns Rullgård
        if (os->codec && os->codec->packet)
384
            os->codec->packet (s, idx);
385
        if (str)
386
            *str = idx;
387 12a195e3 Måns Rullgård
        if (dstart)
388
            *dstart = os->pstart;
389
        if (dsize)
390
            *dsize = os->psize;
391
        os->pstart += os->psize;
392
        os->psize = 0;
393 9146ca37 Måns Rullgård
    }
394
395
    os->seq++;
396
    if (os->segp == os->nsegs)
397
        ogg->curidx = -1;
398
399
    return 0;
400
}
401
402
static int
403
ogg_get_headers (AVFormatContext * s)
404
{
405
    ogg_t *ogg = s->priv_data;
406
407
    do{
408 12a195e3 Måns Rullgård
        if (ogg_packet (s, NULL, NULL, NULL) < 0)
409 9146ca37 Måns Rullgård
            return -1;
410
    }while (!ogg->headers);
411
412
#if 0
413
    av_log (s, AV_LOG_DEBUG, "found headers\n");
414
#endif
415
416
    return 0;
417
}
418
419
static uint64_t
420
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
421
{
422 1ed923ea Måns Rullgård
    ogg_t *ogg = s->priv_data;
423
    ogg_stream_t *os = ogg->streams + i;
424 9146ca37 Måns Rullgård
    uint64_t pts = AV_NOPTS_VALUE;
425
426 1ed923ea Måns Rullgård
    if(os->codec->gptopts){
427 bb270c08 Diego Biurrun
        pts = os->codec->gptopts(s, i, gp);
428 3644cb8f Måns Rullgård
    } else {
429 1ed923ea Måns Rullgård
        pts = gp;
430 9146ca37 Måns Rullgård
    }
431
432
    return pts;
433
}
434
435
436
static int
437
ogg_get_length (AVFormatContext * s)
438
{
439
    ogg_t *ogg = s->priv_data;
440
    int idx = -1, i;
441 56466d7b Måns Rullgård
    offset_t size, end;
442 69599eea Måns Rullgård
443 ceeacce6 Aurelien Jacobs
    if(url_is_streamed(s->pb))
444 69599eea Måns Rullgård
        return 0;
445 9146ca37 Måns Rullgård
446
// already set
447
    if (s->duration != AV_NOPTS_VALUE)
448
        return 0;
449
450 899681cd Björn Axelsson
    size = url_fsize(s->pb);
451 56466d7b Måns Rullgård
    if(size < 0)
452
        return 0;
453
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
454
455 9146ca37 Måns Rullgård
    ogg_save (s);
456 899681cd Björn Axelsson
    url_fseek (s->pb, end, SEEK_SET);
457 9146ca37 Måns Rullgård
458
    while (!ogg_read_page (s, &i)){
459 e22f2aaf Måns Rullgård
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
460
            ogg->streams[i].codec)
461 9146ca37 Måns Rullgård
            idx = i;
462
    }
463
464
    if (idx != -1){
465
        s->streams[idx]->duration =
466
            ogg_gptopts (s, idx, ogg->streams[idx].granule);
467
    }
468
469 56466d7b Måns Rullgård
    ogg->size = size;
470 9146ca37 Måns Rullgård
    ogg_restore (s, 0);
471
472
    return 0;
473
}
474
475
476
static int
477
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
478
{
479
    ogg_t *ogg = s->priv_data;
480
    ogg->curidx = -1;
481
    //linear headers seek from start
482
    if (ogg_get_headers (s) < 0){
483
      return -1;
484
    }
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
494
static int
495
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
496
{
497
    ogg_t *ogg;
498
    ogg_stream_t *os;
499
    int idx = -1;
500 12a195e3 Måns Rullgård
    int pstart, psize;
501 9146ca37 Måns Rullgård
502 115329f1 Diego Biurrun
    //Get an ogg packet
503 9146ca37 Måns Rullgård
    do{
504 12a195e3 Måns Rullgård
        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
505 6f3e0b21 Panagiotis Issaris
            return AVERROR(EIO);
506 9146ca37 Måns Rullgård
    }while (idx < 0 || !s->streams[idx]);
507
508
    ogg = s->priv_data;
509
    os = ogg->streams + idx;
510
511
    //Alloc a pkt
512 12a195e3 Måns Rullgård
    if (av_new_packet (pkt, psize) < 0)
513 6f3e0b21 Panagiotis Issaris
        return AVERROR(EIO);
514 9146ca37 Måns Rullgård
    pkt->stream_index = idx;
515 12a195e3 Måns Rullgård
    memcpy (pkt->data, os->buf + pstart, psize);
516 9146ca37 Måns Rullgård
    if (os->lastgp != -1LL){
517
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
518
        os->lastgp = -1;
519
    }
520 12a195e3 Måns Rullgård
521 e1a794b2 Måns Rullgård
    pkt->flags = os->pflags;
522
523 12a195e3 Måns Rullgård
    return psize;
524 9146ca37 Måns Rullgård
}
525
526
527
static int
528
ogg_read_close (AVFormatContext * s)
529
{
530
    ogg_t *ogg = s->priv_data;
531
    int i;
532
533
    for (i = 0; i < ogg->nstreams; i++){
534
        av_free (ogg->streams[i].buf);
535 1ed923ea Måns Rullgård
        av_free (ogg->streams[i].private);
536 9146ca37 Måns Rullgård
    }
537
    av_free (ogg->streams);
538
    return 0;
539
}
540
541
542
static int64_t
543
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
544
                    int64_t pos_limit)
545
{
546
    ogg_t *ogg = s->priv_data;
547 899681cd Björn Axelsson
    ByteIOContext *bc = s->pb;
548 a1f29b95 Reimar Döffinger
    int64_t pts = AV_NOPTS_VALUE;
549
    int i;
550
    url_fseek(bc, *pos_arg, SEEK_SET);
551
    while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
552
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
553
            ogg->streams[i].codec && i == stream_index) {
554
            pts = ogg_gptopts(s, i, ogg->streams[i].granule);
555
            // FIXME: this is the position of the packet after the one with above
556
            // pts.
557
            *pos_arg = url_ftell(bc);
558
            break;
559
        }
560
    }
561
    ogg_reset(ogg);
562
    return pts;
563 9146ca37 Måns Rullgård
}
564
565 2e70e4aa Måns Rullgård
static int ogg_probe(AVProbeData *p)
566
{
567
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
568
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
569
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
570
        return AVPROBE_SCORE_MAX;
571
    else
572
        return 0;
573
}
574
575 ff70e601 Måns Rullgård
AVInputFormat ogg_demuxer = {
576 9146ca37 Måns Rullgård
    "ogg",
577 bde15e74 Stefano Sabatini
    NULL_IF_CONFIG_SMALL("Ogg"),
578 9146ca37 Måns Rullgård
    sizeof (ogg_t),
579 2e70e4aa Måns Rullgård
    ogg_probe,
580 9146ca37 Måns Rullgård
    ogg_read_header,
581
    ogg_read_packet,
582
    ogg_read_close,
583 ce3132be Reimar Döffinger
    NULL,
584 a1f29b95 Reimar Döffinger
    ogg_read_timestamp,
585 9146ca37 Måns Rullgård
    .extensions = "ogg",
586
};