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 //FIXME We could avoid some structure duplication
53 ogg_save (AVFormatContext * s)
55 ogg_t *ogg = s->priv_data;
57 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
59 ost->pos = url_ftell (s->pb);
60 ost->curidx = ogg->curidx;
61 ost->next = ogg->state;
62 ost->nstreams = ogg->nstreams;
63 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
65 for (i = 0; i < ogg->nstreams; i++){
66 ogg_stream_t *os = ogg->streams + i;
67 os->buf = av_malloc (os->bufsize);
68 memset (os->buf, 0, os->bufsize);
69 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
78 ogg_restore (AVFormatContext * s, int discard)
80 ogg_t *ogg = s->priv_data;
81 ByteIOContext *bc = s->pb;
82 ogg_state_t *ost = ogg->state;
88 ogg->state = ost->next;
91 for (i = 0; i < ogg->nstreams; i++)
92 av_free (ogg->streams[i].buf);
94 url_fseek (bc, ost->pos, SEEK_SET);
95 ogg->curidx = ost->curidx;
96 ogg->nstreams = ost->nstreams;
97 memcpy(ogg->streams, ost->streams,
98 ost->nstreams * sizeof(*ogg->streams));
107 ogg_reset (ogg_t * ogg)
111 for (i = 0; i < ogg->nstreams; i++){
112 ogg_stream_t *os = ogg->streams + i;
128 ogg_find_codec (uint8_t * buf, int size)
132 for (i = 0; ogg_codecs[i]; i++)
133 if (size >= ogg_codecs[i]->magicsize &&
134 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
135 return ogg_codecs[i];
141 ogg_find_stream (ogg_t * ogg, int serial)
145 for (i = 0; i < ogg->nstreams; i++)
146 if (ogg->streams[i].serial == serial)
153 ogg_new_stream (AVFormatContext * s, uint32_t serial)
156 ogg_t *ogg = s->priv_data;
157 int idx = ogg->nstreams++;
161 ogg->streams = av_realloc (ogg->streams,
162 ogg->nstreams * sizeof (*ogg->streams));
163 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
164 os = ogg->streams + idx;
166 os->bufsize = DECODER_BUFFER_SIZE;
167 os->buf = av_malloc(os->bufsize);
170 st = av_new_stream (s, idx);
172 return AVERROR(ENOMEM);
174 av_set_pts_info(st, 64, 1, 1000000);
180 ogg_new_buf(ogg_t *ogg, int idx)
182 ogg_stream_t *os = ogg->streams + idx;
183 uint8_t *nb = av_malloc(os->bufsize);
184 int size = os->bufpos - os->pstart;
186 memcpy(nb, os->buf + os->pstart, size);
197 ogg_read_page (AVFormatContext * s, int *str)
199 ByteIOContext *bc = s->pb;
200 ogg_t *ogg = s->priv_data;
212 if (get_buffer (bc, sync, 4) < 4)
218 if (sync[sp & 3] == 'O' &&
219 sync[(sp + 1) & 3] == 'g' &&
220 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
227 }while (i++ < MAX_PAGE_SIZE);
229 if (i >= MAX_PAGE_SIZE){
230 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
234 if (url_fgetc (bc) != 0) /* version */
237 flags = url_fgetc (bc);
239 serial = get_le32 (bc);
242 nsegs = url_fgetc (bc);
244 idx = ogg_find_stream (ogg, serial);
246 idx = ogg_new_stream (s, serial);
251 os = ogg->streams + idx;
254 ogg_new_buf(ogg, idx);
256 if (get_buffer (bc, os->segments, nsegs) < nsegs)
263 for (i = 0; i < nsegs; i++)
264 size += os->segments[i];
266 if (flags & OGG_FLAG_CONT){
268 while (os->segp < os->nsegs){
269 int seg = os->segments[os->segp++];
279 if (os->bufsize - os->bufpos < size){
280 uint8_t *nb = av_malloc (os->bufsize *= 2);
281 memcpy (nb, os->buf, os->bufpos);
286 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
289 os->lastgp = os->granule;
301 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
303 ogg_t *ogg = s->priv_data;
307 int segp = 0, psize = 0;
310 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
317 if (ogg_read_page (s, &idx) < 0)
321 os = ogg->streams + idx;
324 av_log (s, AV_LOG_DEBUG,
325 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
326 idx, os->pstart, os->psize, os->segp, os->nsegs);
331 os->codec = ogg_find_codec (os->buf, os->bufpos);
344 while (os->segp < os->nsegs){
345 int ss = os->segments[os->segp++];
353 if (!complete && os->segp == os->nsegs){
359 av_log (s, AV_LOG_DEBUG,
360 "ogg_packet: idx %i, frame size %i, start %i\n",
361 idx, os->psize, os->pstart);
367 int hdr = os->codec->header (s, idx);
369 os->header = os->seq;
374 os->pstart += os->psize;
379 if (os->header > -1 && os->seq > os->header){
381 if (os->codec && os->codec->packet)
382 os->codec->packet (s, idx);
386 *dstart = os->pstart;
389 os->pstart += os->psize;
394 if (os->segp == os->nsegs)
401 ogg_get_headers (AVFormatContext * s)
403 ogg_t *ogg = s->priv_data;
406 if (ogg_packet (s, NULL, NULL, NULL) < 0)
408 }while (!ogg->headers);
411 av_log (s, AV_LOG_DEBUG, "found headers\n");
418 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
420 ogg_t *ogg = s->priv_data;
421 ogg_stream_t *os = ogg->streams + i;
422 uint64_t pts = AV_NOPTS_VALUE;
424 if(os->codec->gptopts){
425 pts = os->codec->gptopts(s, i, gp);
435 ogg_get_length (AVFormatContext * s)
437 ogg_t *ogg = s->priv_data;
441 if(s->pb->is_streamed)
445 if (s->duration != AV_NOPTS_VALUE)
448 size = url_fsize(s->pb);
451 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
454 url_fseek (s->pb, end, SEEK_SET);
456 while (!ogg_read_page (s, &i)){
457 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
458 ogg->streams[i].codec)
463 s->streams[idx]->duration =
464 ogg_gptopts (s, idx, ogg->streams[idx].granule);
470 while (!ogg_read_page (s, &i)) {
471 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
475 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
476 s->streams[idx]->duration -= s->streams[idx]->start_time;
485 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
487 ogg_t *ogg = s->priv_data;
489 //linear headers seek from start
490 if (ogg_get_headers (s) < 0){
494 //linear granulepos seek from end
497 //fill the extradata in the per codec callbacks
503 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
512 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
514 }while (idx < 0 || !s->streams[idx]);
517 os = ogg->streams + idx;
520 if (av_new_packet (pkt, psize) < 0)
522 pkt->stream_index = idx;
523 memcpy (pkt->data, os->buf + pstart, psize);
524 if (os->lastgp != -1LL){
525 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
529 pkt->flags = os->pflags;
536 ogg_read_close (AVFormatContext * s)
538 ogg_t *ogg = s->priv_data;
541 for (i = 0; i < ogg->nstreams; i++){
542 av_free (ogg->streams[i].buf);
543 av_free (ogg->streams[i].private);
545 av_free (ogg->streams);
551 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
554 ogg_t *ogg = s->priv_data;
555 ByteIOContext *bc = s->pb;
556 int64_t pts = AV_NOPTS_VALUE;
558 url_fseek(bc, *pos_arg, SEEK_SET);
559 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
560 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
561 ogg->streams[i].codec && i == stream_index) {
562 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
563 // FIXME: this is the position of the packet after the one with above
565 *pos_arg = url_ftell(bc);
573 static int ogg_probe(AVProbeData *p)
575 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
576 p->buf[2] == 'g' && p->buf[3] == 'S' &&
577 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
578 return AVPROBE_SCORE_MAX;
583 AVInputFormat ogg_demuxer = {