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[] = {
50 #if 0 // CONFIG_MUXERS
52 ogg_write_header (AVFormatContext * avfcontext)
57 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
63 ogg_write_trailer (AVFormatContext * avfcontext)
68 static AVOutputFormat ogg_muxer = {
80 #endif //CONFIG_MUXERS
82 //FIXME We could avoid some structure duplication
84 ogg_save (AVFormatContext * s)
86 ogg_t *ogg = s->priv_data;
88 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
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));
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);
108 ogg_restore (AVFormatContext * s, int discard)
110 ogg_t *ogg = s->priv_data;
111 ByteIOContext *bc = &s->pb;
112 ogg_state_t *ost = ogg->state;
118 ogg->state = ost->next;
121 for (i = 0; i < ogg->nstreams; i++)
122 av_free (ogg->streams[i].buf);
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));
136 ogg_reset (ogg_t * ogg)
140 for (i = 0; i < ogg->nstreams; i++){
141 ogg_stream_t *os = ogg->streams + i;
157 ogg_find_codec (uint8_t * buf, int size)
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];
170 ogg_find_stream (ogg_t * ogg, int serial)
174 for (i = 0; i < ogg->nstreams; i++)
175 if (ogg->streams[i].serial == serial)
182 ogg_new_stream (AVFormatContext * s, uint32_t serial)
185 ogg_t *ogg = s->priv_data;
186 int idx = ogg->nstreams++;
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;
195 os->bufsize = DECODER_BUFFER_SIZE;
196 os->buf = av_malloc(os->bufsize);
199 st = av_new_stream (s, idx);
201 return AVERROR_NOMEM;
203 av_set_pts_info(st, 64, 1, 1000000);
210 ogg_new_buf(ogg_t *ogg, int idx)
212 ogg_stream_t *os = ogg->streams + idx;
213 uint8_t *nb = av_malloc(os->bufsize);
214 int size = os->bufpos - os->pstart;
216 memcpy(nb, os->buf + os->pstart, size);
227 ogg_read_page (AVFormatContext * s, int *str)
229 ByteIOContext *bc = &s->pb;
230 ogg_t *ogg = s->priv_data;
242 if (get_buffer (bc, sync, 4) < 4)
248 if (sync[sp & 3] == 'O' &&
249 sync[(sp + 1) & 3] == 'g' &&
250 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
257 }while (i++ < MAX_PAGE_SIZE);
259 if (i >= MAX_PAGE_SIZE){
260 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
264 if (url_fgetc (bc) != 0) /* version */
267 flags = url_fgetc (bc);
269 serial = get_le32 (bc);
272 nsegs = url_fgetc (bc);
274 idx = ogg_find_stream (ogg, serial);
276 idx = ogg_new_stream (s, serial);
281 os = ogg->streams + idx;
284 ogg_new_buf(ogg, idx);
286 if (get_buffer (bc, os->segments, nsegs) < nsegs)
293 for (i = 0; i < nsegs; i++)
294 size += os->segments[i];
296 if (flags & OGG_FLAG_CONT){
298 while (os->segp < os->nsegs){
299 int seg = os->segments[os->segp++];
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);
317 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
320 os->lastgp = os->granule;
332 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
334 ogg_t *ogg = s->priv_data;
338 int segp = 0, psize = 0;
341 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
348 if (ogg_read_page (s, &idx) < 0)
352 os = ogg->streams + idx;
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);
362 os->codec = ogg_find_codec (os->buf, os->bufpos);
375 while (os->segp < os->nsegs){
376 int ss = os->segments[os->segp++];
384 if (!complete && os->segp == os->nsegs){
390 av_log (s, AV_LOG_DEBUG,
391 "ogg_packet: idx %i, frame size %i, start %i\n",
392 idx, os->psize, os->pstart);
398 int hdr = os->codec->header (s, idx);
400 os->header = os->seq;
405 os->pstart += os->psize;
410 if (os->header > -1 && os->seq > os->header){
411 if (os->codec && os->codec->packet)
412 os->codec->packet (s, idx);
416 *dstart = os->pstart;
419 os->pstart += os->psize;
424 if (os->segp == os->nsegs)
431 ogg_get_headers (AVFormatContext * s)
433 ogg_t *ogg = s->priv_data;
436 if (ogg_packet (s, NULL, NULL, NULL) < 0)
438 }while (!ogg->headers);
441 av_log (s, AV_LOG_DEBUG, "found headers\n");
448 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
450 ogg_t *ogg = s->priv_data;
451 ogg_stream_t *os = ogg->streams + i;
452 uint64_t pts = AV_NOPTS_VALUE;
454 if(os->codec->gptopts){
455 pts = os->codec->gptopts(s, i, gp);
465 ogg_get_length (AVFormatContext * s)
467 ogg_t *ogg = s->priv_data;
471 if(s->pb.is_streamed)
475 if (s->duration != AV_NOPTS_VALUE)
478 size = url_fsize(&s->pb);
481 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
484 url_fseek (&s->pb, end, SEEK_SET);
486 while (!ogg_read_page (s, &i)){
487 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
492 s->streams[idx]->duration =
493 ogg_gptopts (s, idx, ogg->streams[idx].granule);
504 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
506 ogg_t *ogg = s->priv_data;
508 //linear headers seek from start
509 if (ogg_get_headers (s) < 0){
513 //linear granulepos seek from end
516 //fill the extradata in the per codec callbacks
522 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
531 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
533 }while (idx < 0 || !s->streams[idx]);
536 os = ogg->streams + idx;
539 if (av_new_packet (pkt, psize) < 0)
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);
553 ogg_read_close (AVFormatContext * s)
555 ogg_t *ogg = s->priv_data;
558 for (i = 0; i < ogg->nstreams; i++){
559 av_free (ogg->streams[i].buf);
560 av_free (ogg->streams[i].private);
562 av_free (ogg->streams);
568 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
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;
581 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
584 url_fseek (bc, p, SEEK_SET);
586 while (!ogg_read_page (s, &i)){
587 if (i == stream_index && ogg->streams[i].granule != 0 &&
588 ogg->streams[i].granule != -1)
595 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
598 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
601 if (pts > target_ts){
610 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
615 pts = AV_NOPTS_VALUE;
623 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
625 pos = url_ftell (&s->pb);
626 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
633 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
636 ogg_t *ogg = s->priv_data;
637 ByteIOContext *bc = &s->pb;
641 return AV_NOPTS_VALUE;
647 static int ogg_probe(AVProbeData *p)
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;
659 static AVInputFormat ogg_demuxer = {
668 // ogg_read_timestamp,
675 #if 0 // CONFIG_MUXERS
676 av_register_output_format (&ogg_muxer);
678 av_register_input_format (&ogg_demuxer);