2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
8 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
10 Permission is hereby granted, free of charge, to any person
11 obtaining a copy of this software and associated documentation
12 files (the "Software"), to deal in the Software without
13 restriction, including without limitation the rights to use, copy,
14 modify, merge, publish, distribute, sublicense, and/or sell copies
15 of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
32 #include "libavutil/avassert.h"
33 #include "libavutil/intreadwrite.h"
37 #include "vorbiscomment.h"
39 #define MAX_PAGE_SIZE 65307
40 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
42 static const struct ogg_codec * const ogg_codecs[] = {
62 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
63 static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
64 static int ogg_restore(AVFormatContext *s);
66 static void free_stream(AVFormatContext *s, int i)
68 struct ogg *ogg = s->priv_data;
69 struct ogg_stream *stream = &ogg->streams[i];
71 av_freep(&stream->buf);
73 stream->codec->cleanup) {
74 stream->codec->cleanup(s, i);
77 av_freep(&stream->private);
78 av_freep(&stream->new_metadata);
81 //FIXME We could avoid some structure duplication
82 static int ogg_save(AVFormatContext *s)
84 struct ogg *ogg = s->priv_data;
85 struct ogg_state *ost =
86 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
91 return AVERROR(ENOMEM);
93 ost->pos = avio_tell(s->pb);
94 ost->curidx = ogg->curidx;
95 ost->next = ogg->state;
96 ost->nstreams = ogg->nstreams;
97 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
99 for (i = 0; i < ogg->nstreams; i++) {
100 struct ogg_stream *os = ogg->streams + i;
101 os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
103 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
105 ret = AVERROR(ENOMEM);
106 os->new_metadata = NULL;
107 os->new_metadata_size = 0;
118 static int ogg_restore(AVFormatContext *s)
120 struct ogg *ogg = s->priv_data;
121 AVIOContext *bc = s->pb;
122 struct ogg_state *ost = ogg->state;
128 ogg->state = ost->next;
130 for (i = 0; i < ogg->nstreams; i++) {
131 av_freep(&ogg->streams[i].buf);
132 if (i >= ost->nstreams || !ost->streams[i].private) {
137 avio_seek(bc, ost->pos, SEEK_SET);
139 ogg->curidx = ost->curidx;
140 ogg->nstreams = ost->nstreams;
141 if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
142 sizeof(*ogg->streams))) < 0) {
146 memcpy(ogg->streams, ost->streams,
147 ost->nstreams * sizeof(*ogg->streams));
154 static int ogg_reset(AVFormatContext *s)
156 struct ogg *ogg = s->priv_data;
158 int64_t start_pos = avio_tell(s->pb);
160 for (i = 0; i < ogg->nstreams; i++) {
161 struct ogg_stream *os = ogg->streams + i;
166 os->lastpts = AV_NOPTS_VALUE;
167 os->lastdts = AV_NOPTS_VALUE;
174 if (start_pos <= s->internal->data_offset) {
177 os->end_trimming = 0;
178 av_freep(&os->new_metadata);
179 os->new_metadata_size = 0;
188 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
192 for (i = 0; ogg_codecs[i]; i++)
193 if (size >= ogg_codecs[i]->magicsize &&
194 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
195 return ogg_codecs[i];
201 * Replace the current stream with a new one. This is a typical webradio
202 * situation where a new audio stream spawn (identified with a new serial) and
203 * must replace the previous one (track switch).
205 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
207 struct ogg *ogg = s->priv_data;
208 struct ogg_stream *os;
209 const struct ogg_codec *codec;
212 if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
214 int64_t pos = avio_tell(s->pb);
215 avio_skip(s->pb, nsegs);
216 avio_read(s->pb, magic, sizeof(magic));
217 avio_seek(s->pb, pos, SEEK_SET);
218 codec = ogg_find_codec(magic, sizeof(magic));
220 av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
221 return AVERROR_INVALIDDATA;
223 for (i = 0; i < ogg->nstreams; i++) {
224 if (ogg->streams[i].codec == codec)
227 if (i >= ogg->nstreams)
228 return ogg_new_stream(s, serial);
229 } else if (ogg->nstreams != 1) {
230 avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
231 return AVERROR_PATCHWELCOME;
234 os = &ogg->streams[i];
241 bufsize = os->bufsize;
244 if (!ogg->state || ogg->state->streams[i].private != os->private)
245 av_freep(&ogg->streams[i].private);
247 /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
248 * also re-use the ogg_stream allocated buffer */
249 memset(os, 0, sizeof(*os));
251 os->bufsize = bufsize;
260 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
262 struct ogg *ogg = s->priv_data;
263 int idx = ogg->nstreams;
265 struct ogg_stream *os;
269 av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
270 "in between Ogg context save/restore operations.\n");
274 /* Allocate and init a new Ogg Stream */
275 if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
276 !(os = av_realloc(ogg->streams, size)))
277 return AVERROR(ENOMEM);
279 os = ogg->streams + idx;
280 memset(os, 0, sizeof(*os));
282 os->bufsize = DECODER_BUFFER_SIZE;
283 os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
285 os->start_granule = OGG_NOGRANULE_VALUE;
287 return AVERROR(ENOMEM);
289 /* Create the associated AVStream */
290 st = avformat_new_stream(s, NULL);
293 return AVERROR(ENOMEM);
296 avpriv_set_pts_info(st, 64, 1, 1000000);
302 static int ogg_new_buf(struct ogg *ogg, int idx)
304 struct ogg_stream *os = ogg->streams + idx;
305 uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
306 int size = os->bufpos - os->pstart;
309 return AVERROR(ENOMEM);
312 memcpy(nb, os->buf + os->pstart, size);
323 static int data_packets_seen(const struct ogg *ogg)
327 for (i = 0; i < ogg->nstreams; i++)
328 if (ogg->streams[i].got_data)
333 static int ogg_read_page(AVFormatContext *s, int *sid)
335 AVIOContext *bc = s->pb;
336 struct ogg *ogg = s->priv_data;
337 struct ogg_stream *os;
346 ret = avio_read(bc, sync, 4);
348 return ret < 0 ? ret : AVERROR_EOF;
353 if (sync[sp & 3] == 'O' &&
354 sync[(sp + 1) & 3] == 'g' &&
355 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
358 if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
360 avio_seek(bc, ogg->page_pos+4, SEEK_SET);
370 } while (i++ < MAX_PAGE_SIZE);
372 if (i >= MAX_PAGE_SIZE) {
373 av_log(s, AV_LOG_INFO, "cannot find sync word\n");
374 return AVERROR_INVALIDDATA;
377 if (avio_r8(bc) != 0) { /* version */
378 av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
379 return AVERROR_INVALIDDATA;
384 serial = avio_rl32(bc);
385 avio_skip(bc, 8); /* seq, crc */
388 idx = ogg_find_stream(ogg, serial);
390 if (data_packets_seen(ogg))
391 idx = ogg_replace_stream(s, serial, nsegs);
393 idx = ogg_new_stream(s, serial);
396 av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
401 os = ogg->streams + idx;
403 os->page_pos = avio_tell(bc) - 27;
406 ret = ogg_new_buf(ogg, idx);
411 ret = avio_read(bc, os->segments, nsegs);
413 return ret < 0 ? ret : AVERROR_EOF;
419 for (i = 0; i < nsegs; i++)
420 size += os->segments[i];
422 if (!(flags & OGG_FLAG_BOS))
425 if (flags & OGG_FLAG_CONT || os->incomplete) {
427 // If this is the very first segment we started
428 // playback in the middle of a continuation packet.
429 // Discard it since we missed the start of it.
430 while (os->segp < os->nsegs) {
431 int seg = os->segments[os->segp++];
436 os->sync_pos = os->page_pos;
440 os->sync_pos = os->page_pos;
443 if (os->bufsize - os->bufpos < size) {
444 uint8_t *nb = av_malloc((os->bufsize *= 2) + AV_INPUT_BUFFER_PADDING_SIZE);
446 return AVERROR(ENOMEM);
447 memcpy(nb, os->buf, os->bufpos);
452 ret = avio_read(bc, os->buf + os->bufpos, size);
454 return ret < 0 ? ret : AVERROR_EOF;
460 memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
468 * @brief find the next Ogg packet
469 * @param *sid is set to the stream for the packet or -1 if there is
470 * no matching stream, in that case assume all other return
471 * values to be uninitialized.
472 * @return negative value on error or EOF.
474 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
477 struct ogg *ogg = s->priv_data;
479 struct ogg_stream *os;
481 int segp = 0, psize = 0;
483 av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
491 ret = ogg_read_page(s, &idx);
496 os = ogg->streams + idx;
498 av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
499 idx, os->pstart, os->psize, os->segp, os->nsegs);
502 if (os->header < 0) {
503 os->codec = ogg_find_codec(os->buf, os->bufpos);
505 av_log(s, AV_LOG_WARNING, "Codec not found\n");
517 while (os->segp < os->nsegs) {
518 int ss = os->segments[os->segp++];
526 if (!complete && os->segp == os->nsegs) {
528 // Do not set incomplete for empty packets.
529 // Together with the code in ogg_read_page
530 // that discards all continuation of empty packets
531 // we would get an infinite loop.
532 os->incomplete = !!os->psize;
537 if (os->granule == -1)
538 av_log(s, AV_LOG_WARNING,
539 "Page at %"PRId64" is missing granule\n",
546 if ((ret = os->codec->header(s, idx)) < 0) {
547 av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
555 // We have reached the first non-header packet in this stream.
556 // Unfortunately more header packets may still follow for others,
557 // but if we continue with header parsing we may lose data packets.
560 // Update the header state for all streams and
561 // compute the data_offset.
562 if (!s->internal->data_offset)
563 s->internal->data_offset = os->sync_pos;
565 for (i = 0; i < ogg->nstreams; i++) {
566 struct ogg_stream *cur_os = ogg->streams + i;
568 // if we have a partial non-header packet, its start is
569 // obviously at or after the data start
570 if (cur_os->incomplete)
571 s->internal->data_offset = FFMIN(s->internal->data_offset, cur_os->sync_pos);
575 os->pstart += os->psize;
581 if (os->codec && os->codec->packet) {
582 if ((ret = os->codec->packet(s, idx)) < 0) {
583 av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
590 *dstart = os->pstart;
594 *fpos = os->sync_pos;
595 os->pstart += os->psize;
597 if(os->pstart == os->bufpos)
598 os->bufpos = os->pstart = 0;
599 os->sync_pos = os->page_pos;
602 // determine whether there are more complete packets in this page
603 // if not, the page's granule will apply to this packet
605 for (i = os->segp; i < os->nsegs; i++)
606 if (os->segments[i] < 255) {
611 if (os->segp == os->nsegs)
617 static int ogg_get_length(AVFormatContext *s)
619 struct ogg *ogg = s->priv_data;
624 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
628 if (s->duration != AV_NOPTS_VALUE)
631 size = avio_size(s->pb);
634 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
639 avio_seek(s->pb, end, SEEK_SET);
642 while (!ogg_read_page(s, &i)) {
643 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
644 ogg->streams[i].codec) {
645 s->streams[i]->duration =
646 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
647 if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
648 s->streams[i]->duration -= s->streams[i]->start_time;
649 streams_left-= (ogg->streams[i].got_start==-1);
650 ogg->streams[i].got_start= 1;
651 } else if(!ogg->streams[i].got_start) {
652 ogg->streams[i].got_start= -1;
664 avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
666 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
669 pts = ogg_calc_pts(s, i, NULL);
670 if (s->streams[i]->duration == AV_NOPTS_VALUE)
672 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
673 s->streams[i]->duration -= pts;
674 ogg->streams[i].got_start= 1;
676 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
677 ogg->streams[i].got_start= 1;
686 static int ogg_read_close(AVFormatContext *s)
688 struct ogg *ogg = s->priv_data;
691 for (i = 0; i < ogg->nstreams; i++) {
697 av_freep(&ogg->streams);
701 static int ogg_read_header(AVFormatContext *s)
703 struct ogg *ogg = s->priv_data;
708 //linear headers seek from start
710 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
715 } while (!ogg->headers);
716 av_log(s, AV_LOG_TRACE, "found headers\n");
718 for (i = 0; i < ogg->nstreams; i++) {
719 struct ogg_stream *os = ogg->streams + i;
721 if (ogg->streams[i].header < 0) {
722 av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
723 ogg->streams[i].codec = NULL;
724 av_freep(&ogg->streams[i].private);
725 } else if (os->codec && os->nb_header < os->codec->nb_header) {
726 av_log(s, AV_LOG_WARNING,
727 "Headers mismatch for stream %d: "
728 "expected %d received %d.\n",
729 i, os->codec->nb_header, os->nb_header);
730 if (s->error_recognition & AV_EF_EXPLODE) {
732 return AVERROR_INVALIDDATA;
735 if (os->start_granule != OGG_NOGRANULE_VALUE)
736 os->lastpts = s->streams[i]->start_time =
737 ogg_gptopts(s, i, os->start_granule, NULL);
740 //linear granulepos seek from end
741 ret = ogg_get_length(s);
750 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
752 struct ogg *ogg = s->priv_data;
753 struct ogg_stream *os = ogg->streams + idx;
754 int64_t pts = AV_NOPTS_VALUE;
757 *dts = AV_NOPTS_VALUE;
759 if (os->lastpts != AV_NOPTS_VALUE) {
761 os->lastpts = AV_NOPTS_VALUE;
763 if (os->lastdts != AV_NOPTS_VALUE) {
766 os->lastdts = AV_NOPTS_VALUE;
769 if (os->granule != -1LL) {
770 if (os->codec && os->codec->granule_is_start)
771 pts = ogg_gptopts(s, idx, os->granule, dts);
773 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
780 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
782 struct ogg *ogg = s->priv_data;
783 struct ogg_stream *os = ogg->streams + idx;
786 switch (s->streams[idx]->codecpar->codec_id) {
787 case AV_CODEC_ID_THEORA:
788 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
790 case AV_CODEC_ID_VP8:
791 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
794 os->pflags ^= AV_PKT_FLAG_KEY;
795 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
796 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
801 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
804 struct ogg_stream *os;
807 int64_t fpos, pts, dts;
809 if (s->io_repositioned) {
811 s->io_repositioned = 0;
817 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
820 } while (idx < 0 || !s->streams[idx]);
823 os = ogg->streams + idx;
825 // pflags might not be set until after this
826 pts = ogg_calc_pts(s, idx, &dts);
827 ogg_validate_keyframe(s, idx, pstart, psize);
829 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
831 os->keyframe_seek = 0;
834 ret = av_new_packet(pkt, psize);
837 pkt->stream_index = idx;
838 memcpy(pkt->data, os->buf + pstart, psize);
842 pkt->flags = os->pflags;
843 pkt->duration = os->pduration;
846 if (os->end_trimming) {
847 uint8_t *side_data = av_packet_new_side_data(pkt,
848 AV_PKT_DATA_SKIP_SAMPLES,
852 AV_WL32(side_data + 4, os->end_trimming);
853 os->end_trimming = 0;
856 if (os->new_metadata) {
857 uint8_t *side_data = av_packet_new_side_data(pkt,
858 AV_PKT_DATA_METADATA_UPDATE,
859 os->new_metadata_size);
863 memcpy(side_data, os->new_metadata, os->new_metadata_size);
864 av_freep(&os->new_metadata);
865 os->new_metadata_size = 0;
870 av_packet_unref(pkt);
871 return AVERROR(ENOMEM);
874 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
875 int64_t *pos_arg, int64_t pos_limit)
877 struct ogg *ogg = s->priv_data;
878 AVIOContext *bc = s->pb;
879 int64_t pts = AV_NOPTS_VALUE;
883 avio_seek(bc, *pos_arg, SEEK_SET);
886 while ( avio_tell(bc) <= pos_limit
887 && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
888 if (i == stream_index) {
889 struct ogg_stream *os = ogg->streams + stream_index;
890 // Do not trust the last timestamps of an ogm video
891 if ( (os->flags & OGG_FLAG_EOS)
892 && !(os->flags & OGG_FLAG_BOS)
893 && os->codec == &ff_ogm_video_codec)
895 pts = ogg_calc_pts(s, i, NULL);
896 ogg_validate_keyframe(s, i, pstart, psize);
897 if (os->pflags & AV_PKT_FLAG_KEY) {
899 } else if (os->keyframe_seek) {
900 // if we had a previous keyframe but no pts for it,
901 // return that keyframe with this pts value.
905 pts = AV_NOPTS_VALUE;
908 if (pts != AV_NOPTS_VALUE)
915 static int ogg_read_seek(AVFormatContext *s, int stream_index,
916 int64_t timestamp, int flags)
918 struct ogg *ogg = s->priv_data;
919 struct ogg_stream *os = ogg->streams + stream_index;
922 av_assert0(stream_index < ogg->nstreams);
923 // Ensure everything is reset even when seeking via
924 // the generated index.
927 // Try seeking to a keyframe first. If this fails (very possible),
928 // av_seek_frame will fall back to ignoring keyframes
929 if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
930 && !(flags & AVSEEK_FLAG_ANY))
931 os->keyframe_seek = 1;
933 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
935 os = ogg->streams + stream_index;
937 os->keyframe_seek = 0;
941 static int ogg_probe(AVProbeData *p)
943 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
944 return AVPROBE_SCORE_MAX;
948 AVInputFormat ff_ogg_demuxer = {
950 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
951 .priv_data_size = sizeof(struct ogg),
952 .read_probe = ogg_probe,
953 .read_header = ogg_read_header,
954 .read_packet = ogg_read_packet,
955 .read_close = ogg_read_close,
956 .read_seek = ogg_read_seek,
957 .read_timestamp = ogg_read_timestamp,
959 .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,