Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 0a5790d1

History | View | Annotate | Download (15.5 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 format",
71
    "application/ogg",
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
    ost->nstreams = ogg->nstreams;
94
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
95

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

    
103
    ogg->state = ost;
104

    
105
    return 0;
106
}
107

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

    
116
    if (!ost)
117
        return 0;
118

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

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

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

    
132
    av_free (ost);
133

    
134
    return 0;
135
}
136

    
137
static int
138
ogg_reset (ogg_t * ogg)
139
{
140
    int i;
141

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

    
153
    ogg->curidx = -1;
154

    
155
    return 0;
156
}
157

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

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

    
168
    return NULL;
169
}
170

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

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

    
180
    return -1;
181
}
182

    
183
static int
184
ogg_new_stream (AVFormatContext * s, uint32_t serial)
185
{
186

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

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

    
201
    st = av_new_stream (s, idx);
202
    if (!st)
203
        return AVERROR(ENOMEM);
204

    
205
    av_set_pts_info(st, 64, 1, 1000000);
206

    
207
    return idx;
208
}
209

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

    
224
    return 0;
225
}
226

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

    
243
    if (get_buffer (bc, sync, 4) < 4)
244
        return -1;
245

    
246
    do{
247
        int c;
248

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

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

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

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

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

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

    
282
    os = ogg->streams + idx;
283

    
284
    if(os->psize > 0)
285
        ogg_new_buf(ogg, idx);
286

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

    
290
    os->nsegs = nsegs;
291
    os->segp = 0;
292

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

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

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

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

    
320
    os->lastgp = os->granule;
321
    os->bufpos += size;
322
    os->granule = gp;
323
    os->flags = flags;
324

    
325
    if (str)
326
        *str = idx;
327

    
328
    return 0;
329
}
330

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

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

    
344
    do{
345
        idx = ogg->curidx;
346

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

    
352
        os = ogg->streams + idx;
353

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

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

    
372
        segp = os->segp;
373
        psize = os->psize;
374

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

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

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

    
395
    ogg->curidx = idx;
396

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

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

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

    
427
    return 0;
428
}
429

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

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

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

    
444
    return 0;
445
}
446

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

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

    
460
    return pts;
461
}
462

    
463

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

    
471
    if(s->pb.is_streamed)
472
        return 0;
473

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

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

    
483
    ogg_save (s);
484
    url_fseek (&s->pb, end, SEEK_SET);
485

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

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

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

    
510
    return 0;
511
}
512

    
513

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

    
524
    //linear granulepos seek from end
525
    ogg_get_length (s);
526

    
527
    //fill the extradata in the per codec callbacks
528
    return 0;
529
}
530

    
531

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

    
540
    //Get an ogg packet
541
    do{
542
        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
543
            return AVERROR(EIO);
544
    }while (idx < 0 || !s->streams[idx]);
545

    
546
    ogg = s->priv_data;
547
    os = ogg->streams + idx;
548

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

    
559
    return psize;
560
}
561

    
562

    
563
static int
564
ogg_read_close (AVFormatContext * s)
565
{
566
    ogg_t *ogg = s->priv_data;
567
    int i;
568

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

    
577

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

    
589
    ogg_save (s);
590

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

    
597
        url_fseek (bc, p, SEEK_SET);
598

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

    
605
        if (i == -1)
606
            break;
607

    
608
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
609
        p = url_ftell (bc);
610

    
611
        if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den)
612
            break;
613

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

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

    
647
    av_update_cur_dts(s, st, pts);
648
    return 0;
649

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

    
659
}
660

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

670
    if (*pos_arg < 0)
671
        return AV_NOPTS_VALUE;
672

673
    pos = *pos_arg;
674
}
675
#endif
676

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

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