Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 25f8db58

History | View | Annotate | Download (13.9 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
    NULL
45
};
46

    
47
#if 0                           // CONFIG_MUXERS
48
static int
49
ogg_write_header (AVFormatContext * avfcontext)
50
{
51
}
52

53
static int
54
ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
55
{
56
}
57

58

59
static int
60
ogg_write_trailer (AVFormatContext * avfcontext)
61
{
62
}
63

64

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

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

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

    
99
    ogg->state = ost;
100

    
101
    return 0;
102
}
103

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

    
112
    if (!ost)
113
        return 0;
114

    
115
    ogg->state = ost->next;
116

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

    
121
        url_fseek (bc, ost->pos, SEEK_SET);
122
        ogg->curidx = ost->curidx;
123
        memcpy (ogg->streams, ost->streams,
124
        ogg->nstreams * sizeof (*ogg->streams));
125
    }
126

    
127
    av_free (ost);
128

    
129
    return 0;
130
}
131

    
132
static int
133
ogg_reset (ogg_t * ogg)
134
{
135
    int i;
136

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

    
148
    ogg->curidx = -1;
149

    
150
    return 0;
151
}
152

    
153
static ogg_codec_t *
154
ogg_find_codec (uint8_t * buf, int size)
155
{
156
    int i;
157

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

    
163
    return NULL;
164
}
165

    
166
static int
167
ogg_find_stream (ogg_t * ogg, int serial)
168
{
169
    int i;
170

    
171
    for (i = 0; i < ogg->nstreams; i++)
172
        if (ogg->streams[i].serial == serial)
173
            return i;
174

    
175
    return -1;
176
}
177

    
178
static int
179
ogg_new_stream (AVFormatContext * s, uint32_t serial)
180
{
181

    
182
    ogg_t *ogg = s->priv_data;
183
    int idx = ogg->nstreams++;
184
    AVStream *st;
185
    ogg_stream_t *os;
186

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

    
197
    st = av_new_stream (s, idx);
198
    if (!st)
199
        return AVERROR_NOMEM;
200

    
201
    av_set_pts_info(st, 64, 1, 1000000);
202
    st->start_time = 0;
203

    
204
    return idx;
205
}
206

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

    
223
    if (get_buffer (bc, sync, 4) < 4)
224
        return -1;
