2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
9 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
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:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
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.
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 static ogg_codec_t *ogg_codecs[] = {
47 #if 0 // CONFIG_MUXERS
49 ogg_write_header (AVFormatContext * avfcontext)
54 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
60 ogg_write_trailer (AVFormatContext * avfcontext)
65 static AVOutputFormat ogg_oformat = {
77 #endif //CONFIG_MUXERS
79 //FIXME We could avoid some structure duplication
81 ogg_save (AVFormatContext * s)
83 ogg_t *ogg = s->priv_data;
85 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
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));
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);
105 ogg_restore (AVFormatContext * s, int discard)
107 ogg_t *ogg = s->priv_data;
108 ByteIOContext *bc = &s->pb;
109 ogg_state_t *ost = ogg->state;
115 ogg->state = ost->next;
118 for (i = 0; i < ogg->nstreams; i++)
119 av_free (ogg->streams[i].buf);
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));
133 ogg_reset (ogg_t * ogg)
137 for (i = 0; i < ogg->nstreams; i++){
138 ogg_stream_t *os = ogg->streams + i;
154 ogg_find_codec (uint8_t * buf, int size)
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];
167 ogg_find_stream (ogg_t * ogg, int serial)
171 for (i = 0; i < ogg->nstreams; i++)
172 if (ogg->streams[i].serial == serial)
179 ogg_new_stream (AVFormatContext * s, uint32_t serial)
182 ogg_t *ogg = s->priv_data;
183 int idx = ogg->nstreams++;
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;
192 os->bufsize = DECODER_BUFFER_SIZE;
193 os->buf = av_malloc (os->bufsize);
194 memset (os->buf, 0, os->bufsize);
197 st = av_new_stream (s, idx);
199 return AVERROR_NOMEM;
201 av_set_pts_info(st, 64, 1, 1000000);
208 ogg_read_page (AVFormatContext * s, int *str)
210 ByteIOContext *bc = &s->pb;
211 ogg_t *ogg = s->priv_data;
223 if (get_buffer (bc, sync, 4) < 4)
229 if (sync[sp & 3] == 'O' &&
230 sync[(sp + 1) & 3] == 'g' &&
231 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
238 }while (i++ < MAX_PAGE_SIZE);
240 if (i >= MAX_PAGE_SIZE){
241 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
245 if (url_fgetc (bc) != 0) /* version */
248 flags = url_fgetc (bc);
250 serial = get_le32 (bc);
253 nsegs = url_fgetc (bc);
255 idx = ogg_find_stream (ogg, serial);
257 idx = ogg_new_stream (s, serial);
262 os = ogg->streams + idx;
264 if (get_buffer (bc, os->segments, nsegs) < nsegs)
271 for (i = 0; i < nsegs; i++)
272 size += os->segments[i];
274 if (flags & OGG_FLAG_CONT){
276 while (os->segp < os->nsegs){
277 int seg = os->segments[os->segp++];
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);
295 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
298 os->lastgp = os->granule;
310 ogg_packet (AVFormatContext * s, int *str)
312 ogg_t *ogg = s->priv_data;
316 int segp = 0, psize = 0;
319 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
326 if (ogg_read_page (s, &idx) < 0)
330 os = ogg->streams + idx;
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);
340 os->codec = ogg_find_codec (os->buf, os->bufpos);
353 while (os->segp < os->nsegs){
354 int ss = os->segments[os->segp++];
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);
376 av_log (s, AV_LOG_DEBUG,
377 "ogg_packet: idx %i, frame size %i, start %i\n",
378 idx, os->psize, os->pstart);
384 int hdr = os->codec->header (s, idx);
386 os->header = os->seq;
391 os->pstart += os->psize;
396 if (os->header > -1 && os->seq > os->header){
397 if (os->codec && os->codec->packet)
398 os->codec->packet (s, idx);
404 if (os->segp == os->nsegs)
411 ogg_get_headers (AVFormatContext * s)
413 ogg_t *ogg = s->priv_data;
416 if (ogg_packet (s, NULL) < 0)
418 }while (!ogg->headers);
421 av_log (s, AV_LOG_DEBUG, "found headers\n");
428 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
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;
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){
449 ogg_get_length (AVFormatContext * s)
451 ogg_t *ogg = s->priv_data;
454 if(s->pb.is_streamed)
458 if (s->duration != AV_NOPTS_VALUE)
462 url_fseek (&s->pb, -MAX_PAGE_SIZE, SEEK_END);
464 while (!ogg_read_page (s, &i)){
465 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
470 s->streams[idx]->duration =
471 ogg_gptopts (s, idx, ogg->streams[idx].granule);
474 ogg->size = url_fsize(&s->pb);
482 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
484 ogg_t *ogg = s->priv_data;
486 //linear headers seek from start
487 if (ogg_get_headers (s) < 0){
491 //linear granulepos seek from end
494 //fill the extradata in the per codec callbacks
500 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
508 if (ogg_packet (s, &idx) < 0)
510 }while (idx < 0 || !s->streams[idx]);
513 os = ogg->streams + idx;
516 if (av_new_packet (pkt, os->psize) < 0)
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);
525 os->pstart += os->psize;
532 ogg_read_close (AVFormatContext * s)
534 ogg_t *ogg = s->priv_data;
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);
542 av_free (ogg->streams);
548 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
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;
560 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
563 url_fseek (bc, p, SEEK_SET);
565 while (!ogg_read_page (s, &i)){
566 if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1)
573 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
576 if (ABS (pts - target_ts) < 1000000LL)
579 if (pts > target_ts){
588 if (ABS (pts - target_ts) < 1000000LL){
593 pts = AV_NOPTS_VALUE;
601 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
603 pos = url_ftell (&s->pb);
604 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
611 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
614 ogg_t *ogg = s->priv_data;
615 ByteIOContext *bc = &s->pb;
619 return AV_NOPTS_VALUE;
625 static int ogg_probe(AVProbeData *p)
629 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
630 p->buf[2] == 'g' && p->buf[3] == 'S' &&
631 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
632 return AVPROBE_SCORE_MAX;
637 static AVInputFormat ogg_iformat = {
646 // ogg_read_timestamp,
653 #if 0 // CONFIG_MUXERS
654 av_register_output_format (&ogg_oformat);
656 av_register_input_format (&ogg_iformat);