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 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);
209 ogg_new_buf(ogg_t *ogg, int idx)
211 ogg_stream_t *os = ogg->streams + idx;
212 uint8_t *nb = av_malloc(os->bufsize);
213 int size = os->bufpos - os->pstart;
215 memcpy(nb, os->buf + os->pstart, size);
226 ogg_read_page (AVFormatContext * s, int *str)
228 ByteIOContext *bc = &s->pb;
229 ogg_t *ogg = s->priv_data;
241 if (get_buffer (bc, sync, 4) < 4)
247 if (sync[sp & 3] == 'O' &&
248 sync[(sp + 1) & 3] == 'g' &&
249 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
256 }while (i++ < MAX_PAGE_SIZE);
258 if (i >= MAX_PAGE_SIZE){
259 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
263 if (url_fgetc (bc) != 0) /* version */
266 flags = url_fgetc (bc);
268 serial = get_le32 (bc);
271 nsegs = url_fgetc (bc);
273 idx = ogg_find_stream (ogg, serial);
275 idx = ogg_new_stream (s, serial);
280 os = ogg->streams + idx;
283 ogg_new_buf(ogg, idx);
285 if (get_buffer (bc, os->segments, nsegs) < nsegs)
292 for (i = 0; i < nsegs; i++)
293 size += os->segments[i];
295 if (flags & OGG_FLAG_CONT){
297 while (os->segp < os->nsegs){
298 int seg = os->segments[os->segp++];
308 if (os->bufsize - os->bufpos < size){
309 uint8_t *nb = av_malloc (os->bufsize *= 2);
310 memset (nb, 0, os->bufsize);
311 memcpy (nb, os->buf, os->bufpos);
316 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
319 os->lastgp = os->granule;
331 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
333 ogg_t *ogg = s->priv_data;
337 int segp = 0, psize = 0;
340 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
347 if (ogg_read_page (s, &idx) < 0)
351 os = ogg->streams + idx;
354 av_log (s, AV_LOG_DEBUG,
355 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
356 idx, os->pstart, os->psize, os->segp, os->nsegs);
361 os->codec = ogg_find_codec (os->buf, os->bufpos);
374 while (os->segp < os->nsegs){
375 int ss = os->segments[os->segp++];
383 if (!complete && os->segp == os->nsegs){
389 av_log (s, AV_LOG_DEBUG,
390 "ogg_packet: idx %i, frame size %i, start %i\n",
391 idx, os->psize, os->pstart);
397 int hdr = os->codec->header (s, idx);
399 os->header = os->seq;
404 os->pstart += os->psize;
409 if (os->header > -1 && os->seq > os->header){
410 if (os->codec && os->codec->packet)
411 os->codec->packet (s, idx);
415 *dstart = os->pstart;
418 os->pstart += os->psize;
423 if (os->segp == os->nsegs)
430 ogg_get_headers (AVFormatContext * s)
432 ogg_t *ogg = s->priv_data;
435 if (ogg_packet (s, NULL, NULL, NULL) < 0)
437 }while (!ogg->headers);
440 av_log (s, AV_LOG_DEBUG, "found headers\n");
447 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
449 ogg_t *ogg = s->priv_data;
450 ogg_stream_t *os = ogg->streams + i;
451 uint64_t pts = AV_NOPTS_VALUE;
453 if(os->codec->gptopts){
454 pts = os->codec->gptopts(s, i, gp);
464 ogg_get_length (AVFormatContext * s)
466 ogg_t *ogg = s->priv_data;
470 if(s->pb.is_streamed)
474 if (s->duration != AV_NOPTS_VALUE)
477 size = url_fsize(&s->pb);
480 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
483 url_fseek (&s->pb, end, SEEK_SET);
485 while (!ogg_read_page (s, &i)){
486 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
491 s->streams[idx]->duration =
492 ogg_gptopts (s, idx, ogg->streams[idx].granule);
498 while (ogg_read_page (s, &i)) {
499 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
503 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
504 s->streams[idx]->duration -= s->streams[idx]->start_time;
513 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
515 ogg_t *ogg = s->priv_data;
517 //linear headers seek from start
518 if (ogg_get_headers (s) < 0){
522 //linear granulepos seek from end
525 //fill the extradata in the per codec callbacks
531 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
540 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
542 }while (idx < 0 || !s->streams[idx]);
545 os = ogg->streams + idx;
548 if (av_new_packet (pkt, psize) < 0)
550 pkt->stream_index = idx;
551 memcpy (pkt->data, os->buf + pstart, psize);
552 if (os->lastgp != -1LL){
553 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
562 ogg_read_close (AVFormatContext * s)
564 ogg_t *ogg = s->priv_data;
567 for (i = 0; i < ogg->nstreams; i++){
568 av_free (ogg->streams[i].buf);
569 av_free (ogg->streams[i].private);
571 av_free (ogg->streams);
577 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
580 AVStream *st = s->streams[stream_index];
581 ogg_t *ogg = s->priv_data;
582 ByteIOContext *bc = &s->pb;
583 uint64_t min = 0, max = ogg->size;
584 uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
585 int64_t pts = AV_NOPTS_VALUE;
589 if ((uint64_t)target_ts < tmin || target_ts < 0)
591 while (min <= max && tmin < tmax){
592 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
595 url_fseek (bc, p, SEEK_SET);
597 while (!ogg_read_page (s, &i)){
598 if (i == stream_index && ogg->streams[i].granule != 0 &&
599 ogg->streams[i].granule != -1)
606 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
609 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
612 if (pts > target_ts){
613 if (max == p && tmax == pts) {
614 // probably our tmin is wrong, causing us to always end up too late in the file
615 tmin = (target_ts + tmin + 1) / 2;
616 if (tmin == target_ts) {
617 url_fseek(bc, min, SEEK_SET);
624 if (min == p && tmin == pts) {
625 // probably our tmax is wrong, causing us to always end up too early in the file
626 tmax = (target_ts + tmax) / 2;
627 if (tmax == target_ts) {
628 url_fseek(bc, max, SEEK_SET);
637 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
642 pts = AV_NOPTS_VALUE;
645 av_update_cur_dts(s, st, pts);
651 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
653 pos = url_ftell (&s->pb);
654 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
661 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
664 ogg_t *ogg = s->priv_data;
665 ByteIOContext *bc = &s->pb;
669 return AV_NOPTS_VALUE;
675 static int ogg_probe(AVProbeData *p)
679 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
680 p->buf[2] == 'g' && p->buf[3] == 'S' &&
681 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
682 return AVPROBE_SCORE_MAX;
687 AVInputFormat ogg_demuxer = {
696 // ogg_read_timestamp,