Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ 5f8e0227

History | View | Annotate | Download (12.9 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 ogg_codec_t *ogg_codecs[] = {
41
    &speex_codec,
42
    &vorbis_codec,
43
    &theora_codec,
44
    &flac_codec,
45
    &old_flac_codec,
46
    &ogm_video_codec,
47
    &ogm_audio_codec,
48
    &ogm_text_codec,
49
    &ogm_old_codec,
50
    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
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
60
    int i;
61
    ost->pos = url_ftell (s->pb);
62
    ost->curidx = ogg->curidx;
63
    ost->next = ogg->state;
64
    ost->nstreams = ogg->nstreams;
65
    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
    ByteIOContext *bc = s->pb;
84
    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
        ogg->nstreams = ost->nstreams;
99
        memcpy(ogg->streams, ost->streams,
100
               ost->nstreams * sizeof(*ogg->streams));
101
    }
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
ogg_find_codec (uint8_t * buf, int size)
131
{
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
    os->buf = av_malloc(os->bufsize);
170
    os->header = -1;
171

    
172
    st = av_new_stream (s, idx);
173
    if (!st)
174
        return AVERROR(ENOMEM);
175

    
176
    av_set_pts_info(st, 64, 1, 1000000);
177

    
178
    return idx;
179
}
180

    
181
static int
182
ogg_new_buf(ogg_t *ogg, int idx)
183
{
184
    ogg_stream_t *os = ogg->streams + idx;
185
    uint8_t *nb = av_malloc(os->bufsize);
186
    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
ogg_read_page (AVFormatContext * s, int *str)
200
{
201
    ByteIOContext *bc = s->pb;
202
    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
    uint8_t sync[4];
212
    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
    if(os->psize > 0)
256
        ogg_new_buf(ogg, idx);
257

    
258
    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
        uint8_t *nb = av_malloc (os->bufsize *= 2);
283
        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
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
304
{
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
        os->pflags = 0;
383
        if (os->codec && os->codec->packet)
384
            os->codec->packet (s, idx);
385
        if (str)
386
            *str = idx;
387
        if (dstart)
388
            *dstart = os->pstart;
389
        if (dsize)
390
            *dsize = os->psize;
391
        os->pstart += os->psize;
392
        os->psize = 0;
393
    }
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
        if (ogg_packet (s, NULL, NULL, NULL) < 0)
409
            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
    ogg_t *ogg = s->priv_data;
423
    ogg_stream_t *os = ogg->streams + i;
424
    uint64_t pts = AV_NOPTS_VALUE;
425

    
426
    if(os->codec->gptopts){
427
        pts = os->codec->gptopts(s, i, gp);
428
    } else {
429
        pts = gp;
430
    }
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
    offset_t size, end;
442

    
443
    if(url_is_streamed(s->pb))
444
        return 0;
445

    
446
// already set
447
    if (s->duration != AV_NOPTS_VALUE)
448
        return 0;
449

    
450
    size = url_fsize(s->pb);
451
    if(size < 0)
452
        return 0;
453
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
454

    
455
    ogg_save (s);
456
    url_fseek (s->pb, end, SEEK_SET);
457

    
458
    while (!ogg_read_page (s, &i)){
459
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
460
            ogg->streams[i].codec)
461
            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
    ogg->size = size;
470
    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
    int pstart, psize;
501

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

    
508
    ogg = s->priv_data;
509
    os = ogg->streams + idx;
510

    
511
    //Alloc a pkt
512
    if (av_new_packet (pkt, psize) < 0)
513
        return AVERROR(EIO);
514
    pkt->stream_index = idx;
515
    memcpy (pkt->data, os->buf + pstart, psize);
516
    if (os->lastgp != -1LL){
517
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
518
        os->lastgp = -1;
519
    }
520

    
521
    pkt->flags = os->pflags;
522

    
523
    return psize;
524
}
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
        av_free (ogg->streams[i].private);
536
    }
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
    ByteIOContext *bc = s->pb;
548
    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
}
564

    
565
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
AVInputFormat ogg_demuxer = {
576
    "ogg",
577
    NULL_IF_CONFIG_SMALL("Ogg"),
578
    sizeof (ogg_t),
579
    ogg_probe,
580
    ogg_read_header,
581
    ogg_read_packet,
582
    ogg_read_close,
583
    NULL,
584
    ogg_read_timestamp,
585
    .extensions = "ogg",
586
};