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[] = {
51 #if 0 // CONFIG_MUXERS
53 ogg_write_header (AVFormatContext * avfcontext)
58 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
64 ogg_write_trailer (AVFormatContext * avfcontext)
69 AVOutputFormat ogg_muxer = {
81 #endif //CONFIG_MUXERS
83 //FIXME We could avoid some structure duplication
85 ogg_save (AVFormatContext * s)
87 ogg_t *ogg = s->priv_data;
89 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
91 ost->pos = url_ftell (&s->pb);;
92 ost->curidx = ogg->curidx;
93 ost->next = ogg->state;
94 ost->nstreams = ogg->nstreams;
95 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
97 for (i = 0; i < ogg->nstreams; i++){
98 ogg_stream_t *os = ogg->streams + i;
99 os->buf = av_malloc (os->bufsize);
100 memset (os->buf, 0, os->bufsize);
101 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
110 ogg_restore (AVFormatContext * s, int discard)
112 ogg_t *ogg = s->priv_data;
113 ByteIOContext *bc = &s->pb;
114 ogg_state_t *ost = ogg->state;
120 ogg->state = ost->next;
123 for (i = 0; i < ogg->nstreams; i++)
124 av_free (ogg->streams[i].buf);
126 url_fseek (bc, ost->pos, SEEK_SET);
127 ogg->curidx = ost->curidx;
128 ogg->nstreams = ost->nstreams;
129 memcpy(ogg->streams, ost->streams,
130 ost->nstreams * sizeof(*ogg->streams));
139 ogg_reset (ogg_t * ogg)
143 for (i = 0; i < ogg->nstreams; i++){
144 ogg_stream_t *os = ogg->streams + i;
160 ogg_find_codec (uint8_t * buf, int size)
164 for (i = 0; ogg_codecs[i]; i++)
165 if (size >= ogg_codecs[i]->magicsize &&
166 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
167 return ogg_codecs[i];
173 ogg_find_stream (ogg_t * ogg, int serial)
177 for (i = 0; i < ogg->nstreams; i++)
178 if (ogg->streams[i].serial == serial)
185 ogg_new_stream (AVFormatContext * s, uint32_t serial)
188 ogg_t *ogg = s->priv_data;
189 int idx = ogg->nstreams++;
193 ogg->streams = av_realloc (ogg->streams,
194 ogg->nstreams * sizeof (*ogg->streams));
195 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
196 os = ogg->streams + idx;
198 os->bufsize = DECODER_BUFFER_SIZE;
199 os->buf = av_malloc(os->bufsize);
202 st = av_new_stream (s, idx);
204 return AVERROR(ENOMEM);
206 av_set_pts_info(st, 64, 1, 1000000);
212 ogg_new_buf(ogg_t *ogg, int idx)
214 ogg_stream_t *os = ogg->streams + idx;
215 uint8_t *nb = av_malloc(os->bufsize);
216 int size = os->bufpos - os->pstart;
218 memcpy(nb, os->buf + os->pstart, size);
229 ogg_read_page (AVFormatContext * s, int *str)
231 ByteIOContext *bc = &s->pb;
232 ogg_t *ogg = s->priv_data;
244 if (get_buffer (bc, sync, 4) < 4)
250 if (sync[sp & 3] == 'O' &&
251 sync[(sp + 1) & 3] == 'g' &&
252 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
259 }while (i++ < MAX_PAGE_SIZE);
261 if (i >= MAX_PAGE_SIZE){
262 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
266 if (url_fgetc (bc) != 0) /* version */
269 flags = url_fgetc (bc);
271 serial = get_le32 (bc);
274 nsegs = url_fgetc (bc);
276 idx = ogg_find_stream (ogg, serial);
278 idx = ogg_new_stream (s, serial);
283 os = ogg->streams + idx;
286 ogg_new_buf(ogg, idx);
288 if (get_buffer (bc, os->segments, nsegs) < nsegs)
295 for (i = 0; i < nsegs; i++)
296 size += os->segments[i];
298 if (flags & OGG_FLAG_CONT){
300 while (os->segp < os->nsegs){
301 int seg = os->segments[os->segp++];
311 if (os->bufsize - os->bufpos < size){
312 uint8_t *nb = av_malloc (os->bufsize *= 2);
313 memcpy (nb, os->buf, os->bufpos);
318 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
321 os->lastgp = os->granule;
333 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
335 ogg_t *ogg = s->priv_data;
339 int segp = 0, psize = 0;
342 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
349 if (ogg_read_page (s, &idx) < 0)
353 os = ogg->streams + idx;
356 av_log (s, AV_LOG_DEBUG,
357 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
358 idx, os->pstart, os->psize, os->segp, os->nsegs);
363 os->codec = ogg_find_codec (os->buf, os->bufpos);
376 while (os->segp < os->nsegs){
377 int ss = os->segments[os->segp++];
385 if (!complete && os->segp == os->nsegs){
391 av_log (s, AV_LOG_DEBUG,
392 "ogg_packet: idx %i, frame size %i, start %i\n",
393 idx, os->psize, os->pstart);
399 int hdr = os->codec->header (s, idx);
401 os->header = os->seq;
406 os->pstart += os->psize;
411 if (os->header > -1 && os->seq > os->header){
412 if (os->codec && os->codec->packet)
413 os->codec->packet (s, idx);
417 *dstart = os->pstart;
420 os->pstart += os->psize;
425 if (os->segp == os->nsegs)
432 ogg_get_headers (AVFormatContext * s)
434 ogg_t *ogg = s->priv_data;
437 if (ogg_packet (s, NULL, NULL, NULL) < 0)
439 }while (!ogg->headers);
442 av_log (s, AV_LOG_DEBUG, "found headers\n");
449 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
451 ogg_t *ogg = s->priv_data;
452 ogg_stream_t *os = ogg->streams + i;
453 uint64_t pts = AV_NOPTS_VALUE;
455 if(os->codec->gptopts){
456 pts = os->codec->gptopts(s, i, gp);
466 ogg_get_length (AVFormatContext * s)
468 ogg_t *ogg = s->priv_data;
472 if(s->pb.is_streamed)
476 if (s->duration != AV_NOPTS_VALUE)
479 size = url_fsize(&s->pb);
482 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
485 url_fseek (&s->pb, end, SEEK_SET);
487 while (!ogg_read_page (s, &i)){
488 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
489 ogg->streams[i].codec)
494 s->streams[idx]->duration =
495 ogg_gptopts (s, idx, ogg->streams[idx].granule);
501 while (!ogg_read_page (s, &i)) {
502 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
506 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
507 s->streams[idx]->duration -= s->streams[idx]->start_time;
516 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
518 ogg_t *ogg = s->priv_data;
520 //linear headers seek from start
521 if (ogg_get_headers (s) < 0){
525 //linear granulepos seek from end
528 //fill the extradata in the per codec callbacks
534 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
543 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
545 }while (idx < 0 || !s->streams[idx]);
548 os = ogg->streams + idx;
551 if (av_new_packet (pkt, psize) < 0)
553 pkt->stream_index = idx;
554 memcpy (pkt->data, os->buf + pstart, psize);
555 if (os->lastgp != -1LL){
556 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
565 ogg_read_close (AVFormatContext * s)
567 ogg_t *ogg = s->priv_data;
570 for (i = 0; i < ogg->nstreams; i++){
571 av_free (ogg->streams[i].buf);
572 av_free (ogg->streams[i].private);
574 av_free (ogg->streams);
580 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
583 ogg_t *ogg = s->priv_data;
584 ByteIOContext *bc = &s->pb;
585 int64_t pts = AV_NOPTS_VALUE;
587 url_fseek(bc, *pos_arg, SEEK_SET);
588 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
589 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
590 ogg->streams[i].codec && i == stream_index) {
591 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
592 // FIXME: this is the position of the packet after the one with above
594 *pos_arg = url_ftell(bc);
602 static int ogg_probe(AVProbeData *p)
604 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
605 p->buf[2] == 'g' && p->buf[3] == 'S' &&
606 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
607 return AVPROBE_SCORE_MAX;
612 AVInputFormat ogg_demuxer = {