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[] = {
55 //FIXME We could avoid some structure duplication
57 ogg_save (AVFormatContext * s)
59 struct ogg *ogg = s->priv_data;
60 struct ogg_state *ost =
61 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
63 ost->pos = url_ftell (s->pb);
64 ost->curidx = ogg->curidx;
65 ost->next = ogg->state;
66 ost->nstreams = ogg->nstreams;
67 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
69 for (i = 0; i < ogg->nstreams; i++){
70 struct ogg_stream *os = ogg->streams + i;
71 os->buf = av_malloc (os->bufsize);
72 memset (os->buf, 0, os->bufsize);
73 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
82 ogg_restore (AVFormatContext * s, int discard)
84 struct ogg *ogg = s->priv_data;
85 ByteIOContext *bc = s->pb;
86 struct ogg_state *ost = ogg->state;
92 ogg->state = ost->next;
95 for (i = 0; i < ogg->nstreams; i++)
96 av_free (ogg->streams[i].buf);
98 url_fseek (bc, ost->pos, SEEK_SET);
99 ogg->curidx = ost->curidx;
100 ogg->nstreams = ost->nstreams;
101 memcpy(ogg->streams, ost->streams,
102 ost->nstreams * sizeof(*ogg->streams));
111 ogg_reset (struct ogg * ogg)
115 for (i = 0; i < ogg->nstreams; i++){
116 struct ogg_stream *os = ogg->streams + i;
121 os->lastpts = AV_NOPTS_VALUE;
122 os->lastdts = AV_NOPTS_VALUE;
132 static const struct ogg_codec *
133 ogg_find_codec (uint8_t * buf, int size)
137 for (i = 0; ogg_codecs[i]; i++)
138 if (size >= ogg_codecs[i]->magicsize &&
139 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
140 return ogg_codecs[i];
146 ogg_find_stream (struct ogg * ogg, int serial)
150 for (i = 0; i < ogg->nstreams; i++)
151 if (ogg->streams[i].serial == serial)
158 ogg_new_stream (AVFormatContext * s, uint32_t serial)
161 struct ogg *ogg = s->priv_data;
162 int idx = ogg->nstreams++;
164 struct ogg_stream *os;
166 ogg->streams = av_realloc (ogg->streams,
167 ogg->nstreams * sizeof (*ogg->streams));
168 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
169 os = ogg->streams + idx;
171 os->bufsize = DECODER_BUFFER_SIZE;
172 os->buf = av_malloc(os->bufsize);
175 st = av_new_stream (s, idx);
177 return AVERROR(ENOMEM);
179 av_set_pts_info(st, 64, 1, 1000000);
185 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);
202 ogg_read_page (AVFormatContext * s, int *str)
204 ByteIOContext *bc = s->pb;
205 struct ogg *ogg = s->priv_data;
206 struct ogg_stream *os;
217 if (get_buffer (bc, sync, 4) < 4)
223 if (sync[sp & 3] == 'O' &&
224 sync[(sp + 1) & 3] == 'g' &&
225 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
232 }while (i++ < MAX_PAGE_SIZE);
234 if (i >= MAX_PAGE_SIZE){
235 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
239 if (url_fgetc (bc) != 0) /* version */
242 flags = url_fgetc (bc);
244 serial = get_le32 (bc);
247 nsegs = url_fgetc (bc);
249 idx = ogg_find_stream (ogg, serial);
251 idx = ogg_new_stream (s, serial);
256 os = ogg->streams + idx;
259 ogg_new_buf(ogg, idx);
261 if (get_buffer (bc, os->segments, nsegs) < nsegs)
268 for (i = 0; i < nsegs; i++)
269 size += os->segments[i];
271 if (flags & OGG_FLAG_CONT){
273 while (os->segp < os->nsegs){
274 int seg = os->segments[os->segp++];
284 if (os->bufsize - os->bufpos < size){
285 uint8_t *nb = av_malloc (os->bufsize *= 2);
286 memcpy (nb, os->buf, os->bufpos);
291 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
305 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
307 struct ogg *ogg = s->priv_data;
309 struct ogg_stream *os;
311 int segp = 0, psize = 0;
314 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
321 if (ogg_read_page (s, &idx) < 0)
325 os = ogg->streams + idx;
328 av_log (s, AV_LOG_DEBUG,
329 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
330 idx, os->pstart, os->psize, os->segp, os->nsegs);
335 os->codec = ogg_find_codec (os->buf, os->bufpos);
348 while (os->segp < os->nsegs){
349 int ss = os->segments[os->segp++];
357 if (!complete && os->segp == os->nsegs){
363 av_log (s, AV_LOG_DEBUG,
364 "ogg_packet: idx %i, frame size %i, start %i\n",
365 idx, os->psize, os->pstart);
371 int hdr = os->codec->header (s, idx);
373 os->header = os->seq;
378 os->pstart += os->psize;
383 if (os->header > -1 && os->seq > os->header){
386 if (os->codec && os->codec->packet)
387 os->codec->packet (s, idx);
391 *dstart = os->pstart;
394 os->pstart += os->psize;
398 // determine whether there are more complete packets in this page
399 // if not, the page's granule will apply to this packet
401 for (i = os->segp; i < os->nsegs; i++)
402 if (os->segments[i] < 255) {
408 if (os->segp == os->nsegs)
415 ogg_get_headers (AVFormatContext * s)
417 struct ogg *ogg = s->priv_data;
420 if (ogg_packet (s, NULL, NULL, NULL) < 0)
422 }while (!ogg->headers);
425 av_log (s, AV_LOG_DEBUG, "found headers\n");
432 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp, int64_t *dts)
434 struct ogg *ogg = s->priv_data;
435 struct ogg_stream *os = ogg->streams + i;
436 uint64_t pts = AV_NOPTS_VALUE;
438 if(os->codec->gptopts){
439 pts = os->codec->gptopts(s, i, gp, dts);
451 ogg_get_length (AVFormatContext * s)
453 struct ogg *ogg = s->priv_data;
457 if(url_is_streamed(s->pb))
461 if (s->duration != AV_NOPTS_VALUE)
464 size = url_fsize(s->pb);
467 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
470 url_fseek (s->pb, end, SEEK_SET);
472 while (!ogg_read_page (s, &i)){
473 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
474 ogg->streams[i].codec)
479 s->streams[idx]->duration =
480 ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
491 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
493 struct ogg *ogg = s->priv_data;
496 //linear headers seek from start
497 if (ogg_get_headers (s) < 0){
501 for (i = 0; i < ogg->nstreams; i++)
502 if (ogg->streams[i].header < 0)
503 ogg->streams[i].codec = NULL;
505 //linear granulepos seek from end
508 //fill the extradata in the per codec callbacks
514 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
517 struct ogg_stream *os;
523 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
525 }while (idx < 0 || !s->streams[idx]);
528 os = ogg->streams + idx;
531 if (av_new_packet (pkt, psize) < 0)
533 pkt->stream_index = idx;
534 memcpy (pkt->data, os->buf + pstart, psize);
536 if (os->lastpts != AV_NOPTS_VALUE) {
537 pkt->pts = os->lastpts;
538 os->lastpts = AV_NOPTS_VALUE;
540 if (os->lastdts != AV_NOPTS_VALUE) {
541 pkt->dts = os->lastdts;
542 os->lastdts = AV_NOPTS_VALUE;
545 if (os->granule != -1LL) {
546 if (os->codec && os->codec->granule_is_start)
547 pkt->pts = ogg_gptopts(s, idx, os->granule, &pkt->dts);
549 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
552 av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
555 pkt->flags = os->pflags;
556 pkt->duration = os->pduration;
563 ogg_read_close (AVFormatContext * s)
565 struct ogg *ogg = s->priv_data;
568 for (i = 0; i < ogg->nstreams; i++){
569 av_free (ogg->streams[i].buf);
570 av_free (ogg->streams[i].private);
572 av_free (ogg->streams);
578 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
581 struct ogg *ogg = s->priv_data;
582 ByteIOContext *bc = s->pb;
583 int64_t pts = AV_NOPTS_VALUE;
585 url_fseek(bc, *pos_arg, SEEK_SET);
586 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
587 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
588 ogg->streams[i].codec && i == stream_index) {
589 pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
590 // FIXME: this is the position of the packet after the one with above
592 *pos_arg = url_ftell(bc);
600 static int ogg_probe(AVProbeData *p)
602 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
603 p->buf[2] == 'g' && p->buf[3] == 'S' &&
604 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
605 return AVPROBE_SCORE_MAX;
610 AVInputFormat ogg_demuxer = {
612 NULL_IF_CONFIG_SMALL("Ogg"),
621 .metadata_conv = ff_vorbiscomment_metadata_conv,