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 memcpy (nb, os->buf, os->bufpos);
315 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
318 os->lastgp = os->granule;
330 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
332 ogg_t *ogg = s->priv_data;
336 int segp = 0, psize = 0;
339 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
346 if (ogg_read_page (s, &idx) < 0)
350 os = ogg->streams + idx;
353 av_log (s, AV_LOG_DEBUG,
354 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
355 idx, os->pstart, os->psize, os->segp, os->nsegs);
360 os->codec = ogg_find_codec (os->buf, os->bufpos);
373 while (os->segp < os->nsegs){
374 int ss = os->segments[os->segp++];
382 if (!complete && os->segp == os->nsegs){
388 av_log (s, AV_LOG_DEBUG,
389 "ogg_packet: idx %i, frame size %i, start %i\n",
390 idx, os->psize, os->pstart);
396 int hdr = os->codec->header (s, idx);
398 os->header = os->seq;
403 os->pstart += os->psize;
408 if (os->header > -1 && os->seq > os->header){
409 if (os->codec && os->codec->packet)
410 os->codec->packet (s, idx);
414 *dstart = os->pstart;
417 os->pstart += os->psize;
422 if (os->segp == os->nsegs)
429 ogg_get_headers (AVFormatContext * s)
431 ogg_t *ogg = s->priv_data;
434 if (ogg_packet (s, NULL, NULL, NULL) < 0)
436 }while (!ogg->headers);
439 av_log (s, AV_LOG_DEBUG, "found headers\n");
446 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
448 ogg_t *ogg = s->priv_data;
449 ogg_stream_t *os = ogg->streams + i;
450 uint64_t pts = AV_NOPTS_VALUE;
452 if(os->codec->gptopts){
453 pts = os->codec->gptopts(s, i, gp);
463 ogg_get_length (AVFormatContext * s)
465 ogg_t *ogg = s->priv_data;
469 if(s->pb.is_streamed)
473 if (s->duration != AV_NOPTS_VALUE)
476 size = url_fsize(&s->pb);
479 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
482 url_fseek (&s->pb, end, SEEK_SET);
484 while (!ogg_read_page (s, &i)){
485 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
490 s->streams[idx]->duration =
491 ogg_gptopts (s, idx, ogg->streams[idx].granule);
497 while (ogg_read_page (s, &i)) {
498 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
502 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
503 s->streams[idx]->duration -= s->streams[idx]->start_time;
512 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
514 ogg_t *ogg = s->priv_data;
516 //linear headers seek from start
517 if (ogg_get_headers (s) < 0){
521 //linear granulepos seek from end
524 //fill the extradata in the per codec callbacks
530 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
539 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
541 }while (idx < 0 || !s->streams[idx]);
544 os = ogg->streams + idx;
547 if (av_new_packet (pkt, psize) < 0)
549 pkt->stream_index = idx;
550 memcpy (pkt->data, os->buf + pstart, psize);
551 if (os->lastgp != -1LL){
552 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
561 ogg_read_close (AVFormatContext * s)
563 ogg_t *ogg = s->priv_data;
566 for (i = 0; i < ogg->nstreams; i++){
567 av_free (ogg->streams[i].buf);
568 av_free (ogg->streams[i].private);
570 av_free (ogg->streams);
576 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
579 AVStream *st = s->streams[stream_index];
580 ogg_t *ogg = s->priv_data;
581 ByteIOContext *bc = &s->pb;
582 uint64_t min = 0, max = ogg->size;
583 uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
584 int64_t pts = AV_NOPTS_VALUE;
588 if ((uint64_t)target_ts < tmin || target_ts < 0)
590 while (min <= max && tmin < tmax){
591 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
594 url_fseek (bc, p, SEEK_SET);
596 while (!ogg_read_page (s, &i)){
597 if (i == stream_index && ogg->streams[i].granule != 0 &&
598 ogg->streams[i].granule != -1)
605 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
608 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
611 if (pts > target_ts){
612 if (max == p && tmax == pts) {
613 // probably our tmin is wrong, causing us to always end up too late in the file
614 tmin = (target_ts + tmin + 1) / 2;
615 if (tmin == target_ts) {
616 url_fseek(bc, min, SEEK_SET);
623 if (min == p && tmin == pts) {
624 // probably our tmax is wrong, causing us to always end up too early in the file
625 tmax = (target_ts + tmax) / 2;
626 if (tmax == target_ts) {
627 url_fseek(bc, max, SEEK_SET);
636 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
641 pts = AV_NOPTS_VALUE;
644 av_update_cur_dts(s, st, pts);
650 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
652 pos = url_ftell (&s->pb);
653 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
660 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
663 ogg_t *ogg = s->priv_data;
664 ByteIOContext *bc = &s->pb;
668 return AV_NOPTS_VALUE;
674 static int ogg_probe(AVProbeData *p)
678 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
679 p->buf[2] == 'g' && p->buf[3] == 'S' &&
680 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
681 return AVPROBE_SCORE_MAX;
686 AVInputFormat ogg_demuxer = {
695 // ogg_read_timestamp,