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.
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[] = {
58 //FIXME We could avoid some structure duplication
59 static int ogg_save(AVFormatContext *s)
61 struct ogg *ogg = s->priv_data;
62 struct ogg_state *ost =
63 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
65 ost->pos = avio_tell (s->pb);
66 ost->curidx = ogg->curidx;
67 ost->next = ogg->state;
68 ost->nstreams = ogg->nstreams;
69 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
71 for (i = 0; i < ogg->nstreams; i++){
72 struct ogg_stream *os = ogg->streams + i;
73 os->buf = av_malloc (os->bufsize);
74 memset (os->buf, 0, os->bufsize);
75 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
83 static int ogg_restore(AVFormatContext *s, int discard)
85 struct ogg *ogg = s->priv_data;
86 AVIOContext *bc = s->pb;
87 struct ogg_state *ost = ogg->state;
93 ogg->state = ost->next;
96 struct ogg_stream *old_streams = ogg->streams;
98 for (i = 0; i < ogg->nstreams; i++)
99 av_free (ogg->streams[i].buf);
101 avio_seek (bc, ost->pos, SEEK_SET);
102 ogg->curidx = ost->curidx;
103 ogg->nstreams = ost->nstreams;
104 ogg->streams = av_realloc (ogg->streams,
105 ogg->nstreams * sizeof (*ogg->streams));
108 memcpy(ogg->streams, ost->streams,
109 ost->nstreams * sizeof(*ogg->streams));
111 av_free(old_streams);
121 static int ogg_reset(struct ogg *ogg)
125 for (i = 0; i < ogg->nstreams; i++){
126 struct ogg_stream *os = ogg->streams + i;
131 os->lastpts = AV_NOPTS_VALUE;
132 os->lastdts = AV_NOPTS_VALUE;
145 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
149 for (i = 0; ogg_codecs[i]; i++)
150 if (size >= ogg_codecs[i]->magicsize &&
151 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
152 return ogg_codecs[i];
157 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
160 struct ogg *ogg = s->priv_data;
161 int idx = ogg->nstreams++;
163 struct ogg_stream *os;
165 ogg->streams = av_realloc (ogg->streams,
166 ogg->nstreams * sizeof (*ogg->streams));
167 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
168 os = ogg->streams + idx;
170 os->bufsize = DECODER_BUFFER_SIZE;
171 os->buf = av_malloc(os->bufsize);
175 st = avformat_new_stream(s, NULL);
177 return AVERROR(ENOMEM);
180 av_set_pts_info(st, 64, 1, 1000000);
186 static int ogg_new_buf(struct ogg *ogg, int idx)
188 struct ogg_stream *os = ogg->streams + idx;
189 uint8_t *nb = av_malloc(os->bufsize);
190 int size = os->bufpos - os->pstart;
192 memcpy(nb, os->buf + os->pstart, size);
202 static int ogg_read_page(AVFormatContext *s, int *str)
204 AVIOContext *bc = s->pb;
205 struct ogg *ogg = s->priv_data;
206 struct ogg_stream *os;
215 ret = avio_read(bc, sync, 4);
217 return ret < 0 ? ret : AVERROR_EOF;
222 if (sync[sp & 3] == 'O' &&
223 sync[(sp + 1) & 3] == 'g' &&
224 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
231 }while (i++ < MAX_PAGE_SIZE);
233 if (i >= MAX_PAGE_SIZE){
234 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
235 return AVERROR_INVALIDDATA;
238 if (avio_r8(bc) != 0) /* version */
239 return AVERROR_INVALIDDATA;
243 serial = avio_rl32 (bc);
244 avio_skip(bc, 8); /* seq, crc */
247 idx = ogg_find_stream (ogg, serial);
252 for (n = 0; n < ogg->nstreams; n++) {
253 av_freep(&ogg->streams[n].buf);
254 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
255 av_freep(&ogg->streams[n].private);
259 idx = ogg_new_stream(s, serial, 0);
261 idx = ogg_new_stream(s, serial, 1);
267 os = ogg->streams + idx;
268 os->page_pos = avio_tell(bc) - 27;
271 ogg_new_buf(ogg, idx);
273 ret = avio_read(bc, os->segments, nsegs);
275 return ret < 0 ? ret : AVERROR_EOF;
281 for (i = 0; i < nsegs; i++)
282 size += os->segments[i];
284 if (flags & OGG_FLAG_CONT || os->incomplete){
286 while (os->segp < os->nsegs){
287 int seg = os->segments[os->segp++];
292 os->sync_pos = os->page_pos;
296 os->sync_pos = os->page_pos;
299 if (os->bufsize - os->bufpos < size){
300 uint8_t *nb = av_malloc (os->bufsize *= 2);
301 memcpy (nb, os->buf, os->bufpos);
306 ret = avio_read(bc, os->buf + os->bufpos, size);
308 return ret < 0 ? ret : AVERROR_EOF;
320 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
323 struct ogg *ogg = s->priv_data;
325 struct ogg_stream *os;
327 int segp = 0, psize = 0;
329 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
335 ret = ogg_read_page(s, &idx);
340 os = ogg->streams + idx;
342 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
343 idx, os->pstart, os->psize, os->segp, os->nsegs);
347 os->codec = ogg_find_codec (os->buf, os->bufpos);
349 av_log(s, AV_LOG_WARNING, "Codec not found\n");
361 while (os->segp < os->nsegs){
362 int ss = os->segments[os->segp++];
370 if (!complete && os->segp == os->nsegs){
377 if (os->granule == -1)
378 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
384 os->header = os->codec->header (s, idx);
389 // We have reached the first non-header packet in this stream.
390 // Unfortunately more header packets may still follow for others,
391 // but if we continue with header parsing we may lose data packets.
394 // Update the header state for all streams and
395 // compute the data_offset.
397 s->data_offset = os->sync_pos;
398 for (i = 0; i < ogg->nstreams; i++) {
399 struct ogg_stream *cur_os = ogg->streams + i;
401 // if we have a partial non-header packet, its start is
402 // obviously at or after the data start
403 if (cur_os->incomplete)
404 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
407 os->pstart += os->psize;
413 if (os->codec && os->codec->packet)
414 os->codec->packet (s, idx);
418 *dstart = os->pstart;
422 *fpos = os->sync_pos;
423 os->pstart += os->psize;
425 if(os->pstart == os->bufpos)
426 os->bufpos = os->pstart = 0;
427 os->sync_pos = os->page_pos;
430 // determine whether there are more complete packets in this page
431 // if not, the page's granule will apply to this packet
433 for (i = os->segp; i < os->nsegs; i++)
434 if (os->segments[i] < 255) {
439 if (os->segp == os->nsegs)
445 static int ogg_get_headers(AVFormatContext *s)
447 struct ogg *ogg = s->priv_data;
451 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
454 }while (!ogg->headers);
456 av_dlog(s, "found headers\n");
461 static int ogg_get_length(AVFormatContext *s)
463 struct ogg *ogg = s->priv_data;
472 if (s->duration != AV_NOPTS_VALUE)
475 size = avio_size(s->pb);
478 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
481 avio_seek (s->pb, end, SEEK_SET);
483 while (!ogg_read_page (s, &i)){
484 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
485 ogg->streams[i].codec) {
486 s->streams[i]->duration =
487 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
488 if (s->streams[i]->start_time != AV_NOPTS_VALUE){
489 s->streams[i]->duration -= s->streams[i]->start_time;
490 streams_left-= (ogg->streams[i].got_start==-1);
491 ogg->streams[i].got_start= 1;
492 }else if(!ogg->streams[i].got_start){
493 ogg->streams[i].got_start= -1;
502 avio_seek (s->pb, 0, SEEK_SET);
503 while (!ogg_read_page (s, &i)){
504 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
505 ogg->streams[i].codec) {
506 if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
507 int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
508 if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE)
509 s->streams[i]->duration -= start;
510 ogg->streams[i].got_start= 1;
522 static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
524 struct ogg *ogg = s->priv_data;
527 //linear headers seek from start
528 ret = ogg_get_headers(s);
532 for (i = 0; i < ogg->nstreams; i++)
533 if (ogg->streams[i].header < 0)
534 ogg->streams[i].codec = NULL;
536 //linear granulepos seek from end
539 //fill the extradata in the per codec callbacks
543 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
545 struct ogg *ogg = s->priv_data;
546 struct ogg_stream *os = ogg->streams + idx;
547 int64_t pts = AV_NOPTS_VALUE;
550 *dts = AV_NOPTS_VALUE;
552 if (os->lastpts != AV_NOPTS_VALUE) {
554 os->lastpts = AV_NOPTS_VALUE;
556 if (os->lastdts != AV_NOPTS_VALUE) {
559 os->lastdts = AV_NOPTS_VALUE;
562 if (os->granule != -1LL) {
563 if (os->codec && os->codec->granule_is_start)
564 pts = ogg_gptopts(s, idx, os->granule, dts);
566 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
573 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
576 struct ogg_stream *os;
579 int64_t fpos, pts, dts;
584 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
587 }while (idx < 0 || !s->streams[idx]);
590 os = ogg->streams + idx;
592 // pflags might not be set until after this
593 pts = ogg_calc_pts(s, idx, &dts);
595 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
597 os->keyframe_seek = 0;
600 ret = av_new_packet(pkt, psize);
603 pkt->stream_index = idx;
604 memcpy (pkt->data, os->buf + pstart, psize);
608 pkt->flags = os->pflags;
609 pkt->duration = os->pduration;
615 static int ogg_read_close(AVFormatContext *s)
617 struct ogg *ogg = s->priv_data;
620 for (i = 0; i < ogg->nstreams; i++){
621 av_free (ogg->streams[i].buf);
622 av_free (ogg->streams[i].private);
624 av_free (ogg->streams);
628 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
629 int64_t *pos_arg, int64_t pos_limit)
631 struct ogg *ogg = s->priv_data;
632 AVIOContext *bc = s->pb;
633 int64_t pts = AV_NOPTS_VALUE;
635 avio_seek(bc, *pos_arg, SEEK_SET);
638 while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
639 if (i == stream_index) {
640 struct ogg_stream *os = ogg->streams + stream_index;
641 pts = ogg_calc_pts(s, i, NULL);
642 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
643 pts = AV_NOPTS_VALUE;
645 if (pts != AV_NOPTS_VALUE)
652 static int ogg_read_seek(AVFormatContext *s, int stream_index,
653 int64_t timestamp, int flags)
655 struct ogg *ogg = s->priv_data;
656 struct ogg_stream *os = ogg->streams + stream_index;
659 // Try seeking to a keyframe first. If this fails (very possible),
660 // av_seek_frame will fall back to ignoring keyframes
661 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
662 && !(flags & AVSEEK_FLAG_ANY))
663 os->keyframe_seek = 1;
665 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
666 os = ogg->streams + stream_index;
668 os->keyframe_seek = 0;
672 static int ogg_probe(AVProbeData *p)
674 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
675 return AVPROBE_SCORE_MAX;
679 AVInputFormat ff_ogg_demuxer = {
681 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
682 .priv_data_size = sizeof(struct ogg),
683 .read_probe = ogg_probe,
684 .read_header = ogg_read_header,
685 .read_packet = ogg_read_packet,
686 .read_close = ogg_read_close,
687 .read_seek = ogg_read_seek,
688 .read_timestamp = ogg_read_timestamp,
690 .flags = AVFMT_GENERIC_INDEX,