Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 32ad8692

History | View | Annotate | Download (14.2 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
    }
464

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

    
468
    return 0;
469
}
470

    
471

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

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

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

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

    
494

    
495
static int
496
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
497
{
498
    struct ogg *ogg;
499
    struct ogg_stream *os;
500
    int idx = -1;
501
    int pstart, psize;
502
    int64_t fpos;
503

    
504
    //Get an ogg packet
505
    do{
506
        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
507
            return AVERROR(EIO);
508
    }while (idx < 0 || !s->streams[idx]);
509

    
510
    ogg = s->priv_data;
511
    os = ogg->streams + idx;
512

    
513
    //Alloc a pkt
514
    if (av_new_packet (pkt, psize) < 0)
515
        return AVERROR(EIO);
516
    pkt->stream_index = idx;
517
    memcpy (pkt->data, os->buf + pstart, psize);
518

    
519
    if (os->lastpts != AV_NOPTS_VALUE) {
520
        pkt->pts = os->lastpts;
521
        os->lastpts = AV_NOPTS_VALUE;
522
    }
523
    if (os->lastdts != AV_NOPTS_VALUE) {
524
        pkt->dts = os->lastdts;
525
        os->lastdts = AV_NOPTS_VALUE;
526
    }
527
    if (os->page_end) {
528
        if (os->granule != -1LL) {
529
            if (os->codec && os->codec->granule_is_start)
530
                pkt->pts    = ogg_gptopts(s, idx, os->granule, &pkt->dts);
531
            else
532
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
533
            os->granule = -1LL;
534
        } else
535
            av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
536
    }
537

    
538
    pkt->flags = os->pflags;
539
    pkt->duration = os->pduration;
540
    pkt->pos = fpos;
541

    
542
    return psize;
543
}
544

    
545

    
546
static int
547
ogg_read_close (AVFormatContext * s)
548
{
549
    struct ogg *ogg = s->priv_data;
550
    int i;
551

    
552
    for (i = 0; i < ogg->nstreams; i++){
553
        av_free (ogg->streams[i].buf);
554
        av_free (ogg->streams[i].private);
555
    }
556
    av_free (ogg->streams);
557
    return 0;
558
}
559

    
560

    
561
static int64_t
562
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
563
                    int64_t pos_limit)
564
{
565
    struct ogg *ogg = s->priv_data;
566
    ByteIOContext *bc = s->pb;
567
    int64_t pts = AV_NOPTS_VALUE;
568
    int i;
569
    url_fseek(bc, *pos_arg, SEEK_SET);
570
    while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
571
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
572
            ogg->streams[i].codec && i == stream_index) {
573
            pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
574
            // FIXME: this is the position of the packet after the one with above
575
            // pts.
576
            *pos_arg = url_ftell(bc);
577
            break;
578
        }
579
    }
580
    ogg_reset(ogg);
581
    return pts;
582
}
583

    
584
static int ogg_probe(AVProbeData *p)
585
{
586
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
587
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
588
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
589
        return AVPROBE_SCORE_MAX;
590
    else
591
        return 0;
592
}
593

    
594
AVInputFormat ogg_demuxer = {
595
    "ogg",
596
    NULL_IF_CONFIG_SMALL("Ogg"),
597
    sizeof (struct ogg),
598
    ogg_probe,
599
    ogg_read_header,
600
    ogg_read_packet,
601
    ogg_read_close,
602
    NULL,
603
    ogg_read_timestamp,
604
    .extensions = "ogg",
605
    .metadata_conv = ff_vorbiscomment_metadata_conv,
606
};