Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ a5e9102b

History | View | Annotate | Download (14.2 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
static AVOutputFormat ogg_oformat = {
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
    memset (os->buf, 0, os->bufsize);
198
    os->header = -1;
199

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

    
204
    av_set_pts_info(st, 64, 1, 1000000);
205
    st->start_time = 0;
206

    
207
    return idx;
208
}
209

    
210
static int
211
ogg_read_page (AVFormatContext * s, int *str)
212
{
213
    ByteIOContext *bc = &s->pb;
214
    ogg_t *ogg = s->priv_data;
215
    ogg_stream_t *os;
216
    int i = 0;
217
    int flags, nsegs;
218
    uint64_t gp;
219
    uint32_t serial;
220
    uint32_t seq;
221
    uint32_t crc;
222
    int size, idx;
223
    char sync[4];
224
    int sp = 0;
225

    
226
    if (get_buffer (bc, sync, 4) < 4)
227
        return -1;
228

    
229
    do{
230
        int c;
231

    
232
        if (sync[sp & 3] == 'O' &&
233
            sync[(sp + 1) & 3] == 'g' &&
234
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
235
            break;
236

    
237
        c = url_fgetc (bc);
238
        if (c < 0)
239
            return -1;
240
        sync[sp++ & 3] = c;
241
    }while (i++ < MAX_PAGE_SIZE);
242

    
243
    if (i >= MAX_PAGE_SIZE){
244
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
245
        return -1;
246
    }
247

    
248
    if (url_fgetc (bc) != 0)      /* version */
249
        return -1;
250

    
251
    flags = url_fgetc (bc);
252
    gp = get_le64 (bc);
253
    serial = get_le32 (bc);
254
    seq = get_le32 (bc);
255
    crc = get_le32 (bc);
256
    nsegs = url_fgetc (bc);
257

    
258
    idx = ogg_find_stream (ogg, serial);
259
    if (idx < 0){
260
        idx = ogg_new_stream (s, serial);
261
        if (idx < 0)
262
            return -1;
263
    }
264

    
265
    os = ogg->streams + idx;
266

    
267
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
268
        return -1;
269

    
270
    os->nsegs = nsegs;
271
    os->segp = 0;
272

    
273
    size = 0;
274
    for (i = 0; i < nsegs; i++)
275
        size += os->segments[i];
276

    
277
    if (flags & OGG_FLAG_CONT){
278
        if (!os->psize){
279
            while (os->segp < os->nsegs){
280
                int seg = os->segments[os->segp++];
281
                os->pstart += seg;
282
                if (seg < 255)
283
                  break;
284
            }
285
        }
286
    }else{
287
      os->psize = 0;
288
    }
289

    
290
    if (os->bufsize - os->bufpos < size){
291
        uint8_t *nb = av_malloc (os->bufsize *= 2);
292
        memset (nb, 0, os->bufsize);
293
        memcpy (nb, os->buf, os->bufpos);
294
        av_free (os->buf);
295
        os->buf = nb;
296
    }
297

    
298
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
299
        return -1;
300

    
301
    os->lastgp = os->granule;
302
    os->bufpos += size;
303
    os->granule = gp;
304
    os->flags = flags;
305

    
306
    if (str)
307
        *str = idx;
308

    
309
    return 0;
310
}
311

    
312
static int
313
ogg_packet (AVFormatContext * s, int *str)
314
{
315
    ogg_t *ogg = s->priv_data;
316
    int idx;
317
    ogg_stream_t *os;
318
    int complete = 0;
319
    int segp = 0, psize = 0;
320

    
321
#if 0
322
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
323
#endif
324

    
325
    do{
326
        idx = ogg->curidx;
327

    
328
        while (idx < 0){
329
            if (ogg_read_page (s, &idx) < 0)
330
                return -1;
331
        }
332

    
333
        os = ogg->streams + idx;
334

    
335
#if 0
336
        av_log (s, AV_LOG_DEBUG,
337
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
338
                idx, os->pstart, os->psize, os->segp, os->nsegs);
339
#endif
340

    
341
        if (!os->codec){
342
            if (os->header < 0){
343
                os->codec = ogg_find_codec (os->buf, os->bufpos);
344
                if (!os->codec){
345
                    os->header = 0;
346
                    return 0;
347
                }
348
            }else{
349
                return 0;
350
            }
351
        }
352

    
353
        segp = os->segp;
354
        psize = os->psize;
355

    
356
        while (os->segp < os->nsegs){
357
            int ss = os->segments[os->segp++];
358
            os->psize += ss;
359
            if (ss < 255){
360
                complete = 1;
361
                break;
362
            }
363
        }
364

    
365
        if (!complete && os->segp == os->nsegs){
366
            uint8_t *nb = av_malloc (os->bufsize);
367
            int size = os->bufpos - os->pstart;
368
            memset (nb, 0, os->bufsize);
369
            memcpy (nb, os->buf + os->pstart, size);
370
            av_free (os->buf);
371
            os->buf = nb;
372
            os->bufpos = size;
373
            os->pstart = 0;
374
            ogg->curidx = -1;
375
        }
376
    }while (!complete);
377

    
378
#if 0
379
    av_log (s, AV_LOG_DEBUG,
380
            "ogg_packet: idx %i, frame size %i, start %i\n",
381
            idx, os->psize, os->pstart);
382
#endif
383

    
384
    ogg->curidx = idx;
385

    
386
    if (os->header < 0){
387
        int hdr = os->codec->header (s, idx);
388
        if (!hdr){
389
          os->header = os->seq;
390
          os->segp = segp;
391
          os->psize = psize;
392
          ogg->headers = 1;
393
        }else{
394
          os->pstart += os->psize;
395
          os->psize = 0;
396
        }
397
    }
398

    
399
    if (os->header > -1 && os->seq > os->header){
400
        if (os->codec && os->codec->packet)
401
            os->codec->packet (s, idx);
402
        if (str)
403
            *str = idx;
404
    }
405

    
406
    os->seq++;
407
    if (os->segp == os->nsegs)
408
        ogg->curidx = -1;
409

    
410
    return 0;
411
}
412

    
413
static int
414
ogg_get_headers (AVFormatContext * s)
415
{
416
    ogg_t *ogg = s->priv_data;
417

    
418
    do{
419
        if (ogg_packet (s, NULL) < 0)
420
            return -1;
421
    }while (!ogg->headers);
422

    
423
#if 0
424
    av_log (s, AV_LOG_DEBUG, "found headers\n");
425
#endif
426

    
427
    return 0;
428
}
429

    
430
static uint64_t
431
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
432
{
433
    ogg_t *ogg = s->priv_data;
434
    ogg_stream_t *os = ogg->streams + i;
435
    uint64_t pts = AV_NOPTS_VALUE;
436

    
437
    if(os->codec->gptopts){
438
        pts = os->codec->gptopts(s, i, gp);
439
    } else {
440
        pts = gp;
441
    }
442

    
443
    return pts;
444
}
445

    
446

    
447
static int
448
ogg_get_length (AVFormatContext * s)
449
{
450
    ogg_t *ogg = s->priv_data;
451
    int idx = -1, i;
452
    offset_t size, end;
453

    
454
    if(s->pb.is_streamed)
455
        return 0;
456

    
457
// already set
458
    if (s->duration != AV_NOPTS_VALUE)
459
        return 0;
460

    
461
    size = url_fsize(&s->pb);
462
    if(size < 0)
463
        return 0;
464
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
465

    
466
    ogg_save (s);
467
    url_fseek (&s->pb, end, SEEK_SET);
468

    
469
    while (!ogg_read_page (s, &i)){
470
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
471
            idx = i;
472
    }
473

    
474
    if (idx != -1){
475
        s->streams[idx]->duration =
476
            ogg_gptopts (s, idx, ogg->streams[idx].granule);
477
    }
478

    
479
    ogg->size = size;
480
    ogg_restore (s, 0);
481

    
482
    return 0;
483
}
484

    
485

    
486
static int
487
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
488
{
489
    ogg_t *ogg = s->priv_data;
490
    ogg->curidx = -1;
491
    //linear headers seek from start
492
    if (ogg_get_headers (s) < 0){
493
      return -1;
494
    }
495

    
496
    //linear granulepos seek from end
497
    ogg_get_length (s);
498

    
499
    //fill the extradata in the per codec callbacks
500
    return 0;
501
}
502

    
503

    
504
static int
505
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
506
{
507
    ogg_t *ogg;
508
    ogg_stream_t *os;
509
    int idx = -1;
510

    
511
    //Get an ogg packet
512
    do{
513
        if (ogg_packet (s, &idx) < 0)
514
            return AVERROR_IO;
515
    }while (idx < 0 || !s->streams[idx]);
516

    
517
    ogg = s->priv_data;
518
    os = ogg->streams + idx;
519

    
520
    //Alloc a pkt
521
    if (av_new_packet (pkt, os->psize) < 0)
522
        return AVERROR_IO;
523
    pkt->stream_index = idx;
524
    memcpy (pkt->data, os->buf + os->pstart, os->psize);
525
    if (os->lastgp != -1LL){
526
        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
527
        os->lastgp = -1;
528
    }
529
    //next
530
    os->pstart += os->psize;
531
    os->psize = 0;
532
    return os->psize;
533
}
534

    
535

    
536
static int
537
ogg_read_close (AVFormatContext * s)
538
{
539
    ogg_t *ogg = s->priv_data;
540
    int i;
541

    
542
    for (i = 0; i < ogg->nstreams; i++){
543
        av_free (ogg->streams[i].buf);
544
        av_free (ogg->streams[i].private);
545
    }
546
    av_free (ogg->streams);
547
    return 0;
548
}
549

    
550

    
551
static int
552
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
553
               int flags)
554
{
555
    AVStream *st = s->streams[stream_index];
556
    ogg_t *ogg = s->priv_data;
557
    ByteIOContext *bc = &s->pb;
558
    uint64_t min = 0, max = ogg->size;
559
    uint64_t tmin = 0, tmax = st->duration;
560
    int64_t pts = AV_NOPTS_VALUE;
561

    
562
    ogg_save (s);
563

    
564
    while (min <= max){
565
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
566
        int i = -1;
567

    
568
        url_fseek (bc, p, SEEK_SET);
569

    
570
        while (!ogg_read_page (s, &i)){
571
            if (i == stream_index && ogg->streams[i].granule != 0 &&
572
                ogg->streams[i].granule != -1)
573
                break;
574
        }
575

    
576
        if (i == -1)
577
            break;
578

    
579
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
580
        p = url_ftell (bc);
581

    
582
        if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
583
            break;
584

    
585
        if (pts > target_ts){
586
            max = p;
587
            tmax = pts;
588
        }else{
589
            min = p;
590
            tmin = pts;
591
        }
592
    }
593

    
594
    if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
595
        ogg_restore (s, 1);
596
        ogg_reset (ogg);
597
    }else{
598
        ogg_restore (s, 0);
599
        pts = AV_NOPTS_VALUE;
600
    }
601

    
602
    return pts;
603

    
604
#if 0
605
    //later...
606
    int64_t pos;
607
    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
608
        return -1;
609
    pos = url_ftell (&s->pb);
610
    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
611
#endif
612

    
613
}
614

    
615
#if 0
616
static int64_t
617
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
618
                    int64_t pos_limit)
619
{
620
    ogg_t *ogg = s->priv_data;
621
    ByteIOContext *bc = &s->pb;
622
    int64_t pos, pts;
623

624
    if (*pos_arg < 0)
625
        return AV_NOPTS_VALUE;
626

627
    pos = *pos_arg;
628
}
629
#endif
630

    
631
static int ogg_probe(AVProbeData *p)
632
{
633
    if (p->buf_size < 6)
634
        return 0;
635
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
636
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
637
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
638
        return AVPROBE_SCORE_MAX;
639
    else
640
        return 0;
641
}
642

    
643
static AVInputFormat ogg_iformat = {
644
    "ogg",
645
    "Ogg",
646
    sizeof (ogg_t),
647
    ogg_probe,
648
    ogg_read_header,
649
    ogg_read_packet,
650
    ogg_read_close,
651
    ogg_read_seek,
652
// ogg_read_timestamp,
653
    .extensions = "ogg",
654
};
655

    
656
int
657
ogg_init (void)
658
{
659
#if 0 // CONFIG_MUXERS
660
    av_register_output_format (&ogg_oformat);
661
#endif
662
    av_register_input_format (&ogg_iformat);
663
    return 0;
664
}