Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 25f8db58

History | View | Annotate | Download (13.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
 * 
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 "ogg2.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
    &vorbis_codec,
42 1ed923ea Måns Rullgård
    &theora_codec,
43 bcfc40ae Måns Rullgård
    &flac_codec,
44 9146ca37 Måns Rullgård
    NULL
45
};
46
47 a9e35095 Diego Biurrun
#if 0                           // CONFIG_MUXERS
48 9146ca37 Måns Rullgård
static int
49
ogg_write_header (AVFormatContext * avfcontext)
50
{
51
}
52

53
static int
54
ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
55
{
56
}
57

58

59
static int
60
ogg_write_trailer (AVFormatContext * avfcontext)
61
{
62
}
63

64

65
static AVOutputFormat ogg_oformat = {
66
    "ogg",
67
    "Ogg Vorbis",
68
    "audio/x-vorbis",
69
    "ogg",
70
    sizeof (OggContext),
71
    CODEC_ID_VORBIS,
72
    0,
73
    ogg_write_header,
74
    ogg_write_packet,
75
    ogg_write_trailer,
76
};
77 a9e35095 Diego Biurrun
#endif //CONFIG_MUXERS
78 9146ca37 Måns Rullgård
79
//FIXME We could avoid some structure duplication
80
static int
81
ogg_save (AVFormatContext * s)
82
{
83
    ogg_t *ogg = s->priv_data;
84
    ogg_state_t *ost =
85 ad3aa874 Måns Rullgård
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
86 9146ca37 Måns Rullgård
    int i;
87
    ost->pos = url_ftell (&s->pb);;
88
    ost->curidx = ogg->curidx;
89
    ost->next = ogg->state;
90
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
91
92
    for (i = 0; i < ogg->nstreams; i++){
93
        ogg_stream_t *os = ogg->streams + i;
94
        os->buf = av_malloc (os->bufsize);
95
        memset (os->buf, 0, os->bufsize);
96
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
97
    }
98
99
    ogg->state = ost;
100
101
    return 0;
102
}
103
104
static int
105
ogg_restore (AVFormatContext * s, int discard)
106
{
107
    ogg_t *ogg = s->priv_data;
108
    ByteIOContext *bc = &s->pb;
109
    ogg_state_t *ost = ogg->state;
110
    int i;
111
112
    if (!ost)
113
        return 0;
114
115
    ogg->state = ost->next;
116
117
    if (!discard){
118
        for (i = 0; i < ogg->nstreams; i++)
119
            av_free (ogg->streams[i].buf);
120
121
        url_fseek (bc, ost->pos, SEEK_SET);
122
        ogg->curidx = ost->curidx;
123
        memcpy (ogg->streams, ost->streams,
124
        ogg->nstreams * sizeof (*ogg->streams));
125
    }
126
127
    av_free (ost);
128
129
    return 0;
130
}
131
132
static int
133
ogg_reset (ogg_t * ogg)
134
{
135
    int i;
136
137
    for (i = 0; i < ogg->nstreams; i++){
138
        ogg_stream_t *os = ogg->streams + i;
139
        os->bufpos = 0;
140
        os->pstart = 0;
141
        os->psize = 0;
142
        os->granule = -1;
143
        os->lastgp = -1;
144
        os->nsegs = 0;
145
        os->segp = 0;
146
    }
147
148
    ogg->curidx = -1;
149
150
    return 0;
151
}
152
153
static ogg_codec_t *
154 2d2f443d Måns Rullgård
ogg_find_codec (uint8_t * buf, int size)
155 9146ca37 Måns Rullgård
{
156
    int i;
157
158
    for (i = 0; ogg_codecs[i]; i++)
159
        if (size >= ogg_codecs[i]->magicsize &&
160
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
161
            return ogg_codecs[i];
162
163
    return NULL;
164
}
165
166
static int
167
ogg_find_stream (ogg_t * ogg, int serial)
168
{
169
    int i;
170
171
    for (i = 0; i < ogg->nstreams; i++)
172
        if (ogg->streams[i].serial == serial)
173
            return i;
174
175
    return -1;
176
}
177
178
static int
179
ogg_new_stream (AVFormatContext * s, uint32_t serial)
180
{
181
182
    ogg_t *ogg = s->priv_data;
183
    int idx = ogg->nstreams++;
184
    AVStream *st;
185
    ogg_stream_t *os;
186
187
    ogg->streams = av_realloc (ogg->streams,
188
                               ogg->nstreams * sizeof (*ogg->streams));
189
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
190
    os = ogg->streams + idx;
191
    os->serial = serial;
192
    os->bufsize = DECODER_BUFFER_SIZE;
193
    os->buf = av_malloc (os->bufsize);
194
    memset (os->buf, 0, os->bufsize);
195
    os->header = -1;
196
197
    st = av_new_stream (s, idx);
198
    if (!st)
199
        return AVERROR_NOMEM;
200
201
    av_set_pts_info(st, 64, 1, 1000000);
202
    st->start_time = 0;
203
204
    return idx;
205
}
206
207
static int
208
ogg_read_page (AVFormatContext * s, int *str)
209
{
210
    ByteIOContext *bc = &s->pb;
211
    ogg_t *ogg = s->priv_data;
212
    ogg_stream_t *os;
213
    int i = 0;
214
    int flags, nsegs;
215
    uint64_t gp;
216
    uint32_t serial;
217
    uint32_t seq;
218
    uint32_t crc;
219
    int size, idx;
220
    char sync[4];
221
    int sp = 0;
222
223
    if (get_buffer (bc, sync, 4) < 4)
224
        return -1;
225
226
    do{
227
        int c;
228
229
        if (sync[sp & 3] == 'O' &&
230
            sync[(sp + 1) & 3] == 'g' &&
231
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
232
            break;
233
234
        c = url_fgetc (bc);
235
        if (c < 0)
236
            return -1;
237
        sync[sp++ & 3] = c;
238
    }while (i++ < MAX_PAGE_SIZE);
239
240
    if (i >= MAX_PAGE_SIZE){
241
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
242
        return -1;
243
    }
244
245
    if (url_fgetc (bc) != 0)      /* version */
246
        return -1;
247
248
    flags = url_fgetc (bc);
249
    gp = get_le64 (bc);
250
    serial = get_le32 (bc);
251
    seq = get_le32 (bc);
252
    crc = get_le32 (bc);
253
    nsegs = url_fgetc (bc);
254
255
    idx = ogg_find_stream (ogg, serial);
256
    if (idx < 0){
257
        idx = ogg_new_stream (s, serial);
258
        if (idx < 0)
259
            return -1;
260
    }
261
262
    os = ogg->streams + idx;
263
264
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
265
        return -1;
266
267
    os->nsegs = nsegs;
268
    os->segp = 0;
269
270
    size = 0;
271
    for (i = 0; i < nsegs; i++)
272
        size += os->segments[i];
273
274
    if (flags & OGG_FLAG_CONT){
275
        if (!os->psize){
276
            while (os->segp < os->nsegs){
277
                int seg = os->segments[os->segp++];
278
                os->pstart += seg;
279
                if (seg < 255)
280
                  break;
281
            }
282
        }
283
    }else{
284
      os->psize = 0;
285
    }
286
287
    if (os->bufsize - os->bufpos < size){
288 2d2f443d Måns Rullgård
        uint8_t *nb = av_malloc (os->bufsize *= 2);
289 9146ca37 Måns Rullgård
        memset (nb, 0, os->bufsize);
290
        memcpy (nb, os->buf, os->bufpos);
291
        av_free (os->buf);
292
        os->buf = nb;
293
    }
294
295
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
296
        return -1;
297
298
    os->lastgp = os->granule;
299
    os->bufpos += size;
300
    os->granule = gp;
301
    os->flags = flags;
302
303
    if (str)
304
        *str = idx;
305
306
    return 0;
307
}
308
309
static int
310
ogg_packet (AVFormatContext * s, int *str)
311
{
312
    ogg_t *ogg = s->priv_data;
313
    int idx;
314
    ogg_stream_t *os;
315
    int complete = 0;
316
    int segp = 0, psize = 0;
317
318
#if 0
319
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
320
#endif
321
322
    do{
323
        idx = ogg->curidx;
324
325
        while (idx < 0){
326
            if (ogg_read_page (s, &idx) < 0)
327
                return -1;
328
        }
329
330
        os = ogg->streams + idx;
331
332
#if 0
333
        av_log (s, AV_LOG_DEBUG,
334
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
335
                idx, os->pstart, os->psize, os->segp, os->nsegs);
336
#endif
337
338
        if (!os->codec){
339
            if (os->header < 0){
340
                os->codec = ogg_find_codec (os->buf, os->bufpos);
341
                if (!os->codec){
342
                    os->header = 0;
343
                    return 0;
344
                }
345
            }else{
346
                return 0;
347
            }
348
        }
349
350
        segp = os->segp;
351
        psize = os->psize;
352
353
        while (os->segp < os->nsegs){
354
            int ss = os->segments[os->segp++];
355
            os->psize += ss;
356
            if (ss < 255){
357
                complete = 1;
358
                break;
359
            }
360
        }
361
362
        if (!complete && os->segp == os->nsegs){
363 2d2f443d Måns Rullgård
            uint8_t *nb = av_malloc (os->bufsize);
364 9146ca37 Måns Rullgård
            int size = os->bufpos - os->pstart;
365
            memset (nb, 0, os->bufsize);
366
            memcpy (nb, os->buf + os->pstart, size);
367
            av_free (os->buf);
368
            os->buf = nb;
369
            os->bufpos = size;
370
            os->pstart = 0;
371
            ogg->curidx = -1;
372
        }
373
    }while (!complete);
374
375
#if 0
376
    av_log (s, AV_LOG_DEBUG,
377
            "ogg_packet: idx %i, frame size %i, start %i\n",
378
            idx, os->psize, os->pstart);
379
#endif
380
381
    ogg->curidx = idx;
382
383
    if (os->header < 0){
384
        int hdr = os->codec->header (s, idx);
385
        if (!hdr){
386
          os->header = os->seq;
387
          os->segp = segp;
388
          os->psize = psize;
389
          ogg->headers = 1;
390
        }else{
391
          os->pstart += os->psize;
392
          os->psize = 0;
393
        }
394
    }
395
396
    if (os->header > -1 && os->seq > os->header){
397
        if (os->codec && os->codec->packet)
398
            os->codec->packet (s, idx);
399
        if (str)
400
            *str = idx;
401
    }
402
403
    os->seq++;
404
    if (os->segp == os->nsegs)
405
        ogg->curidx = -1;
406
407
    return 0;
408
}
409
410
static int
411
ogg_get_headers (AVFormatContext * s)
412
{
413
    ogg_t *ogg = s->priv_data;
414
415
    do{
416
        if (ogg_packet (s, NULL) < 0)
417
            return -1;
418
    }while (!ogg->headers);
419
420
#if 0
421
    av_log (s, AV_LOG_DEBUG, "found headers\n");
422
#endif
423
424
    return 0;
425
}
426
427
static uint64_t
428
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
429
{
430 1ed923ea Måns Rullgård
    ogg_t *ogg = s->priv_data;
431
    ogg_stream_t *os = ogg->streams + i;
432 9146ca37 Måns Rullgård
    AVStream *st = s->streams[i];
433 01f4895c Michael Niedermayer
    AVCodecContext *codec = st->codec;
434 9146ca37 Måns Rullgård
    uint64_t pts = AV_NOPTS_VALUE;
435
436 1ed923ea Måns Rullgård
    if(os->codec->gptopts){
437
        pts = os->codec->gptopts(s, i, gp);
438
    } else if (codec->codec_type == CODEC_TYPE_AUDIO){
439 9146ca37 Måns Rullgård
        pts = gp * 1000000LL / codec->sample_rate;
440
    }else if (codec->codec_type == CODEC_TYPE_VIDEO){
441 1ed923ea Måns Rullgård
        pts = gp;
442 9146ca37 Måns Rullgård
    }
443
444
    return pts;
445
}
446
447
448
static int
449
ogg_get_length (AVFormatContext * s)
450
{
451
    ogg_t *ogg = s->priv_data;
452
    int idx = -1, i;
453 69599eea Måns Rullgård
454
    if(s->pb.is_streamed)
455
        return 0;
456 9146ca37 Måns Rullgård
457
// already set
458
    if (s->duration != AV_NOPTS_VALUE)
459
        return 0;
460
461
    ogg_save (s);
462 a965c478 Aurelien Jacobs
    url_fseek (&s->pb, -MAX_PAGE_SIZE, SEEK_END);
463 9146ca37 Måns Rullgård
464
    while (!ogg_read_page (s, &i)){
465
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
466
            idx = i;
467
    }
468
469
    if (idx != -1){
470
        s->streams[idx]->duration =
471
            ogg_gptopts (s, idx, ogg->streams[idx].granule);
472
    }
473
474 a965c478 Aurelien Jacobs
    ogg->size = url_fsize(&s->pb);
475 9146ca37 Måns Rullgård
    ogg_restore (s, 0);
476
477
    return 0;
478
}
479
480
481
static int
482
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
483
{
484
    ogg_t *ogg = s->priv_data;
485
    ogg->curidx = -1;
486
    //linear headers seek from start
487
    if (ogg_get_headers (s) < 0){
488
      return -1;
489
    }
490
491
    //linear granulepos seek from end
492
    ogg_get_length (s);
493
494
    //fill the extradata in the per codec callbacks
495
    return 0;
496
}
497
498
499
static int
500
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
501
{
502
    ogg_t *ogg;
503
    ogg_stream_t *os;
504
    int idx = -1;
505
506
    //Get an ogg packet 
507
    do{
508
        if (ogg_packet (s, &idx) < 0)
509
            return AVERROR_IO;
510
    }while (idx < 0 || !s->streams[idx]);
511
512
    ogg = s->priv_data;
513
    os = ogg->streams + idx;
514
515
    //Alloc a pkt
516
    if (av_new_packet (pkt, os->psize) < 0)
517
        return AVERROR_IO;
518
    pkt->stream_index = idx;
519
    memcpy (pkt->data, os->buf + os->pstart, os->psize);
520
    if (os->lastgp != -1LL){
521
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
522
        os->lastgp = -1;
523
    }
524
    //next
525
    os->pstart += os->psize;
526
    os->psize = 0;
527
    return os->psize;
528
}
529
530
531
static int
532
ogg_read_close (AVFormatContext * s)
533
{
534
    ogg_t *ogg = s->priv_data;
535
    int i;
536
537
    for (i = 0; i < ogg->nstreams; i++){
538
        av_free (ogg->streams[i].buf);
539 1ed923ea Måns Rullgård
        av_free (ogg->streams[i].private);
540 01f4895c Michael Niedermayer
        av_freep (&s->streams[i]->codec->extradata);
541 9146ca37 Måns Rullgård
    }
542
    av_free (ogg->streams);
543
    return 0;
544
}
545
546
547
static int
548
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
549
               int flags)
550
{
551
    ogg_t *ogg = s->priv_data;
552
    ByteIOContext *bc = &s->pb;
553
    uint64_t min = 0, max = ogg->size;
554
    uint64_t tmin = 0, tmax = s->duration;
555
    int64_t pts = AV_NOPTS_VALUE;
556
557
    ogg_save (s);
558
559
    while (min <= max){
560 17929c04 Måns Rullgård
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
561 9146ca37 Måns Rullgård
        int i = -1;
562
563
        url_fseek (bc, p, SEEK_SET);
564
565
        while (!ogg_read_page (s, &i)){
566
            if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1)
567
                break;
568
        }
569
570
        if (i == -1)
571
            break;
572
573
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
574
        p = url_ftell (bc);
575
576
        if (ABS (pts - target_ts) < 1000000LL)
577
            break;
578
579
        if (pts > target_ts){
580
            max = p;
581
            tmax = pts;
582
        }else{
583
            min = p;
584
            tmin = pts;
585
        }
586
    }
587
588
    if (ABS (pts - target_ts) < 1000000LL){
589
        ogg_restore (s, 1);
590
        ogg_reset (ogg);
591
    }else{
592
        ogg_restore (s, 0);
593
        pts = AV_NOPTS_VALUE;
594
    }
595
596
    return pts;
597
598
#if 0
599
    //later...
600
    int64_t pos;
601
    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
602
        return -1;
603
    pos = url_ftell (&s->pb);
604
    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
605
#endif
606
607
}
608
609
#if 0
610
static int64_t
611
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
612
                    int64_t pos_limit)
613
{
614
    ogg_t *ogg = s->priv_data;
615
    ByteIOContext *bc = &s->pb;
616
    int64_t pos, pts;
617

618
    if (*pos_arg < 0)
619
        return AV_NOPTS_VALUE;
620

621
    pos = *pos_arg;
622
}
623
#endif
624
625
static AVInputFormat ogg_iformat = {
626
    "ogg",
627
    "Ogg",
628
    sizeof (ogg_t),
629
    NULL,
630
    ogg_read_header,
631
    ogg_read_packet,
632
    ogg_read_close,
633
    ogg_read_seek,
634
// ogg_read_timestamp, 
635
    .extensions = "ogg",
636
};
637
638
int
639
ogg_init (void)
640
{
641 a9e35095 Diego Biurrun
#if 0 // CONFIG_MUXERS
642 9146ca37 Måns Rullgård
    av_register_output_format (&ogg_oformat);
643
#endif
644
    av_register_input_format (&ogg_iformat);
645
    return 0;
646
}