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 = avformat_new_stream(s, NULL);
176 return AVERROR(ENOMEM);
179 av_set_pts_info(st, 64, 1, 1000000);
185 static int ogg_new_buf(struct ogg *ogg, int idx)
187 struct ogg_stream *os = ogg->streams + idx;
188 uint8_t *nb = av_malloc(os->bufsize);
189 int size = os->bufpos - os->pstart;
191 memcpy(nb, os->buf + os->pstart, size);
201 static int ogg_read_page(AVFormatContext *s, int *str)
203 AVIOContext *bc = s->pb;
204 struct ogg *ogg = s->priv_data;
205 struct ogg_stream *os;
214 ret = avio_read(bc, sync, 4);
216 return ret < 0 ? ret : AVERROR_EOF;
221 if (sync[sp & 3] == 'O' &&
222 sync[(sp + 1) & 3] == 'g' &&
223 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
230 }while (i++ < MAX_PAGE_SIZE);
232 if (i >= MAX_PAGE_SIZE){
233 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
234 return AVERROR_INVALIDDATA;
237 if (avio_r8(bc) != 0) /* version */
238 return AVERROR_INVALIDDATA;
242 serial = avio_rl32 (bc);
243 avio_skip(bc, 8); /* seq, crc */
246 idx = ogg_find_stream (ogg, serial);
251 for (n = 0; n < ogg->nstreams; n++) {
252 av_freep(&ogg->streams[n].buf);
253 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
254 av_freep(&ogg->streams[n].private);
258 idx = ogg_new_stream(s, serial, 0);
260 idx = ogg_new_stream(s, serial, 1);
266 os = ogg->streams + idx;
267 os->page_pos = avio_tell(bc) - 27;
270 ogg_new_buf(ogg, idx);
272 ret = avio_read(bc, os->segments, nsegs);
274 return ret < 0 ? ret : AVERROR_EOF;
280 for (i = 0; i < nsegs; i++)
281 size += os->segments[i];
283 if (flags & OGG_FLAG_CONT || os->incomplete){
285 while (os->segp < os->nsegs){
286 int seg = os->segments[os->segp++];
291 os->sync_pos = os->page_pos;
295 os->sync_pos = os->page_pos;
298 if (os->bufsize - os->bufpos < size){
299 uint8_t *nb = av_malloc (os->bufsize *= 2);
300 memcpy (nb, os->buf, os->bufpos);
305 ret = avio_read(bc, os->buf + os->bufpos, size);
307 return ret < 0 ? ret : AVERROR_EOF;
319 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
322 struct ogg *ogg = s->priv_data;
324 struct ogg_stream *os;
326 int segp = 0, psize = 0;
328 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
334 ret = ogg_read_page(s, &idx);
339 os = ogg->streams + idx;
341 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
342 idx, os->pstart, os->psize, os->segp, os->nsegs);
346 os->codec = ogg_find_codec (os->buf, os->bufpos);
348 av_log(s, AV_LOG_WARNING, "Codec not found\n");
360 while (os->segp < os->nsegs){
361 int ss = os->segments[os->segp++];
369 if (!complete && os->segp == os->nsegs){
376 if (os->granule == -1)
377 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
383 os->header = os->codec->header (s, idx);
388 // We have reached the first non-header packet in this stream.
389 // Unfortunately more header packets may still follow for others,
390 // but if we continue with header parsing we may lose data packets.
393 // Update the header state for all streams and
394 // compute the data_offset.
396 s->data_offset = os->sync_pos;
397 for (i = 0; i < ogg->nstreams; i++) {
398 struct ogg_stream *cur_os = ogg->streams + i;
400 // if we have a partial non-header packet, its start is
401 // obviously at or after the data start
402 if (cur_os->incomplete)
403 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
406 os->pstart += os->psize;
412 if (os->codec && os->codec->packet)
413 os->codec->packet (s, idx);
417 *dstart = os->pstart;
421 *fpos = os->sync_pos;
422 os->pstart += os->psize;
424 if(os->pstart == os->bufpos)
425 os->bufpos = os->pstart = 0;
426 os->sync_pos = os->page_pos;
429 // determine whether there are more complete packets in this page
430 // if not, the page's granule will apply to this packet
432 for (i = os->segp; i < os->nsegs; i++)
433 if (os->segments[i] < 255) {
438 if (os->segp == os->nsegs)
444 static int ogg_get_headers(AVFormatContext *s)
446 struct ogg *ogg = s->priv_data;
450 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
453 }while (!ogg->headers);
455 av_dlog(s, "found headers\n");
460 static int ogg_get_length(AVFormatContext *s)
462 struct ogg *ogg = s->priv_data;
471 if (s->duration != AV_NOPTS_VALUE)
474 size = avio_size(s->pb);
477 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
480 avio_seek (s->pb, end, SEEK_SET);
482 while (!ogg_read_page (s, &i)){
483 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
484 ogg->streams[i].codec) {
485 s->streams[i]->duration =
486 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
487 if (s->streams[i]->start_time != AV_NOPTS_VALUE){
488 s->streams[i]->duration -= s->streams[i]->start_time;
489 streams_left-= (ogg->streams[i].got_start==-1);
490 ogg->streams[i].got_start= 1;
491 }else if(!ogg->streams[i].got_start){
492 ogg->streams[i].got_start= -1;
501 avio_seek (s->pb, 0, SEEK_SET);
502 while (!ogg_read_page (s, &i)){
503 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
504 ogg->streams[i].codec) {
505 if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
506 int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
507 if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE)
508 s->streams[i]->duration -= start;
509 ogg->streams[i].got_start= 1;
521 static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
523 struct ogg *ogg = s->priv_data;
526 //linear headers seek from start
527 ret = ogg_get_headers(s);
531 for (i = 0; i < ogg->nstreams; i++)
532 if (ogg->streams[i].header < 0)
533 ogg->streams[i].codec = NULL;
535 //linear granulepos seek from end
538 //fill the extradata in the per codec callbacks
542 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
544 struct ogg *ogg = s->priv_data;
545 struct ogg_stream *os = ogg->streams + idx;
546 int64_t pts = AV_NOPTS_VALUE;
549 *dts = AV_NOPTS_VALUE;
551 if (os->lastpts != AV_NOPTS_VALUE) {
553 os->lastpts = AV_NOPTS_VALUE;
555 if (os->lastdts != AV_NOPTS_VALUE) {
558 os->lastdts = AV_NOPTS_VALUE;
561 if (os->granule != -1LL) {
562 if (os->codec && os->codec->granule_is_start)
563 pts = ogg_gptopts(s, idx, os->granule, dts);
565 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
572 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
575 struct ogg_stream *os;
578 int64_t fpos, pts, dts;
583 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
586 }while (idx < 0 || !s->streams[idx]);
589 os = ogg->streams + idx;
591 // pflags might not be set until after this
592 pts = ogg_calc_pts(s, idx, &dts);
594 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
596 os->keyframe_seek = 0;
599 ret = av_new_packet(pkt, psize);
602 pkt->stream_index = idx;
603 memcpy (pkt->data, os->buf + pstart, psize);
607 pkt->flags = os->pflags;
608 pkt->duration = os->pduration;
614 static int ogg_read_close(AVFormatContext *s)
616 struct ogg *ogg = s->priv_data;
619 for (i = 0; i < ogg->nstreams; i++){
620 av_free (ogg->streams[i].buf);
621 av_free (ogg->streams[i].private);
623 av_free (ogg->streams);
627 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
628 int64_t *pos_arg, int64_t pos_limit)
630 struct ogg *ogg = s->priv_data;
631 AVIOContext *bc = s->pb;
632 int64_t pts = AV_NOPTS_VALUE;
634 avio_seek(bc, *pos_arg, SEEK_SET);
637 while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
638 if (i == stream_index) {
639 struct ogg_stream *os = ogg->streams + stream_index;
640 pts = ogg_calc_pts(s, i, NULL);
641 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
642 pts = AV_NOPTS_VALUE;
644 if (pts != AV_NOPTS_VALUE)
651 static int ogg_read_seek(AVFormatContext *s, int stream_index,
652 int64_t timestamp, int flags)
654 struct ogg *ogg = s->priv_data;
655 struct ogg_stream *os = ogg->streams + stream_index;
658 // Try seeking to a keyframe first. If this fails (very possible),
659 // av_seek_frame will fall back to ignoring keyframes
660 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
661 && !(flags & AVSEEK_FLAG_ANY))
662 os->keyframe_seek = 1;
664 ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
665 os = ogg->streams + stream_index;
667 os->keyframe_seek = 0;
671 static int ogg_probe(AVProbeData *p)
673 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
674 return AVPROBE_SCORE_MAX;
678 AVInputFormat ff_ogg_demuxer = {
680 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
681 .priv_data_size = sizeof(struct ogg),
682 .read_probe = ogg_probe,
683 .read_header = ogg_read_header,
684 .read_packet = ogg_read_packet,
685 .read_close = ogg_read_close,
686 .read_seek = ogg_read_seek,
687 .read_timestamp = ogg_read_timestamp,
689 .flags = AVFMT_GENERIC_INDEX,