Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 890d2799

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