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.
35 #include "vorbiscomment.h"
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 static const struct ogg_codec * const ogg_codecs[] = {
57 //FIXME We could avoid some structure duplication
58 static int ogg_save(AVFormatContext *s)
60 struct ogg *ogg = s->priv_data;
61 struct ogg_state *ost =
62 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64 ost->pos = avio_tell (s->pb);
65 ost->curidx = ogg->curidx;
66 ost->next = ogg->state;
67 ost->nstreams = ogg->nstreams;
68 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70 for (i = 0; i < ogg->nstreams; i++){
71 struct ogg_stream *os = ogg->streams + i;
72 os->buf = av_malloc (os->bufsize);
73 memset (os->buf, 0, os->bufsize);
74 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
82 static int ogg_restore(AVFormatContext *s, int discard)
84 struct ogg *ogg = s->priv_data;
85 AVIOContext *bc = s->pb;
86 struct ogg_state *ost = ogg->state;
92 ogg->state = ost->next;
95 struct ogg_stream *old_streams = ogg->streams;
97 for (i = 0; i < ogg->nstreams; i++)
98 av_free (ogg->streams[i].buf);
100 avio_seek (bc, ost->pos, SEEK_SET);
101 ogg->curidx = ost->curidx;
102 ogg->nstreams = ost->nstreams;
103 ogg->streams = av_realloc (ogg->streams,
104 ogg->nstreams * sizeof (*ogg->streams));
107 memcpy(ogg->streams, ost->streams,
108 ost->nstreams * sizeof(*ogg->streams));
110 av_free(old_streams);
120 static int ogg_reset(struct ogg *ogg)
124 for (i = 0; i < ogg->nstreams; i++){
125 struct ogg_stream *os = ogg->streams + i;
130 os->lastpts = AV_NOPTS_VALUE;
131 os->lastdts = AV_NOPTS_VALUE;
144 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
148 for (i = 0; ogg_codecs[i]; i++)
149 if (size >= ogg_codecs[i]->magicsize &&
150 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
151 return ogg_codecs[i];
156 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
159 struct ogg *ogg = s->priv_data;
160 int idx = ogg->nstreams++;
162 struct ogg_stream *os;
164 ogg->streams = av_realloc (ogg->streams,
165 ogg->nstreams * sizeof (*ogg->streams));
166 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
167 os = ogg->streams + idx;
169 os->bufsize = DECODER_BUFFER_SIZE;
170 os->buf = av_malloc(os->bufsize);
174 st = av_new_stream(s, idx);
176 return AVERROR(ENOMEM);
178 av_set_pts_info(st, 64, 1, 1000000);
184 static int ogg_new_buf(struct ogg *ogg, int idx)
186 struct ogg_stream *os = ogg->streams + idx;
187 uint8_t *nb = av_malloc(os->bufsize);
188 int size = os->bufpos - os->pstart;
190 memcpy(nb, os->buf + os->pstart, size);
200 static int ogg_read_page(AVFormatContext *s, int *str)
202 AVIOContext *bc = s->pb;
203 struct ogg *ogg = s->priv_data;
204 struct ogg_stream *os;
213 ret = avio_read(bc, sync, 4);
215 return ret < 0 ? ret : AVERROR_EOF;
220 if (sync[sp & 3] == 'O' &&
221 sync[(sp + 1) & 3] == 'g' &&
222 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
229 }while (i++ < MAX_PAGE_SIZE);
231 if (i >= MAX_PAGE_SIZE){
232 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
233 return AVERROR_INVALIDDATA;
236 if (avio_r8(bc) != 0) /* version */
237 return AVERROR_INVALIDDATA;
241 serial = avio_rl32 (bc);
242 avio_skip(bc, 8); /* seq, crc */
245 idx = ogg_find_stream (ogg, serial);
250 for (n = 0; n < ogg->nstreams; n++) {
251 av_freep(&ogg->streams[n].buf);
252 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
253 av_freep(&ogg->streams[n].private);
257 idx = ogg_new_stream(s, serial, 0);
259 idx = ogg_new_stream(s, serial, 1);
265 os = ogg->streams + idx;
266 os->page_pos = avio_tell(bc) - 27;
269 ogg_new_buf(ogg, idx);
271 ret = avio_read(bc, os->segments, nsegs);
273 return ret < 0 ? ret : AVERROR_EOF;
279 for (i = 0; i < nsegs; i++)
280 size += os->segments[i];
282 if (flags & OGG_FLAG_CONT || os->incomplete){
284 while (os->segp < os->nsegs){
285 int seg = os->segments[os->segp++];
290 os->sync_pos = os->page_pos;
294 os->sync_pos = os->page_pos;
297 if (os->bufsize - os->bufpos < size){
298 uint8_t *nb = av_malloc (os->bufsize *= 2);
299 memcpy (nb, os->buf, os->bufpos);
304 ret = avio_read(bc, os->buf + os->bufpos, size);
306 return ret < 0 ? ret : AVERROR_EOF;
318 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
321 struct ogg *ogg = s->priv_data;
323 struct ogg_stream *os;
325 int segp = 0, psize = 0;
327 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
333 ret = ogg_read_page(s, &idx);
338 os = ogg->streams + idx;
340 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
341 idx, os->pstart, os->psize, os->segp, os->nsegs);
345 os->codec = ogg_find_codec (os->buf, os->bufpos);
347 av_log(s, AV_LOG_WARNING, "Codec not found\n");
359 while (os->segp < os->nsegs){
360 int ss = os->segments[os->segp++];
368 if (!complete && os->segp == os->nsegs){
375 if (os->granule == -1)
376 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
382 os->header = os->codec->header (s, idx);
387 // We have reached the first non-header packet in this stream.
388 // Unfortunately more header packets may still follow for others,
389 // but if we continue with header parsing we may lose data packets.
392 // Update the header state for all streams and
393 // compute the data_offset.
395 s->data_offset = os->sync_pos;
396 for (i = 0; i < ogg->nstreams; i++) {
397 struct ogg_stream *cur_os = ogg->streams + i;
399 // if we have a partial non-header packet, its start is
400 // obviously at or after the data start
401 if (cur_os->incomplete)
402 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
405 os->pstart += os->psize;
411 if (os->codec && os->codec->packet)
412 os->codec->packet (s, idx);
416 *dstart = os->pstart;
420 *fpos = os->sync_pos;
421 os->pstart += os->psize;
423 if(os->pstart == os->bufpos)
424 os->bufpos = os->pstart = 0;
425 os->sync_pos = os->page_pos;
428 // determine whether there are more complete packets in this page
429 // if not, the page's granule will apply to this packet
431 for (i = os->segp; i < os->nsegs; i++)
432 if (os->segments[i] < 255) {
437 if (os->segp == os->nsegs)
443 static int ogg_get_headers(AVFormatContext *s)
445 struct ogg *ogg = s->priv_data;
449 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
452 }while (!ogg->headers);
454 av_dlog(s, "found headers\n");
459 static int ogg_get_length(AVFormatContext *s)
461 struct ogg *ogg = s->priv_data;
470 if (s->duration != AV_NOPTS_VALUE)
473 size = avio_size(s->pb);
476 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
479 avio_seek (s->pb, end, SEEK_SET);
481 while (!ogg_read_page (s, &i)){
482 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
483 ogg->streams[i].codec) {
484 s->streams[i]->duration =
485 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
486 if (s->streams[i]->start_time != AV_NOPTS_VALUE){
487 s->streams[i]->duration -= s->streams[i]->start_time;
488 streams_left-= (ogg->streams[i].got_start==-1);
489 ogg->streams[i].got_start= 1;
490 }else if(!ogg->streams[i].got_start){
491 ogg->streams[i].got_start= -1;
500 avio_seek (s->pb, 0, SEEK_SET);
501 while (!ogg_read_page (s, &i)){
502 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
503 ogg->streams[i].codec) {
504 if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
505 int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
506 if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE)
507 s->streams[i]->duration -= start;
508 ogg->streams[i].got_start= 1;
520 static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
522 struct ogg *ogg = s->priv_data;
525 //linear headers seek from start
526 ret = ogg_get_headers(s);
530 for (i = 0; i < ogg->nstreams; i++)
531 if (ogg->streams[i].header < 0)
532 ogg->streams[i].codec = NULL;
534 //linear granulepos seek from end
537 //fill the extradata in the per codec callbacks
541 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
543 struct ogg *ogg = s->priv_data;
544 struct ogg_stream *os = ogg->streams + idx;
545 int64_t pts = AV_NOPTS_VALUE;
548 *dts = AV_NOPTS_VALUE;
550 if (os->lastpts != AV_NOPTS_VALUE) {
552 os->lastpts = AV_NOPTS_VALUE;
554 if (os->lastdts != AV_NOPTS_VALUE) {
557 os->lastdts = AV_NOPTS_VALUE;
560 if (os->granule != -1LL) {
561 if (os->codec && os->codec->granule_is_start)
562 pts = ogg_gptopts(s, idx, os->granule, dts);
564 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
571 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
574 struct ogg_stream *os;
577 int64_t fpos, pts, dts;
582 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
585 }while (idx < 0 || !s->streams[idx]);
588 os = ogg->streams + idx;
590 // pflags might not be set until after this
591 pts = ogg_calc_pts(s, idx, &dts);
593 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
595 os->keyframe_seek = 0;
598 ret = av_new_packet(pkt, psize);
601 pkt->stream_index = idx;
602 memcpy (pkt->data, os->buf + pstart, psize);
606 pkt->flags = os->pflags;
607 pkt->duration = os->pduration;
613 static int ogg_read_close(AVFormatContext *s)
615 struct ogg *ogg = s->priv_data;
618 for (i = 0; i < ogg->nstreams; i++){
619 av_free (ogg->streams[i].buf);
620 av_free (ogg->streams[i].private);
622 av_free (ogg->streams);
626 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
627 int64_t *pos_arg, int64_t pos_limit)
629 struct ogg *ogg = s->priv_data;
630 AVIOContext *bc = s->pb;
631 int64_t pts = AV_NOPTS_VALUE;
633 avio_seek(bc, *pos_arg, SEEK_SET);
636 while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
637 if (i == stream_index) {
638 struct ogg_stream *os = ogg->streams + stream_index;
639 pts = ogg_calc_pts(s, i, NULL);
640 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
641 pts = AV_NOPTS_VALUE;
643 if (pts != AV_NOPTS_VALUE)
650 static int ogg_read_seek(AVFormatContext *s, int stream_index,
651 int64_t timestamp, int flags)
653 struct ogg *ogg = s->priv_data;
654 struct ogg_stream *os = ogg->streams + stream_index;
657 // Try seeking to a keyframe first. If this fails (very possible),
658 // av_seek_frame will fall back to ignoring keyframes
659 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
660 && !(flags & AVSEEK_FLAG_ANY))
661 os->keyframe_seek = 1;
663 ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
664 os = ogg->streams + stream_index;
666 os->keyframe_seek = 0;
670 static int ogg_probe(AVProbeData *p)
672 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
673 return AVPROBE_SCORE_MAX;
677 AVInputFormat ff_ogg_demuxer = {
679 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
680 .priv_data_size = sizeof(struct ogg),
681 .read_probe = ogg_probe,
682 .read_header = ogg_read_header,
683 .read_packet = ogg_read_packet,
684 .read_close = ogg_read_close,
685 .read_seek = ogg_read_seek,
686 .read_timestamp = ogg_read_timestamp,
688 .flags = AVFMT_GENERIC_INDEX,