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"
36 #include "vorbiscomment.h"
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
41 static const struct ogg_codec * const ogg_codecs[] = {
59 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
61 //FIXME We could avoid some structure duplication
62 static int ogg_save(AVFormatContext *s)
64 struct ogg *ogg = s->priv_data;
65 struct ogg_state *ost =
66 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
68 ost->pos = avio_tell (s->pb);
69 ost->curidx = ogg->curidx;
70 ost->next = ogg->state;
71 ost->nstreams = ogg->nstreams;
72 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
74 for (i = 0; i < ogg->nstreams; i++){
75 struct ogg_stream *os = ogg->streams + i;
76 os->buf = av_mallocz (os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
77 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
85 static int ogg_restore(AVFormatContext *s, int discard)
87 struct ogg *ogg = s->priv_data;
88 AVIOContext *bc = s->pb;
89 struct ogg_state *ost = ogg->state;
95 ogg->state = ost->next;
98 struct ogg_stream *old_streams = ogg->streams;
100 for (i = 0; i < ogg->nstreams; i++)
101 av_free (ogg->streams[i].buf);
103 avio_seek (bc, ost->pos, SEEK_SET);
104 ogg->curidx = ost->curidx;
105 ogg->nstreams = ost->nstreams;
106 ogg->streams = av_realloc (ogg->streams,
107 ogg->nstreams * sizeof (*ogg->streams));
110 memcpy(ogg->streams, ost->streams,
111 ost->nstreams * sizeof(*ogg->streams));
113 av_free(old_streams);
123 static int ogg_reset(AVFormatContext *s)
125 struct ogg *ogg = s->priv_data;
127 int64_t start_pos = avio_tell(s->pb);
129 for (i = 0; i < ogg->nstreams; i++){
130 struct ogg_stream *os = ogg->streams + i;
135 os->lastpts = AV_NOPTS_VALUE;
136 os->lastdts = AV_NOPTS_VALUE;
142 if (start_pos <= s->data_offset) {
152 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
156 for (i = 0; ogg_codecs[i]; i++)
157 if (size >= ogg_codecs[i]->magicsize &&
158 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
159 return ogg_codecs[i];
164 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
167 struct ogg *ogg = s->priv_data;
168 int idx = ogg->nstreams++;
170 struct ogg_stream *os;
172 ogg->streams = av_realloc (ogg->streams,
173 ogg->nstreams * sizeof (*ogg->streams));
174 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
175 os = ogg->streams + idx;
177 os->bufsize = DECODER_BUFFER_SIZE;
178 os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
182 st = avformat_new_stream(s, NULL);
184 return AVERROR(ENOMEM);
187 avpriv_set_pts_info(st, 64, 1, 1000000);
193 static int ogg_new_buf(struct ogg *ogg, int idx)
195 struct ogg_stream *os = ogg->streams + idx;
196 uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
197 int size = os->bufpos - os->pstart;
199 memcpy(nb, os->buf + os->pstart, size);
209 static int ogg_read_page(AVFormatContext *s, int *str)
211 AVIOContext *bc = s->pb;
212 struct ogg *ogg = s->priv_data;
213 struct ogg_stream *os;
222 ret = avio_read(bc, sync, 4);
224 return ret < 0 ? ret : AVERROR_EOF;
229 if (sync[sp & 3] == 'O' &&
230 sync[(sp + 1) & 3] == 'g' &&
231 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
238 }while (i++ < MAX_PAGE_SIZE);
240 if (i >= MAX_PAGE_SIZE){
241 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
242 return AVERROR_INVALIDDATA;
245 if (avio_r8(bc) != 0){ /* version */
246 av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
247 return AVERROR_INVALIDDATA;
252 serial = avio_rl32 (bc);
253 avio_skip(bc, 8); /* seq, crc */
256 idx = ogg_find_stream (ogg, serial);
261 if (ogg->nstreams != 1) {
262 av_log_missing_feature(s, "Changing stream parameters in multistream ogg is", 0);
266 for (n = 0; n < ogg->nstreams; n++) {
267 av_freep(&ogg->streams[n].buf);
268 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
269 av_freep(&ogg->streams[n].private);
273 idx = ogg_new_stream(s, serial, 0);
275 idx = ogg_new_stream(s, serial, 1);
278 av_log (s, AV_LOG_ERROR, "failed to create stream (OOM?)\n");
283 os = ogg->streams + idx;
284 os->page_pos = avio_tell(bc) - 27;
287 ogg_new_buf(ogg, idx);
289 ret = avio_read(bc, os->segments, nsegs);
291 return ret < 0 ? ret : AVERROR_EOF;
297 for (i = 0; i < nsegs; i++)
298 size += os->segments[i];
300 if (flags & OGG_FLAG_CONT || os->incomplete){
302 // If this is the very first segment we started
303 // playback in the middle of a continuation packet.
304 // Discard it since we missed the start of it.
305 while (os->segp < os->nsegs){
306 int seg = os->segments[os->segp++];
311 os->sync_pos = os->page_pos;
315 os->sync_pos = os->page_pos;
318 if (os->bufsize - os->bufpos < size){
319 uint8_t *nb = av_malloc ((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
320 memcpy (nb, os->buf, os->bufpos);
325 ret = avio_read(bc, os->buf + os->bufpos, size);
327 return ret < 0 ? ret : AVERROR_EOF;
333 memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
341 * @brief find the next Ogg packet
342 * @param *str is set to the stream for the packet or -1 if there is
343 * no matching stream, in that case assume all other return
344 * values to be uninitialized.
345 * @return negative value on error or EOF.
347 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
350 struct ogg *ogg = s->priv_data;
352 struct ogg_stream *os;
354 int segp = 0, psize = 0;
356 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
364 ret = ogg_read_page(s, &idx);
369 os = ogg->streams + idx;
371 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
372 idx, os->pstart, os->psize, os->segp, os->nsegs);
376 os->codec = ogg_find_codec (os->buf, os->bufpos);
378 av_log(s, AV_LOG_WARNING, "Codec not found\n");
390 while (os->segp < os->nsegs){
391 int ss = os->segments[os->segp++];
399 if (!complete && os->segp == os->nsegs){
401 // Do not set incomplete for empty packets.
402 // Together with the code in ogg_read_page
403 // that discards all continuation of empty packets
404 // we would get an infinite loop.
405 os->incomplete = !!os->psize;
410 if (os->granule == -1)
411 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
417 os->header = os->codec->header (s, idx);
422 // We have reached the first non-header packet in this stream.
423 // Unfortunately more header packets may still follow for others,
424 // but if we continue with header parsing we may lose data packets.
427 // Update the header state for all streams and
428 // compute the data_offset.
430 s->data_offset = os->sync_pos;
431 for (i = 0; i < ogg->nstreams; i++) {
432 struct ogg_stream *cur_os = ogg->streams + i;
434 // if we have a partial non-header packet, its start is
435 // obviously at or after the data start
436 if (cur_os->incomplete)
437 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
440 os->pstart += os->psize;
446 if (os->codec && os->codec->packet)
447 os->codec->packet (s, idx);
451 *dstart = os->pstart;
455 *fpos = os->sync_pos;
456 os->pstart += os->psize;
458 if(os->pstart == os->bufpos)
459 os->bufpos = os->pstart = 0;
460 os->sync_pos = os->page_pos;
463 // determine whether there are more complete packets in this page
464 // if not, the page's granule will apply to this packet
466 for (i = os->segp; i < os->nsegs; i++)
467 if (os->segments[i] < 255) {
472 if (os->segp == os->nsegs)
478 static int ogg_get_headers(AVFormatContext *s)
480 struct ogg *ogg = s->priv_data;
484 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
487 }while (!ogg->headers);
489 av_dlog(s, "found headers\n");
494 static int ogg_get_length(AVFormatContext *s)
496 struct ogg *ogg = s->priv_data;
505 if (s->duration != AV_NOPTS_VALUE)
508 size = avio_size(s->pb);
511 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
514 avio_seek (s->pb, end, SEEK_SET);
516 while (!ogg_read_page (s, &i)){
517 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
518 ogg->streams[i].codec) {
519 s->streams[i]->duration =
520 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
521 if (s->streams[i]->start_time != AV_NOPTS_VALUE){
522 s->streams[i]->duration -= s->streams[i]->start_time;
523 streams_left-= (ogg->streams[i].got_start==-1);
524 ogg->streams[i].got_start= 1;
525 }else if(!ogg->streams[i].got_start){
526 ogg->streams[i].got_start= -1;
535 avio_seek (s->pb, s->data_offset, SEEK_SET);
537 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
540 pts = ogg_calc_pts(s, i, NULL);
541 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
542 s->streams[i]->duration -= pts;
543 ogg->streams[i].got_start= 1;
545 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start){
546 ogg->streams[i].got_start= 1;
555 static int ogg_read_header(AVFormatContext *s)
557 struct ogg *ogg = s->priv_data;
560 //linear headers seek from start
561 ret = ogg_get_headers(s);
565 for (i = 0; i < ogg->nstreams; i++)
566 if (ogg->streams[i].header < 0)
567 ogg->streams[i].codec = NULL;
569 //linear granulepos seek from end
572 //fill the extradata in the per codec callbacks
576 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
578 struct ogg *ogg = s->priv_data;
579 struct ogg_stream *os = ogg->streams + idx;
580 int64_t pts = AV_NOPTS_VALUE;
583 *dts = AV_NOPTS_VALUE;
585 if (os->lastpts != AV_NOPTS_VALUE) {
587 os->lastpts = AV_NOPTS_VALUE;
589 if (os->lastdts != AV_NOPTS_VALUE) {
592 os->lastdts = AV_NOPTS_VALUE;
595 if (os->granule != -1LL) {
596 if (os->codec && os->codec->granule_is_start)
597 pts = ogg_gptopts(s, idx, os->granule, dts);
599 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
606 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
608 struct ogg *ogg = s->priv_data;
609 struct ogg_stream *os = ogg->streams + idx;
610 if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) {
611 if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
612 os->pflags ^= AV_PKT_FLAG_KEY;
613 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
614 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
619 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
622 struct ogg_stream *os;
625 int64_t fpos, pts, dts;
630 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
633 }while (idx < 0 || !s->streams[idx]);
636 os = ogg->streams + idx;
638 // pflags might not be set until after this
639 pts = ogg_calc_pts(s, idx, &dts);
640 ogg_validate_keyframe(s, idx, pstart, psize);
642 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
644 os->keyframe_seek = 0;
647 ret = av_new_packet(pkt, psize);
650 pkt->stream_index = idx;
651 memcpy (pkt->data, os->buf + pstart, psize);
655 pkt->flags = os->pflags;
656 pkt->duration = os->pduration;
662 static int ogg_read_close(AVFormatContext *s)
664 struct ogg *ogg = s->priv_data;
667 for (i = 0; i < ogg->nstreams; i++){
668 av_free (ogg->streams[i].buf);
669 av_free (ogg->streams[i].private);
671 av_free (ogg->streams);
675 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
676 int64_t *pos_arg, int64_t pos_limit)
678 struct ogg *ogg = s->priv_data;
679 AVIOContext *bc = s->pb;
680 int64_t pts = AV_NOPTS_VALUE;
684 avio_seek(bc, *pos_arg, SEEK_SET);
687 while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
688 if (i == stream_index) {
689 struct ogg_stream *os = ogg->streams + stream_index;
690 pts = ogg_calc_pts(s, i, NULL);
691 ogg_validate_keyframe(s, i, pstart, psize);
692 if (os->pflags & AV_PKT_FLAG_KEY) {
694 } else if (os->keyframe_seek) {
695 // if we had a previous keyframe but no pts for it,
696 // return that keyframe with this pts value.
700 pts = AV_NOPTS_VALUE;
703 if (pts != AV_NOPTS_VALUE)
710 static int ogg_read_seek(AVFormatContext *s, int stream_index,
711 int64_t timestamp, int flags)
713 struct ogg *ogg = s->priv_data;
714 struct ogg_stream *os = ogg->streams + stream_index;
717 av_assert0(stream_index < ogg->nstreams);
718 // Ensure everything is reset even when seeking via
719 // the generated index.
722 // Try seeking to a keyframe first. If this fails (very possible),
723 // av_seek_frame will fall back to ignoring keyframes
724 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
725 && !(flags & AVSEEK_FLAG_ANY))
726 os->keyframe_seek = 1;
728 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
729 os = ogg->streams + stream_index;
731 os->keyframe_seek = 0;
735 static int ogg_probe(AVProbeData *p)
737 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
738 return AVPROBE_SCORE_MAX;
742 AVInputFormat ff_ogg_demuxer = {
744 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
745 .priv_data_size = sizeof(struct ogg),
746 .read_probe = ogg_probe,
747 .read_header = ogg_read_header,
748 .read_packet = ogg_read_packet,
749 .read_close = ogg_read_close,
750 .read_seek = ogg_read_seek,
751 .read_timestamp = ogg_read_timestamp,
753 .flags = AVFMT_GENERIC_INDEX,