Statistics
| Branch: | Revision:

ffmpeg / libavformat / ogg2.c @ 17929c04

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
    NULL
43
};
44

    
45
#if 0                           // CONFIG_ENCODERS
46
static int
47
ogg_write_header (AVFormatContext * avfcontext)
48
{
49
}
50

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

56

57
static int
58
ogg_write_trailer (AVFormatContext * avfcontext)
59
{
60
}
61

62

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

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

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

    
97
    ogg->state = ost;
98

    
99
    return 0;
100
}
101

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

    
110
    if (!ost)
111
        return 0;
112

    
113
    ogg->state = ost->next;
114

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

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

    
125
    av_free (ost);
126

    
127
    return 0;
128
}
129

    
130
static int
131
ogg_reset (ogg_t * ogg)
132
{
133
    int i;
134

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

    
146
    ogg->curidx = -1;
147

    
148
    return 0;
149
}
150

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

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

    
161
    return NULL;
162
}
163

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

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

    
173
    return -1;
174
}
175

    
176
static int
177
ogg_new_stream (AVFormatContext * s, uint32_t serial)
178
{
179

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

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

    
195
    st = av_new_stream (s, idx);
196
    if (!st)
197
        return AVERROR_NOMEM;
198

    
199
    av_set_pts_info(st, 64, 1, 1000000);
200
    st->start_time = 0;
201

    
202
    return idx;
203
}
204

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

    
221
    if (get_buffer (bc, sync, 4) < 4)
222
        return -1;
223

    
224
    do{
225
        int c;
226

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

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

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

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

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

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

    
260
    os = ogg->streams + idx;
261

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

    
265
    os->nsegs = nsegs;
266
    os->segp = 0;
267

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

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

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

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

    
296
    os->lastgp = os->granule;
297
    os->bufpos += size;
298
    os->granule = gp;
299
    os->flags = flags;
300

    
301
    if (str)
302
        *str = idx;
303

    
304
    return 0;
305
}
306

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

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

    
320
    do{
321
        idx = ogg->curidx;
322

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

    
328
        os = ogg->streams + idx;
329

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

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

    
348
        segp = os->segp;
349
        psize = os->psize;
350

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

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

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

    
379
    ogg->curidx = idx;
380

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

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

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

    
405
    return 0;
406
}
407

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

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

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

    
422
    return 0;
423
}
424

    
425
static uint64_t
426
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
427
{
428
    AVStream *st = s->streams[i];
429
    AVCodecContext *codec = &st->codec;
430
    uint64_t pts = AV_NOPTS_VALUE;
431

    
432
    if (codec->codec_type == CODEC_TYPE_AUDIO){
433
        pts = gp * 1000000LL / codec->sample_rate;
434
    }else if (codec->codec_type == CODEC_TYPE_VIDEO){
435
//FIXME
436
        pts = gp * 1000000LL / codec->sample_rate;
437
//  pts = gp * st->video.frame_rate.den * 27000000LL /
438
//      st->video.frame_rate.num;
439
    }
440

    
441
    return pts;
442
}
443

    
444

    
445
static int
446
ogg_get_length (AVFormatContext * s)
447
{
448
    ogg_t *ogg = s->priv_data;
449
    URLContext *h = url_fileno (&s->pb);
450
    int idx = -1, i;
451
//FIXME: get the right ctx flag to know if is seekable or not
452
//    if(ogg->f->flags & URL_FLAG_STREAMED)
453
//  return 0;
454

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

    
459
    ogg_save (s);
460
    url_seek (h, -MAX_PAGE_SIZE, SEEK_END);
461

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

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

    
472
    ogg->size = url_filesize(h);
473
    ogg_restore (s, 0);
474

    
475
    return 0;
476
}
477

    
478

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

    
489
    //linear granulepos seek from end
490
    ogg_get_length (s);
491

    
492
    //fill the extradata in the per codec callbacks
493
    return 0;
494
}
495

    
496

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

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

    
510
    ogg = s->priv_data;
511
    os = ogg->streams + idx;
512

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

    
528

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

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

    
543

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

    
554
    ogg_save (s);
555

    
556
    while (min <= max){
557
        uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
558
        int i = -1;
559

    
560
        url_fseek (bc, p, SEEK_SET);
561

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

    
567
        if (i == -1)
568
            break;
569

    
570
        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
571
        p = url_ftell (bc);
572

    
573
        if (ABS (pts - target_ts) < 1000000LL)
574
            break;
575

    
576
        if (pts > target_ts){
577
            max = p;
578
            tmax = pts;
579
        }else{
580
            min = p;
581
            tmin = pts;
582
        }
583
    }
584

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

    
593
    return pts;
594

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

    
604
}
605

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

615
    if (*pos_arg < 0)
616
        return AV_NOPTS_VALUE;
617

618
    pos = *pos_arg;
619
}
620
#endif
621

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

    
635
int
636
ogg_init (void)
637
{
638
#if 0 // CONFIG_ENCODERS
639
    av_register_output_format (&ogg_oformat);
640
#endif
641
    av_register_input_format (&ogg_iformat);
642
    return 0;
643
}