Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ ecc0027b

History | View | Annotate | Download (14.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_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->nsegs = 0;
124
        os->segp = 0;
125
        os->incomplete = 0;
126
    }
127

    
128
    ogg->curidx = -1;
129

    
130
    return 0;
131
}
132

    
133
static const struct ogg_codec *
134
ogg_find_codec (uint8_t * buf, int size)
135
{
136
    int i;
137

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

    
143
    return NULL;
144
}
145

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

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

    
155
    return -1;
156
}
157

    
158
static int
159
ogg_new_stream (AVFormatContext * s, uint32_t serial)
160
{
161

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

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

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

    
180
    av_set_pts_info(st, 64, 1, 1000000);
181

    
182
    return idx;
183
}
184

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

    
199
    return 0;
200
}
201

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

    
218
    if (get_buffer (bc, sync, 4) < 4)
219
        return -1;
220

    
221
    do{
222
        int c;
223

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

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

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

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

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

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

    
257
    os = ogg->streams + idx;
258

    
259
    if(os->psize > 0)
260
        ogg_new_buf(ogg, idx);
261

    
262
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
263
        return -1;
264

    
265
    os->nsegs = nsegs;
266
    os->segp = 0;
267

    
268
    size = 0;
269
    for (i = 0; i < nsegs; i++)
270
        size += os->segments[i];
271

    
272
    if (flags & OGG_FLAG_CONT || os->incomplete){
273
        if (!os->psize){
274
            while (os->segp < os->nsegs){
275
                int seg = os->segments[os->segp++];
276
                os->pstart += seg;
277
                if (seg < 255)
278
                    break;
279
            }
280
        }
281
    }else{
282
        os->psize = 0;
283
    }
284

    
285
    if (os->bufsize - os->bufpos < size){
286
        uint8_t *nb = av_malloc (os->bufsize *= 2);
287
        memcpy (nb, os->buf, os->bufpos);
288
        av_free (os->buf);
289
        os->buf = nb;
290
    }
291

    
292
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
293
        return -1;
294

    
295
    os->bufpos += size;
296
    os->granule = gp;
297
    os->flags = flags;
298

    
299
    if (str)
300
        *str = idx;
301

    
302
    return 0;
303
}
304

    
305
static int
306
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
307
{
308
    struct ogg *ogg = s->priv_data;
309
    int idx, i;
310
    struct ogg_stream *os;
311
    int complete = 0;
312
    int segp = 0, psize = 0;
313

    
314
#if 0
315
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
316
#endif
317

    
318
    do{
319
        idx = ogg->curidx;
320

    
321
        while (idx < 0){
322
            if (ogg_read_page (s, &idx) < 0)
323
                return -1;
324
        }
325

    
326
        os = ogg->streams + idx;
327

    
328
#if 0
329
        av_log (s, AV_LOG_DEBUG,
330
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
331
                idx, os->pstart, os->psize, os->segp, os->nsegs);
332
#endif
333

    
334
        if (!os->codec){
335
            if (os->header < 0){
336
                os->codec = ogg_find_codec (os->buf, os->bufpos);
337
                if (!os->codec){
338
                    os->header = 0;
339
                    return 0;
340
                }
341
            }else{
342
                return 0;
343
            }
344
        }
345

    
346
        segp = os->segp;
347
        psize = os->psize;
348

    
349
        while (os->segp < os->nsegs){
350
            int ss = os->segments[os->segp++];
351
            os->psize += ss;
352
            if (ss < 255){
353
                complete = 1;
354
                break;
355
            }
356
        }
357

    
358
        if (!complete && os->segp == os->nsegs){
359
            ogg->curidx = -1;
360
            os->incomplete = 1;
361
        }
362
    }while (!complete);
363

    
364
#if 0
365
    av_log (s, AV_LOG_DEBUG,
366
            "ogg_packet: idx %i, frame size %i, start %i\n",
367
            idx, os->psize, os->pstart);
368
#endif
369

    
370
    ogg->curidx = idx;
371
    os->incomplete = 0;
372

    
373
    if (os->header < 0){
374
        int hdr = os->codec->header (s, idx);
375
        if (!hdr){
376
            os->header = os->seq;
377
            os->segp = segp;
378
            os->psize = psize;
379
            ogg->headers = 1;
380
        }else{
381
            os->pstart += os->psize;
382
            os->psize = 0;
383
        }
384
    }
385

    
386
    if (os->header > -1 && os->seq > os->header){
387
        os->pflags = 0;
388
        os->pduration = 0;
389
        if (os->codec && os->codec->packet)
390
            os->codec->packet (s, idx);
391
        if (str)
392
            *str = idx;
393
        if (dstart)
394
            *dstart = os->pstart;
395
        if (dsize)
396
            *dsize = os->psize;
397
        os->pstart += os->psize;
398
        os->psize = 0;
399
    }
400

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

    
410
    os->seq++;
411
    if (os->segp == os->nsegs)
412
        ogg->curidx = -1;
413

    
414
    return 0;
415
}
416

    
417
static int
418
ogg_get_headers (AVFormatContext * s)
419
{
420
    struct ogg *ogg = s->priv_data;
421

    
422
    do{
423
        if (ogg_packet (s, NULL, NULL, NULL) < 0)
424
            return -1;
425
    }while (!ogg->headers);
426

    
427
#if 0
428
    av_log (s, AV_LOG_DEBUG, "found headers\n");
429
#endif
430

    
431
    return 0;
432
}
433

    
434
static uint64_t
435
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp, int64_t *dts)
436
{
437
    struct ogg *ogg = s->priv_data;
438
    struct ogg_stream *os = ogg->streams + i;
439
    uint64_t pts = AV_NOPTS_VALUE;
440

    
441
    if(os->codec->gptopts){
442
        pts = os->codec->gptopts(s, i, gp, dts);
443
    } else {
444
        pts = gp;
445
        if (dts)
446
            *dts = pts;
447
    }
448

    
449
    return pts;
450
}
451

    
452

    
453
static int
454
ogg_get_length (AVFormatContext * s)
455
{
456
    struct ogg *ogg = s->priv_data;
457
    int idx = -1, i;
458
    int64_t size, end;
459

    
460
    if(url_is_streamed(s->pb))
461
        return 0;
462

    
463
// already set
464
    if (s->duration != AV_NOPTS_VALUE)
465
        return 0;
466

    
467
    size = url_fsize(s->pb);
468
    if(size < 0)
469
        return 0;
470
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
471

    
472
    ogg_save (s);
473
    url_fseek (s->pb, end, SEEK_SET);
474

    
475
    while (!ogg_read_page (s, &i)){
476
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
477
            ogg->streams[i].codec)
478
            idx = i;
479
    }
