Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 595da759

History | View | Annotate | Download (15.4 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 "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
    &theora_codec,
43
    &flac_codec,
44
    &ogm_video_codec,
45
    &ogm_audio_codec,
46
    &ogm_old_codec,
47
    NULL
48
};
49

    
50
#if 0                           // CONFIG_MUXERS
51
static int
52
ogg_write_header (AVFormatContext * avfcontext)
53
{
54
}
55

56
static int
57
ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
58
{
59
}
60

61

62
static int
63
ogg_write_trailer (AVFormatContext * avfcontext)
64
{
65
}
66

67

68
AVOutputFormat ogg_muxer = {
69
    "ogg",
70
    "Ogg Vorbis",
71
    "audio/x-vorbis",
72
    "ogg",
73
    sizeof (OggContext),
74
    CODEC_ID_VORBIS,
75
    0,
76
    ogg_write_header,
77
    ogg_write_packet,
78
    ogg_write_trailer,
79
};
80
#endif //CONFIG_MUXERS
81

    
82
//FIXME We could avoid some structure duplication
83
static int
84
ogg_save (AVFormatContext * s)
85
{
86
    ogg_t *ogg = s->priv_data;
87
    ogg_state_t *ost =
88
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
89
    int i;
90
    ost->pos = url_ftell (&s->pb);;
91
    ost->curidx = ogg->curidx;
92
    ost->next = ogg->state;
93
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
94

    
95
    for (i = 0; i < ogg->nstreams; i++){
96
        ogg_stream_t *os = ogg->streams + i;
97
        os->buf = av_malloc (os->bufsize);
98
        memset (os->buf, 0, os->bufsize);
99
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
100
    }
101

    
102
    ogg->state = ost;
103

    
104
    return 0;
105
}
106

    
107
static int
108
ogg_restore (AVFormatContext * s, int discard)
109
{
110
    ogg_t *ogg = s->priv_data;
111
    ByteIOContext *bc = &s->pb;
112
    ogg_state_t *ost = ogg->state;
113
    int i;
114

    
115
    if (!ost)
116
        return 0;
117

    
118
    ogg->state = ost->next;
119

    
120
    if (!discard){
121
        for (i = 0; i < ogg->nstreams; i++)
122
            av_free (ogg->streams[i].buf);
123

    
124
        url_fseek (bc, ost->pos, SEEK_SET);
125
        ogg->curidx = ost->curidx;
126
        memcpy (ogg->streams, ost->streams,
127
        ogg->nstreams * sizeof (*ogg->streams));
128
    }
129

    
130
    av_free (ost);
131

    
132
    return 0;
133
}
134

    
135
static int
136
ogg_reset (ogg_t * ogg)
137
{
138
    int i;
139

    
140
    for (i = 0; i < ogg->nstreams; i++){
141
        ogg_stream_t *os = ogg->streams + i;
142
        os->bufpos = 0;
143
        os->pstart = 0;
144
        os->psize = 0;
145
        os->granule = -1;
146
        os->lastgp = -1;
147
        os->nsegs = 0;
148
        os->segp = 0;
149
    }
150

    
151
    ogg->curidx = -1;
152

    
153
    return 0;
154
}
155

    
156
static ogg_codec_t *
157
ogg_find_codec (uint8_t * buf, int size)
158
{
159
    int i;
160

    
161
    for (i = 0; ogg_codecs[i]; i++)
162
        if (size >= ogg_codecs[i]->magicsize &&
163
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
164
            return ogg_codecs[i];
165

    
166
    return NULL;
167
}
168

    
169
static int
170
ogg_find_stream (ogg_t * ogg, int serial)
171
{
172
    int i;
173

    
174
    for (i = 0; i < ogg->nstreams; i++)
175
        if (ogg->streams[i].serial == serial)
176
            return i;
177

    
178
    return -1;
179
}
180

    
181
static int
182
ogg_new_stream (AVFormatContext * s, uint32_t serial)
183
{
184

    
185
    ogg_t *ogg = s->priv_data;
186
    int idx = ogg->nstreams++;
187
    AVStream *st;
188
    ogg_stream_t *os;
189

    
190
    ogg->streams = av_realloc (ogg->streams,
191
                               ogg->nstreams * sizeof (*ogg->streams));
192
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
193
    os = ogg->streams + idx;
194
    os->serial = serial;
195
    os->bufsize = DECODER_BUFFER_SIZE;
196
    os->buf = av_malloc(os->bufsize);
197
    os->header = -1;
198

    
199
    st = av_new_stream (s, idx);
200
    if (!st)
201
        return AVERROR_NOMEM;
202

    
203
    av_set_pts_info(st, 64, 1, 1000000);
204

    
205
    return idx;
206
}
207

    
208
static int
209
ogg_new_buf(ogg_t *ogg, int idx)
210
{
211
    ogg_stream_t *os = ogg->streams + idx;
212
    uint8_t *nb = av_malloc(os->bufsize);
213
    int size = os->bufpos - os->pstart;
214
    if(os->buf){
215
        memcpy(nb, os->buf + os->pstart, size);
216
        av_free(os->buf);
217
    }
218
    os->buf = nb;
219
    os->bufpos = size;
220
    os->pstart = 0;
221

    
222
    return 0;
223
}
224

    
225
static int
226
ogg_read_page (AVFormatContext * s, int *str)
227
{
228
    ByteIOContext *bc = &s->pb;
229
    ogg_t *ogg = s->priv_data;
230
    ogg_stream_t *os;
231
    int i = 0;
232
    int flags, nsegs;
233
    uint64_t gp;
234
    uint32_t serial;
235
    uint32_t seq;
236
    uint32_t crc;
237
    int size, idx;
238
    uint8_t sync[4];
239
    int sp = 0;
240

    
241
    if (get_buffer (bc, sync, 4) < 4)
242
        return -1;
243

    
244
    do{
245
        int c;
246

    
247
        if (sync[sp & 3] == 'O' &&
248
            sync[(sp + 1) & 3] == 'g' &&
249
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
250
            break;
251

    
252
        c = url_fgetc (bc);
253
        if (c < 0)
254
            return -1;
255
        sync[sp++ & 3] = c;
256
    }while (i++ < MAX_PAGE_SIZE);
257

    
258
    if (i >= MAX_PAGE_SIZE){
259
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
260
        return -1;
261
    }
262

    
263
    if (url_fgetc (bc) != 0)      /* version */
264
        return -1;
265

    
266
    flags = url_fgetc (bc);
267
    gp = get_le64 (bc);
268
    serial = get_le32 (bc);
269
    seq = get_le32 (bc);
270
    crc = get_le32 (bc);
271
    nsegs = url_fgetc (bc);
272

    
273
    idx = ogg_find_stream (ogg, serial);
274
    if (idx < 0){
275
        idx = ogg_new_stream (s, serial);
276
        if (idx < 0)
277
            return -1;
278
    }
279

    
280
    os = ogg->streams + idx;
281

    
282
    if(os->psize > 0)
283
        ogg_new_buf(ogg, idx);
284

    
285
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
286
        return -1;
287

    
288
    os->nsegs = nsegs;
289
    os->segp = 0;
290

    
291
    size = 0;
292
    for (i = 0; i < nsegs; i++)
293
        size += os->segments[i];
294

    
295
    if (flags & OGG_FLAG_CONT){
296
        if (!os->psize){
297
            while (os->segp < os->nsegs){
298
                int seg = os->segments[os->segp++];
299
                os->pstart += seg;
300
                if (seg < 255)
301
                  break;
302
            }
303
        }
304
    }else{
305
      os->psize = 0;
306
    }
307

    
308
    if (os->bufsize - os->bufpos < size){
309
        uint8_t *nb = av_malloc (os->bufsize *= 2);
310
        memcpy (nb, os->buf, os->bufpos);
311
        av_free (os->buf);
312
        os->buf = nb;
313
    }
314

    
315
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
316
        return -1;
317

    
318
    os->lastgp = os->granule;
319
    os->bufpos += size;
320
    os->granule = gp;
321
    os->flags = flags;
322

    
323
    if (str)
324
        *str = idx;
325

    
326
    return 0;
327
}
328

    
329
static int
330
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
331
{
332
    ogg_t *ogg = s->priv_data;
333
    int idx;
334
    ogg_stream_t *os;
335
    int complete = 0;
336
    int segp = 0, psize = 0;
337

    
338
#if 0
339
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
340
#endif
341

    
342
    do{
343
        idx = ogg->curidx;
344

    
345
        while (idx < 0){
346
            if (ogg_read_page (s, &idx) < 0)
347
                return -1;
348
        }
349

    
350
        os = ogg->streams + idx;
351

    
352
#if 0
353
        av_log (s, AV_LOG_DEBUG,
354
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
355
                idx, os->pstart, os->psize, os->segp, os->nsegs);
356
#endif
357

    
358
        if (!os->codec){
359
            if (os->header < 0){
360
                os->codec = ogg_find_codec (os->buf, os->bufpos);
361
                if (!os->codec){
362
                    os->header = 0;
363
                    return 0;
364
                }
365
            }else{
366
                return 0;
367
            }
368
        }
369

    
370
        segp = os->segp;
371
        psize = os->psize;
372

    
373
        while (os->segp < os->nsegs){
374
            int ss = os->segments[os->segp++];
375
            os->psize += ss;
376
            if (ss < 255){
377
                complete = 1;
378
                break;
379
            }
380
        }
381

    
382
        if (!complete && os->segp == os->nsegs){
383
            ogg->curidx = -1;
384
        }
385
    }while (!complete);
386

    
387
#if 0
388
    av_log (s, AV_LOG_DEBUG,
389
            "ogg_packet: idx %i, frame size %i, start %i\n",
390
            idx, os->psize, os->pstart);
391
#endif
392

    
393
    ogg->curidx = idx;
394

    
395
    if (os->header < 0){
396
        int hdr = os->codec->header (s, idx);
397
        if (!hdr){
398
          os->header = os->seq;
399
          os->segp = segp;
400
          os->psize = psize;
401
          ogg->headers = 1;
402
        }else{
403
          os->pstart += os->psize;
404
          os->psize = 0;
405
        }
406
    }
407

    
408
    if (os->header > -1 && os->seq > os->header){
409
        if (os->codec && os->codec->packet)
410
            os->codec->packet (s, idx);
411
        if (str)
412
            *str = idx;
413
        if (dstart)
414
            *dstart = os->pstart;
415
        if (dsize)
416
            *dsize = os->psize;
417
        os->pstart += os->psize;
418
        os->psize = 0;
419
    }
420

    
421
    os->seq++;
422
    if (os->segp == os->nsegs)
423
        ogg->curidx = -1;
424

    
425
    return 0;
426
}
427

    
428
static int
429
ogg_get_headers (AVFormatContext * s)
430
{
431
    ogg_t *ogg = s->priv_data;
432

    
433
    do{
434
        if (ogg_packet (s, NULL, NULL, NULL) < 0)
435
            return -1;
436
    }while (!ogg->headers);
437

    
438
#if 0
439
    av_log (s, AV_LOG_DEBUG, "found headers\n");
440
#endif
441

    
442
    return 0;
443
}
444

    
445
static uint64_t
446
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
447
{
448
    ogg_t *ogg = s->priv_data;
449
    ogg_stream_t *os = ogg->streams + i;
450
    uint64_t pts = AV_NOPTS_VALUE;
451

    
452
    if(os->codec->gptopts){
453
        pts = os->codec->gptopts(s, i, gp);
454
    } else {
455
        pts = gp;
456
    }
457

    
458
    return pts;
459
}
460

    
461

    
462
static int
463
ogg_get_length (AVFormatContext * s)
464
{
465
    ogg_t *ogg = s->priv_data;
466
    int idx = -1, i;
467
    offset_t size, end;
468

    
469
    if(s->pb.is_streamed)
470
        return 0;
471

    
472
// already set
473
    if (s->duration != AV_NOPTS_VALUE)
474
        return 0;
475

    
476
    size = url_fsize(&s->pb);
477
    if(size < 0)
478
        return 0;
479
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
480

    
481
    ogg_save (s);
482
    url_fseek (&s->pb, end, SEEK_SET);
483

    
484
    while (!ogg_read_page (s, &i)){
485
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
486
            idx = i;
487
    }
488

    
489
    if (idx != -1){
490
        s->streams[idx]->duration =
491
            ogg_gptopts (s, idx, ogg->streams[idx].granule);
492
    }
493

    
494
    ogg->size = size;
495
    ogg_restore (s, 0);
496
    ogg_save (s);
497
    while (!ogg_read_page (s, &i)) {
498
        if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
499
            break;
500
    }
501
    if (i == idx) {
502
        s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
503
        s->streams[idx]->duration -= s->streams[idx]->start_time;
504
    }
505
    ogg_restore (s, 0);
506

    
507
    return 0;
508
}
509

    
510

    
511
static int
512
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
513
{
514
    ogg_t *ogg = s->priv_data;
515
    ogg->curidx = -1;
516
    //linear headers seek from start
517
    if (ogg_get_headers (s) < 0){
518
      return -1;
519
    }
520

    
521
    //linear granulepos seek from end
522
    ogg_get_length (s);
523

    
524
    //fill the extradata in the per codec callbacks
525
    return 0;
526
}
527

    
528

    
529
static int
530
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
531
{
532
    ogg_t *ogg;
533
    ogg_stream_t *os;
534
    int idx = -1;
535
    int pstart, psize;
536

    
537
    //Get an ogg packet
538
    do{
539
        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
540
            return AVERROR_IO;
541
    }while (idx < 0 || !s->streams[idx]);
542

    
543
    ogg = s->priv_data;
544
    os = ogg->streams + idx;
545

    
546
    //Alloc a pkt
547
    if (av_new_packet (pkt, psize) < 0)
548
        return AVERROR_IO;
549
    pkt->stream_index = idx;
550
    memcpy (pkt->data, os->buf + pstart, psize);
551
    if (os->lastgp != -1LL){
552
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
553
        os->lastgp = -1;
554
    }
555

    
556
    return psize;
557
}
558

    
559

    
560
static int
561
ogg_read_close (AVFormatContext * s)
562
{
563
    ogg_t *ogg = s->priv_data;
564
    int i;
565

    
566
    for (i = 0; i < ogg->nstreams; i++){
567
        av_free (ogg->streams[i].buf);
568
        av_free (ogg->streams[i].private);
569
    }
570
    av_free (ogg->streams);
571
    return 0;
572
}
573

    
574

    
575
static int
576
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
577
               int flags)
578
{
579
    AVStream *st = s->streams[stream_index];
580
    ogg_t *ogg = s->priv_data;
581
    ByteIOContext *bc = &s->pb;
582
    uint64_t min = 0, max = ogg->size;
583
    uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
584
    int64_t pts = AV_NOPTS_VALUE;
585

    
586
    ogg_save (s);
587

    
588
    if ((uint64_t)target_ts < tmin || target_ts < 0)
589
        target_ts = tmin;
590
    while (min <= max && tmin < tmax){
591
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
592
        int i = -1;
593

    
594
        url_fseek (bc, p, SEEK_SET);
595

    
596
        while (!ogg_read_page (s, &i)){
597
            if (i == stream_index && ogg->streams[i].granule != 0 &&
598
                ogg->streams[i].granule != -1)
599
                break;
600
        }
601

    
602
        if (i == -1)
603
            break;
604

    
605
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
606
        p = url_ftell (bc);
607

    
608
        if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den)
609
            break;
610

    
611
        if (pts > target_ts){
612
            if (max == p && tmax == pts) {
613
                // probably our tmin is wrong, causing us to always end up too late in the file
614
                tmin = (target_ts + tmin + 1) / 2;
615
                if (tmin == target_ts) {
616
                    url_fseek(bc, min, SEEK_SET);
617
                    break;
618
                }
619
            }
620
            max = p;
621
            tmax = pts;
622
        }else{
623
            if (min == p && tmin == pts) {
624
                // probably our tmax is wrong, causing us to always end up too early in the file
625
                tmax = (target_ts + tmax) / 2;
626
                if (tmax == target_ts) {
627
                    url_fseek(bc, max, SEEK_SET);
628
                    break;
629
                }
630
            }
631
            min = p;
632
            tmin = pts;
633
        }
634
    }
635

    
636
    if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den){
637
        ogg_restore (s, 1);
638
        ogg_reset (ogg);
639
    }else{
640
        ogg_restore (s, 0);
641
        pts = AV_NOPTS_VALUE;
642
    }
