Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 4b65d88f

History | View | Annotate | Download (14.3 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
    st->start_time = 0;
205

    
206
    return idx;
207
}
208

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

    
223
    return 0;
224
}
225

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

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

    
245
    do{
246
        int c;
247

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

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

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

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

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

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

    
281
    os = ogg->streams + idx;
282

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

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

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

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

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

    
309
    if (os->bufsize - os->bufpos < size){
310
        uint8_t *nb = av_malloc (os->bufsize *= 2);
311
        memset (nb, 0, os->bufsize);
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
            idx = i;
489
    }
490

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

    
496
    ogg->size = size;
497
    ogg_restore (s, 0);
498

    
499
    return 0;
500
}
501

    
502

    
503
static int
504
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
505
{
506
    ogg_t *ogg = s->priv_data;
507
    ogg->curidx = -1;
508
    //linear headers seek from start
509
    if (ogg_get_headers (s) < 0){
510
      return -1;
511
    }
512

    
513
    //linear granulepos seek from end
514
    ogg_get_length (s);
515

    
516
    //fill the extradata in the per codec callbacks
517
    return 0;
518
}
519

    
520

    
521
static int
522
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
523
{
524
    ogg_t *ogg;
525
    ogg_stream_t *os;
526
    int idx = -1;
527
    int pstart, psize;
528

    
529
    //Get an ogg packet
530
    do{
531
        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
532
            return AVERROR_IO;
533
    }while (idx < 0 || !s->streams[idx]);
534

    
535
    ogg = s->priv_data;
536
    os = ogg->streams + idx;
537

    
538
    //Alloc a pkt
539
    if (av_new_packet (pkt, psize) < 0)
540
        return AVERROR_IO;
541
    pkt->stream_index = idx;
542
    memcpy (pkt->data, os->buf + pstart, psize);
543
    if (os->lastgp != -1LL){
544
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
545
        os->lastgp = -1;
546
    }
547

    
548
    return psize;
549
}
550

    
551

    
552
static int
553
ogg_read_close (AVFormatContext * s)
554
{
555
    ogg_t *ogg = s->priv_data;
556
    int i;
557

    
558
    for (i = 0; i < ogg->nstreams; i++){
559
        av_free (ogg->streams[i].buf);
560
        av_free (ogg->streams[i].private);
561
    }
562
    av_free (ogg->streams);
563
    return 0;
564
}
565

    
566

    
567
static int
568
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
569
               int flags)
570
{
571
    AVStream *st = s->streams[stream_index];
572
    ogg_t *ogg = s->priv_data;
573
    ByteIOContext *bc = &s->pb;
574
    uint64_t min = 0, max = ogg->size;
575
    uint64_t tmin = 0, tmax = st->duration;
576
    int64_t pts = AV_NOPTS_VALUE;
577

    
578
    ogg_save (s);
579

    
580
    while (min <= max){
581
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
582
        int i = -1;
583

    
584
        url_fseek (bc, p, SEEK_SET);
585

    
586
        while (!ogg_read_page (s, &i)){
587
            if (i == stream_index && ogg->streams[i].granule != 0 &&
588
                ogg->streams[i].granule != -1)
589
                break;
590
        }
591

    
592
        if (i == -1)
593
            break;
594

    
595
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
596
        p = url_ftell (bc);
597

    
598
        if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
599
            break;
600

    
601
        if (pts > target_ts){
602
            max = p;
603
            tmax = pts;
604
        }else{
605
            min = p;
606
            tmin = pts;
607
        }
608
    }
609

    
610
    if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
611
        ogg_restore (s, 1);
612
        ogg_reset (ogg);
613
    }else{
614
        ogg_restore (s, 0);
615
        pts = AV_NOPTS_VALUE;
616
    }
617

    
618
    return pts;
619

    
620
#if 0
621
    //later...
622
    int64_t pos;
623
    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
624
        return -1;
625
    pos = url_ftell (&s->pb);
626
    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
627
#endif
628

    
629
}
630

    
631
#if 0
632
static int64_t
633
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
634
                    int64_t pos_limit)
635
{
636
    ogg_t *ogg = s->priv_data;
637
    ByteIOContext *bc = &s->pb;
638
    int64_t pos, pts;
639

640
    if (*pos_arg < 0)
641
        return AV_NOPTS_VALUE;
642

643
    pos = *pos_arg;
644
}
645
#endif
646

    
647
static int ogg_probe(AVProbeData *p)
648
{
649
    if (p->buf_size < 6)
650
        return 0;
651
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
652
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
653
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
654
        return AVPROBE_SCORE_MAX;
655
    else
656
        return 0;
657
}
658

    
659
AVInputFormat ogg_demuxer = {
660
    "ogg",
661
    "Ogg",
662
    sizeof (ogg_t),
663
    ogg_probe,
664
    ogg_read_header,
665
    ogg_read_packet,
666
    ogg_read_close,
667
    ogg_read_seek,
668
// ogg_read_timestamp,
669
    .extensions = "ogg",
670
};