480

    
481
    if (idx != -1){
482
        s->streams[idx]->duration =
483
            ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
484
    }
485

    
486
    ogg->size = size;
487
    ogg_restore (s, 0);
488

    
489
    return 0;
490
}
491

    
492

    
493
static int
494
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
495
{
496
    struct ogg *ogg = s->priv_data;
497
    int i;
498
    ogg->curidx = -1;
499
    //linear headers seek from start
500
    if (ogg_get_headers (s) < 0){
501
        return -1;
502
    }
503

    
504
    for (i = 0; i < ogg->nstreams; i++)
505
        if (ogg->streams[i].header < 0)
506
            ogg->streams[i].codec = NULL;
507

    
508
    //linear granulepos seek from end
509
    ogg_get_length (s);
510

    
511
    //fill the extradata in the per codec callbacks
512
    return 0;
513
}
514

    
515

    
516
static int
517
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
518
{
519
    struct ogg *ogg;
520
    struct ogg_stream *os;
521
    int idx = -1;
522
    int pstart, psize;
523

    
524
    //Get an ogg packet
525
    do{
526
        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
527
            return AVERROR(EIO);
528
    }while (idx < 0 || !s->streams[idx]);
529

    
530
    ogg = s->priv_data;
531
    os = ogg->streams + idx;
532

    
533
    //Alloc a pkt
534
    if (av_new_packet (pkt, psize) < 0)
535
        return AVERROR(EIO);
536
    pkt->stream_index = idx;
537
    memcpy (pkt->data, os->buf + pstart, psize);
538

    
539
    if (os->lastpts != AV_NOPTS_VALUE) {
540
        pkt->pts = os->lastpts;
541
        os->lastpts = AV_NOPTS_VALUE;
542
    }
543
    if (os->lastdts != AV_NOPTS_VALUE) {
544
        pkt->dts = os->lastdts;
545
        os->lastdts = AV_NOPTS_VALUE;
546
    }
547
    if (os->page_end) {
548
        if (os->granule != -1LL) {
549
            if (os->codec && os->codec->granule_is_start)
550
                pkt->pts    = ogg_gptopts(s, idx, os->granule, &pkt->dts);
551
            else
552
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
553
            os->granule = -1LL;
554
        } else
555
            av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
556
    }
557

    
558
    pkt->flags = os->pflags;
559
    pkt->duration = os->pduration;
560

    
561
    return psize;
562
}
563

    
564

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

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

    
579

    
580
static int64_t
581
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
582
                    int64_t pos_limit)
583
{
584
    struct ogg *ogg = s->priv_data;
585
    ByteIOContext *bc = s->pb;
586
    int64_t pts = AV_NOPTS_VALUE;
587
    int i;
588
    url_fseek(bc, *pos_arg, SEEK_SET);
589
    while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
590
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
591
            ogg->streams[i].codec && i == stream_index) {
592
            pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
593
            // FIXME: this is the position of the packet after the one with above
594
            // pts.
595
            *pos_arg = url_ftell(bc);
596
            break;
597
        }
598
    }
599
    ogg_reset(ogg);
600
    return pts;
601
}
602

    
603
static int ogg_probe(AVProbeData *p)
604
{
605
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
606
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
607
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
608
        return AVPROBE_SCORE_MAX;
609
    else
610
        return 0;
611
}
612

    
613
AVInputFormat ogg_demuxer = {
614
    "ogg",
615
    NULL_IF_CONFIG_SMALL("Ogg"),
616
    sizeof (struct ogg),
617
    ogg_probe,
618
    ogg_read_header,
619
    ogg_read_packet,
620
    ogg_read_close,
621
    NULL,
622
    ogg_read_timestamp,
623
    .extensions = "ogg",
624
    .metadata_conv = ff_vorbiscomment_metadata_conv,
625
};