643

    
644
    av_update_cur_dts(s, st, pts);
645
    return 0;
646

    
647
#if 0
648
    //later...
649
    int64_t pos;
650
    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
651
        return -1;
652
    pos = url_ftell (&s->pb);
653
    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
654
#endif
655

    
656
}
657

    
658
#if 0
659
static int64_t
660
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
661
                    int64_t pos_limit)
662
{
663
    ogg_t *ogg = s->priv_data;
664
    ByteIOContext *bc = &s->pb;
665
    int64_t pos, pts;
666

667
    if (*pos_arg < 0)
668
        return AV_NOPTS_VALUE;
669

670
    pos = *pos_arg;
671
}
672
#endif
673

    
674
static int ogg_probe(AVProbeData *p)
675
{
676
    if (p->buf_size < 6)
677
        return 0;
678
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
679
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
680
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
681
        return AVPROBE_SCORE_MAX;
682
    else
683
        return 0;
684
}
685

    
686
AVInputFormat ogg_demuxer = {
687
    "ogg",
688
    "Ogg",
689
    sizeof (ogg_t),
690
    ogg_probe,
691
    ogg_read_header,
692
    ogg_read_packet,
693
    ogg_read_close,
694
    ogg_read_seek,
695
// ogg_read_timestamp,
696
    .extensions = "ogg",
697
};