Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 7e33d3fe

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
    &old_flac_codec,
45
    &ogm_video_codec,
46
    &ogm_audio_codec,
47
    &ogm_old_codec,
48
    NULL
49
};
50

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

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

62

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

68

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

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

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

    
104
    ogg->state = ost;
105

    
106
    return 0;
107
}
108

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

    
117
    if (!ost)
118
        return 0;
119

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

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

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

    
133
    av_free (ost);
134

    
135
    return 0;
136
}
137

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

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

    
154
    ogg->curidx = -1;
155

    
156
    return 0;
157
}
158

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

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

    
169
    return NULL;
170
}
171

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

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

    
181
    return -1;
182
}
183

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

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

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

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

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

    
208
    return idx;
209
}
210

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

    
225
    return 0;
226
}
227

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

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

    
247
    do{
248
        int c;
249

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

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

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

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

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

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

    
283
    os = ogg->streams + idx;
284

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

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

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

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

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

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

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

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

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

    
329
    return 0;
330
}
331

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

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

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

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

    
353
        os = ogg->streams + idx;
354

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

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

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

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

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

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

    
396
    ogg->curidx = idx;
397

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

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

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

    
428
    return 0;
429
}
430

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

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

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

    
445
    return 0;
446
}
447

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

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

    
461
    return pts;
462
}
463

    
464

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

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

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

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

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

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

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

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

    
511
    return 0;
512
}
513

    
514

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

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

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

    
532

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

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

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

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

    
560
    return psize;
561
}
562

    
563

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

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

    
578

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

    
590
    ogg_save (s);
591

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

    
598
        url_fseek (bc, p, SEEK_SET);
599

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

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

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

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

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

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

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

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

    
660
}
661

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

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

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

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

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