225

    
226
    do{
227
        int c;
228

    
229
        if (sync[sp & 3] == 'O' &&
230
            sync[(sp + 1) & 3] == 'g' &&
231
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
232
            break;
233

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

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

    
245
    if (url_fgetc (bc) != 0)      /* version */
246
        return -1;
247

    
248
    flags = url_fgetc (bc);
249
    gp = get_le64 (bc);
250
    serial = get_le32 (bc);
251
    seq = get_le32 (bc);
252
    crc = get_le32 (bc);
253
    nsegs = url_fgetc (bc);
254

    
255
    idx = ogg_find_stream (ogg, serial);
256
    if (idx < 0){
257
        idx = ogg_new_stream (s, serial);
258
        if (idx < 0)
259
            return -1;
260
    }
261

    
262
    os = ogg->streams + idx;
263

    
264
    if (get_buffer (bc, os->segments, nsegs) < nsegs)
265
        return -1;
266

    
267
    os->nsegs = nsegs;
268
    os->segp = 0;
269

    
270
    size = 0;
271
    for (i = 0; i < nsegs; i++)
272
        size += os->segments[i];
273

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

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

    
295
    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
296
        return -1;
297

    
298
    os->lastgp = os->granule;
299
    os->bufpos += size;
300
    os->granule = gp;
301
    os->flags = flags;
302

    
303
    if (str)
304
        *str = idx;
305

    
306
    return 0;
307
}
308

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

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

    
322
    do{
323
        idx = ogg->curidx;
324

    
325
        while (idx < 0){
326
            if (ogg_read_page (s, &idx) < 0)
327
                return -1;
328
        }
329

    
330
        os = ogg->streams + idx;
331

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

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

    
350
        segp = os->segp;
351
        psize = os->psize;
352

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

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

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

    
381
    ogg->curidx = idx;
382

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

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

    
403
    os->seq++;
404
    if (os->segp == os->nsegs)
405
        ogg->curidx = -1;
406

    
407
    return 0;
408
}
409

    
410
static int
411
ogg_get_headers (AVFormatContext * s)
412
{
413
    ogg_t *ogg = s->priv_data;
414

    
415
    do{
416
        if (ogg_packet (s, NULL) < 0)
417
            return -1;
418
    }while (!ogg->headers);
419

    
420
#if 0
421
    av_log (s, AV_LOG_DEBUG, "found headers\n");
422
#endif
423

    
424
    return 0;
425
}
426

    
427
static uint64_t
428
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
429
{
430
    ogg_t *ogg = s->priv_data;
431
    ogg_stream_t *os = ogg->streams + i;
432
    AVStream *st = s->streams[i];
433
    AVCodecContext *codec = st->codec;
434
    uint64_t pts = AV_NOPTS_VALUE;
435

    
436
    if(os->codec->gptopts){
437
        pts = os->codec->gptopts(s, i, gp);
438
    } else if (codec->codec_type == CODEC_TYPE_AUDIO){
439
        pts = gp * 1000000LL / codec->sample_rate;
440
    }else if (codec->codec_type == CODEC_TYPE_VIDEO){
441
        pts = gp;
442
    }
443

    
444
    return pts;
445
}
446

    
447

    
448
static int
449
ogg_get_length (AVFormatContext * s)
450
{
451
    ogg_t *ogg = s->priv_data;
452
    int idx = -1, i;
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
    ogg_save (s);
462
    url_fseek (&s->pb, -MAX_PAGE_SIZE, SEEK_END);
463

    
464
    while (!ogg_read_page (s, &i)){
465
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
466
            idx = i;
467
    }
468

    
469
    if (idx != -1){
470
        s->streams[idx]->duration =
471
            ogg_gptopts (s, idx, ogg->streams[idx].granule);
472
    }
473

    
474
    ogg->size = url_fsize(&s->pb);
475
    ogg_restore (s, 0);
476

    
477
    return 0;
478
}
479

    
480

    
481
static int
482
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
483
{
484
    ogg_t *ogg = s->priv_data;
485
    ogg->curidx = -1;
486
    //linear headers seek from start
487
    if (ogg_get_headers (s) < 0){
488
      return -1;
489
    }
490

    
491
    //linear granulepos seek from end
492
    ogg_get_length (s);
493

    
494
    //fill the extradata in the per codec callbacks
495
    return 0;
496
}
497

    
498

    
499
static int
500
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
501
{
502
    ogg_t *ogg;
503
    ogg_stream_t *os;
504
    int idx = -1;
505

    
506
    //Get an ogg packet 
507
    do{
508
        if (ogg_packet (s, &idx) < 0)
509
            return AVERROR_IO;
510
    }while (idx < 0 || !s->streams[idx]);
511

    
512
    ogg = s->priv_data;
513
    os = ogg->streams + idx;
514

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

    
530

    
531
static int
532
ogg_read_close (AVFormatContext * s)
533
{
534
    ogg_t *ogg = s->priv_data;
535
    int i;
536

    
537
    for (i = 0; i < ogg->nstreams; i++){
538
        av_free (ogg->streams[i].buf);
539
        av_free (ogg->streams[i].private);
540
        av_freep (&s->streams[i]->codec->extradata);
541
    }
542
    av_free (ogg->streams);
543
    return 0;
544
}
545

    
546

    
547
static int
548
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
549
               int flags)
550
{
551
    ogg_t *ogg = s->priv_data;
552
    ByteIOContext *bc = &s->pb;
553
    uint64_t min = 0, max = ogg->size;
554
    uint64_t tmin = 0, tmax = s->duration;
555
    int64_t pts = AV_NOPTS_VALUE;
556

    
557
    ogg_save (s);
558

    
559
    while (min <= max){
560
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
561
        int i = -1;
562

    
563
        url_fseek (bc, p, SEEK_SET);
564

    
565
        while (!ogg_read_page (s, &i)){
566
            if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1)
567
                break;
568
        }
569

    
570
        if (i == -1)
571
            break;
572

    
573
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
574
        p = url_ftell (bc);
575

    
576
        if (ABS (pts - target_ts) < 1000000LL)
577
            break;
578

    
579
        if (pts > target_ts){
580
            max = p;
581
            tmax = pts;
582
        }else{
583
            min = p;
584
            tmin = pts;
585
        }
586
    }
587

    
588
    if (ABS (pts - target_ts) < 1000000LL){
589
        ogg_restore (s, 1);
590
        ogg_reset (ogg);
591
    }else{
592
        ogg_restore (s, 0);
593
        pts = AV_NOPTS_VALUE;
594
    }
595

    
596
    return pts;
597

    
598
#if 0
599
    //later...
600
    int64_t pos;
601
    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
602
        return -1;
603
    pos = url_ftell (&s->pb);
604
    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
605
#endif
606

    
607
}
608

    
609
#if 0
610
static int64_t
611
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
612
                    int64_t pos_limit)
613
{
614
    ogg_t *ogg = s->priv_data;
615
    ByteIOContext *bc = &s->pb;
616
    int64_t pos, pts;
617

618
    if (*pos_arg < 0)
619
        return AV_NOPTS_VALUE;
620

621
    pos = *pos_arg;
622
}
623
#endif
624

    
625
static AVInputFormat ogg_iformat = {
626
    "ogg",
627
    "Ogg",
628
    sizeof (ogg_t),
629
    NULL,
630
    ogg_read_header,
631
    ogg_read_packet,
632
    ogg_read_close,
633
    ogg_read_seek,
634
// ogg_read_timestamp, 
635
    .extensions = "ogg",
636
};
637

    
638
int
639
ogg_init (void)
640
{
641
#if 0 // CONFIG_MUXERS
642
    av_register_output_format (&ogg_oformat);
643
#endif
644
    av_register_input_format (&ogg_iformat);
645
    return 0;
646
}