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.
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 static const struct ogg_codec * const ogg_codecs[] = {
53 //FIXME We could avoid some structure duplication
55 ogg_save (AVFormatContext * s)
57 struct ogg *ogg = s->priv_data;
58 struct ogg_state *ost =
59 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
61 ost->pos = url_ftell (s->pb);
62 ost->curidx = ogg->curidx;
63 ost->next = ogg->state;
64 ost->nstreams = ogg->nstreams;
65 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
67 for (i = 0; i < ogg->nstreams; i++){
68 struct ogg_stream *os = ogg->streams + i;
69 os->buf = av_malloc (os->bufsize);
70 memset (os->buf, 0, os->bufsize);
71 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
80 ogg_restore (AVFormatContext * s, int discard)
82 struct ogg *ogg = s->priv_data;
83 ByteIOContext *bc = s->pb;
84 struct ogg_state *ost = ogg->state;
90 ogg->state = ost->next;
93 for (i = 0; i < ogg->nstreams; i++)
94 av_free (ogg->streams[i].buf);
96 url_fseek (bc, ost->pos, SEEK_SET);
97 ogg->curidx = ost->curidx;
98 ogg->nstreams = ost->nstreams;
99 memcpy(ogg->streams, ost->streams,
100 ost->nstreams * sizeof(*ogg->streams));
109 ogg_reset (struct ogg * ogg)
113 for (i = 0; i < ogg->nstreams; i++){
114 struct ogg_stream *os = ogg->streams + i;
119 os->lastpts = AV_NOPTS_VALUE;
129 static const struct ogg_codec *
130 ogg_find_codec (uint8_t * buf, int size)
134 for (i = 0; ogg_codecs[i]; i++)
135 if (size >= ogg_codecs[i]->magicsize &&
136 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
137 return ogg_codecs[i];
143 ogg_find_stream (struct ogg * ogg, int serial)
147 for (i = 0; i < ogg->nstreams; i++)
148 if (ogg->streams[i].serial == serial)
155 ogg_new_stream (AVFormatContext * s, uint32_t serial)
158 struct ogg *ogg = s->priv_data;
159 int idx = ogg->nstreams++;
161 struct ogg_stream *os;
163 ogg->streams = av_realloc (ogg->streams,
164 ogg->nstreams * sizeof (*ogg->streams));
165 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
166 os = ogg->streams + idx;
168 os->bufsize = DECODER_BUFFER_SIZE;
169 os->buf = av_malloc(os->bufsize);
172 st = av_new_stream (s, idx);
174 return AVERROR(ENOMEM);
176 av_set_pts_info(st, 64, 1, 1000000);
182 ogg_new_buf(struct ogg *ogg, int idx)
184 struct ogg_stream *os = ogg->streams + idx;
185 uint8_t *nb = av_malloc(os->bufsize);
186 int size = os->bufpos - os->pstart;
188 memcpy(nb, os->buf + os->pstart, size);
199 ogg_read_page (AVFormatContext * s, int *str)
201 ByteIOContext *bc = s->pb;
202 struct ogg *ogg = s->priv_data;
203 struct ogg_stream *os;
214 if (get_buffer (bc, sync, 4) < 4)
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");
236 if (url_fgetc (bc) != 0) /* version */
239 flags = url_fgetc (bc);
241 serial = get_le32 (bc);
244 nsegs = url_fgetc (bc);
246 idx = ogg_find_stream (ogg, serial);
248 idx = ogg_new_stream (s, serial);
253 os = ogg->streams + idx;
256 ogg_new_buf(ogg, idx);
258 if (get_buffer (bc, os->segments, nsegs) < nsegs)
265 for (i = 0; i < nsegs; i++)
266 size += os->segments[i];
268 if (flags & OGG_FLAG_CONT){
270 while (os->segp < os->nsegs){
271 int seg = os->segments[os->segp++];
281 if (os->bufsize - os->bufpos < size){
282 uint8_t *nb = av_malloc (os->bufsize *= 2);
283 memcpy (nb, os->buf, os->bufpos);
288 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
302 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
304 struct ogg *ogg = s->priv_data;
306 struct ogg_stream *os;
308 int segp = 0, psize = 0;
311 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
318 if (ogg_read_page (s, &idx) < 0)
322 os = ogg->streams + idx;
325 av_log (s, AV_LOG_DEBUG,
326 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
327 idx, os->pstart, os->psize, os->segp, os->nsegs);
332 os->codec = ogg_find_codec (os->buf, os->bufpos);
345 while (os->segp < os->nsegs){
346 int ss = os->segments[os->segp++];
354 if (!complete && os->segp == os->nsegs){
360 av_log (s, AV_LOG_DEBUG,
361 "ogg_packet: idx %i, frame size %i, start %i\n",
362 idx, os->psize, os->pstart);
368 int hdr = os->codec->header (s, idx);
370 os->header = os->seq;
375 os->pstart += os->psize;
380 if (os->header > -1 && os->seq > os->header){
383 if (os->codec && os->codec->packet)
384 os->codec->packet (s, idx);
388 *dstart = os->pstart;
391 os->pstart += os->psize;
395 // determine whether there are more complete packets in this page
396 // if not, the page's granule will apply to this packet
398 for (i = os->segp; i < os->nsegs; i++)
399 if (os->segments[i] < 255) {
405 if (os->segp == os->nsegs)
412 ogg_get_headers (AVFormatContext * s)
414 struct ogg *ogg = s->priv_data;
417 if (ogg_packet (s, NULL, NULL, NULL) < 0)
419 }while (!ogg->headers);
422 av_log (s, AV_LOG_DEBUG, "found headers\n");
429 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
431 struct ogg *ogg = s->priv_data;
432 struct ogg_stream *os = ogg->streams + i;
433 uint64_t pts = AV_NOPTS_VALUE;
435 if(os->codec->gptopts){
436 pts = os->codec->gptopts(s, i, gp);
446 ogg_get_length (AVFormatContext * s)
448 struct ogg *ogg = s->priv_data;
452 if(url_is_streamed(s->pb))
456 if (s->duration != AV_NOPTS_VALUE)
459 size = url_fsize(s->pb);
462 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
465 url_fseek (s->pb, end, SEEK_SET);
467 while (!ogg_read_page (s, &i)){
468 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
469 ogg->streams[i].codec)
474 s->streams[idx]->duration =
475 ogg_gptopts (s, idx, ogg->streams[idx].granule);
486 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
488 struct ogg *ogg = s->priv_data;
491 //linear headers seek from start
492 if (ogg_get_headers (s) < 0){
496 for (i = 0; i < ogg->nstreams; i++)
497 if (ogg->streams[i].header < 0)
498 ogg->streams[i].codec = NULL;
500 //linear granulepos seek from end
503 //fill the extradata in the per codec callbacks
509 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
512 struct ogg_stream *os;
518 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
520 }while (idx < 0 || !s->streams[idx]);
523 os = ogg->streams + idx;
526 if (av_new_packet (pkt, psize) < 0)
528 pkt->stream_index = idx;
529 memcpy (pkt->data, os->buf + pstart, psize);
531 if (os->lastpts != AV_NOPTS_VALUE) {
532 pkt->pts = os->lastpts;
533 os->lastpts = AV_NOPTS_VALUE;
536 if (os->granule != -1LL) {
537 if (os->codec && os->codec->granule_is_start)
538 pkt->pts = ogg_gptopts(s, idx, os->granule);
540 os->lastpts = ogg_gptopts(s, idx, os->granule);
543 av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
546 pkt->flags = os->pflags;
547 pkt->duration = os->pduration;
554 ogg_read_close (AVFormatContext * s)
556 struct ogg *ogg = s->priv_data;
559 for (i = 0; i < ogg->nstreams; i++){
560 av_free (ogg->streams[i].buf);
561 av_free (ogg->streams[i].private);
563 av_free (ogg->streams);
569 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
572 struct ogg *ogg = s->priv_data;
573 ByteIOContext *bc = s->pb;
574 int64_t pts = AV_NOPTS_VALUE;
576 url_fseek(bc, *pos_arg, SEEK_SET);
577 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
578 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
579 ogg->streams[i].codec && i == stream_index) {
580 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
581 // FIXME: this is the position of the packet after the one with above
583 *pos_arg = url_ftell(bc);
591 static int ogg_probe(AVProbeData *p)
593 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
594 p->buf[2] == 'g' && p->buf[3] == 'S' &&
595 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
596 return AVPROBE_SCORE_MAX;
601 AVInputFormat ogg_demuxer = {
603 NULL_IF_CONFIG_SMALL("Ogg"),
612 .metadata_conv = ff_vorbiscomment_metadata_conv,