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[] = {
52 //FIXME We could avoid some structure duplication
54 ogg_save (AVFormatContext * s)
56 ogg_t *ogg = s->priv_data;
58 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
60 ost->pos = url_ftell (s->pb);
61 ost->curidx = ogg->curidx;
62 ost->next = ogg->state;
63 ost->nstreams = ogg->nstreams;
64 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
66 for (i = 0; i < ogg->nstreams; i++){
67 ogg_stream_t *os = ogg->streams + i;
68 os->buf = av_malloc (os->bufsize);
69 memset (os->buf, 0, os->bufsize);
70 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
79 ogg_restore (AVFormatContext * s, int discard)
81 ogg_t *ogg = s->priv_data;
82 ByteIOContext *bc = s->pb;
83 ogg_state_t *ost = ogg->state;
89 ogg->state = ost->next;
92 for (i = 0; i < ogg->nstreams; i++)
93 av_free (ogg->streams[i].buf);
95 url_fseek (bc, ost->pos, SEEK_SET);
96 ogg->curidx = ost->curidx;
97 ogg->nstreams = ost->nstreams;
98 memcpy(ogg->streams, ost->streams,
99 ost->nstreams * sizeof(*ogg->streams));
108 ogg_reset (ogg_t * ogg)
112 for (i = 0; i < ogg->nstreams; i++){
113 ogg_stream_t *os = ogg->streams + i;
129 ogg_find_codec (uint8_t * buf, int size)
133 for (i = 0; ogg_codecs[i]; i++)
134 if (size >= ogg_codecs[i]->magicsize &&
135 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
136 return ogg_codecs[i];
142 ogg_find_stream (ogg_t * ogg, int serial)
146 for (i = 0; i < ogg->nstreams; i++)
147 if (ogg->streams[i].serial == serial)
154 ogg_new_stream (AVFormatContext * s, uint32_t serial)
157 ogg_t *ogg = s->priv_data;
158 int idx = ogg->nstreams++;
162 ogg->streams = av_realloc (ogg->streams,
163 ogg->nstreams * sizeof (*ogg->streams));
164 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
165 os = ogg->streams + idx;
167 os->bufsize = DECODER_BUFFER_SIZE;
168 os->buf = av_malloc(os->bufsize);
171 st = av_new_stream (s, idx);
173 return AVERROR(ENOMEM);
175 av_set_pts_info(st, 64, 1, 1000000);
181 ogg_new_buf(ogg_t *ogg, int idx)
183 ogg_stream_t *os = ogg->streams + idx;
184 uint8_t *nb = av_malloc(os->bufsize);
185 int size = os->bufpos - os->pstart;
187 memcpy(nb, os->buf + os->pstart, size);
198 ogg_read_page (AVFormatContext * s, int *str)
200 ByteIOContext *bc = s->pb;
201 ogg_t *ogg = s->priv_data;
213 if (get_buffer (bc, sync, 4) < 4)
219 if (sync[sp & 3] == 'O' &&
220 sync[(sp + 1) & 3] == 'g' &&
221 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
228 }while (i++ < MAX_PAGE_SIZE);
230 if (i >= MAX_PAGE_SIZE){
231 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
235 if (url_fgetc (bc) != 0) /* version */
238 flags = url_fgetc (bc);
240 serial = get_le32 (bc);
243 nsegs = url_fgetc (bc);
245 idx = ogg_find_stream (ogg, serial);
247 idx = ogg_new_stream (s, serial);
252 os = ogg->streams + idx;
255 ogg_new_buf(ogg, idx);
257 if (get_buffer (bc, os->segments, nsegs) < nsegs)
264 for (i = 0; i < nsegs; i++)
265 size += os->segments[i];
267 if (flags & OGG_FLAG_CONT){
269 while (os->segp < os->nsegs){
270 int seg = os->segments[os->segp++];
280 if (os->bufsize - os->bufpos < size){
281 uint8_t *nb = av_malloc (os->bufsize *= 2);
282 memcpy (nb, os->buf, os->bufpos);
287 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
290 os->lastgp = os->granule;
302 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
304 ogg_t *ogg = s->priv_data;
308 int segp = 0, psize = 0;
311 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
318 if (ogg_read_page (s, &idx) < 0)
322 os = ogg->streams + idx;
325 av_log (s, AV_LOG_DEBUG,
326 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
327 idx, os->pstart, os->psize, os->segp, os->nsegs);
332 os->codec = ogg_find_codec (os->buf, os->bufpos);
345 while (os->segp < os->nsegs){
346 int ss = os->segments[os->segp++];
354 if (!complete && os->segp == os->nsegs){
360 av_log (s, AV_LOG_DEBUG,
361 "ogg_packet: idx %i, frame size %i, start %i\n",
362 idx, os->psize, os->pstart);
368 int hdr = os->codec->header (s, idx);
370 os->header = os->seq;
375 os->pstart += os->psize;
380 if (os->header > -1 && os->seq > os->header){
382 if (os->codec && os->codec->packet)
383 os->codec->packet (s, idx);
387 *dstart = os->pstart;
390 os->pstart += os->psize;
395 if (os->segp == os->nsegs)
402 ogg_get_headers (AVFormatContext * s)
404 ogg_t *ogg = s->priv_data;
407 if (ogg_packet (s, NULL, NULL, NULL) < 0)
409 }while (!ogg->headers);
412 av_log (s, AV_LOG_DEBUG, "found headers\n");
419 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
421 ogg_t *ogg = s->priv_data;
422 ogg_stream_t *os = ogg->streams + i;
423 uint64_t pts = AV_NOPTS_VALUE;
425 if(os->codec->gptopts){
426 pts = os->codec->gptopts(s, i, gp);
436 ogg_get_length (AVFormatContext * s)
438 ogg_t *ogg = s->priv_data;
442 if(url_is_streamed(s->pb))
446 if (s->duration != AV_NOPTS_VALUE)
449 size = url_fsize(s->pb);
452 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
455 url_fseek (s->pb, end, SEEK_SET);
457 while (!ogg_read_page (s, &i)){
458 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
459 ogg->streams[i].codec)
464 s->streams[idx]->duration =
465 ogg_gptopts (s, idx, ogg->streams[idx].granule);
471 while (!ogg_read_page (s, &i)) {
472 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
476 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
477 s->streams[idx]->duration -= s->streams[idx]->start_time;
486 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
488 ogg_t *ogg = s->priv_data;
490 //linear headers seek from start
491 if (ogg_get_headers (s) < 0){
495 //linear granulepos seek from end
498 //fill the extradata in the per codec callbacks
504 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
513 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
515 }while (idx < 0 || !s->streams[idx]);
518 os = ogg->streams + idx;
521 if (av_new_packet (pkt, psize) < 0)
523 pkt->stream_index = idx;
524 memcpy (pkt->data, os->buf + pstart, psize);
525 if (os->lastgp != -1LL){
526 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
530 pkt->flags = os->pflags;
537 ogg_read_close (AVFormatContext * s)
539 ogg_t *ogg = s->priv_data;
542 for (i = 0; i < ogg->nstreams; i++){
543 av_free (ogg->streams[i].buf);
544 av_free (ogg->streams[i].private);
546 av_free (ogg->streams);
552 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
555 ogg_t *ogg = s->priv_data;
556 ByteIOContext *bc = s->pb;
557 int64_t pts = AV_NOPTS_VALUE;
559 url_fseek(bc, *pos_arg, SEEK_SET);
560 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
561 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
562 ogg->streams[i].codec && i == stream_index) {
563 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
564 // FIXME: this is the position of the packet after the one with above
566 *pos_arg = url_ftell(bc);
574 static int ogg_probe(AVProbeData *p)
576 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
577 p->buf[2] == 'g' && p->buf[3] == 'S' &&
578 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
579 return AVPROBE_SCORE_MAX;
584 AVInputFormat ogg_demuxer = {