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[] = {
56 //FIXME We could avoid some structure duplication
58 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 = url_ftell (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);
83 ogg_restore (AVFormatContext * s, int discard)
85 struct ogg *ogg = s->priv_data;
86 ByteIOContext *bc = s->pb;
87 struct ogg_state *ost = ogg->state;
93 ogg->state = ost->next;
96 for (i = 0; i < ogg->nstreams; i++)
97 av_free (ogg->streams[i].buf);
99 url_fseek (bc, ost->pos, SEEK_SET);
100 ogg->curidx = ost->curidx;
101 ogg->nstreams = ost->nstreams;
102 memcpy(ogg->streams, ost->streams,
103 ost->nstreams * sizeof(*ogg->streams));
112 ogg_reset (struct ogg * ogg)
116 for (i = 0; i < ogg->nstreams; i++){
117 struct ogg_stream *os = ogg->streams + i;
122 os->lastpts = AV_NOPTS_VALUE;
123 os->lastdts = AV_NOPTS_VALUE;
136 static const struct ogg_codec *
137 ogg_find_codec (uint8_t * buf, int size)
141 for (i = 0; ogg_codecs[i]; i++)
142 if (size >= ogg_codecs[i]->magicsize &&
143 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
144 return ogg_codecs[i];
150 ogg_new_stream (AVFormatContext * s, uint32_t serial)
153 struct ogg *ogg = s->priv_data;
154 int idx = ogg->nstreams++;
156 struct ogg_stream *os;
158 ogg->streams = av_realloc (ogg->streams,
159 ogg->nstreams * sizeof (*ogg->streams));
160 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
161 os = ogg->streams + idx;
163 os->bufsize = DECODER_BUFFER_SIZE;
164 os->buf = av_malloc(os->bufsize);
167 st = av_new_stream (s, idx);
169 return AVERROR(ENOMEM);
171 av_set_pts_info(st, 64, 1, 1000000);
177 ogg_new_buf(struct ogg *ogg, int idx)
179 struct ogg_stream *os = ogg->streams + idx;
180 uint8_t *nb = av_malloc(os->bufsize);
181 int size = os->bufpos - os->pstart;
183 memcpy(nb, os->buf + os->pstart, size);
194 ogg_read_page (AVFormatContext * s, int *str)
196 ByteIOContext *bc = s->pb;
197 struct ogg *ogg = s->priv_data;
198 struct ogg_stream *os;
209 if (get_buffer (bc, sync, 4) < 4)
215 if (sync[sp & 3] == 'O' &&
216 sync[(sp + 1) & 3] == 'g' &&
217 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
224 }while (i++ < MAX_PAGE_SIZE);
226 if (i >= MAX_PAGE_SIZE){
227 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
231 if (url_fgetc (bc) != 0) /* version */
234 flags = url_fgetc (bc);
236 serial = get_le32 (bc);
239 nsegs = url_fgetc (bc);
241 idx = ogg_find_stream (ogg, serial);
243 idx = ogg_new_stream (s, serial);
248 os = ogg->streams + idx;
249 os->page_pos = url_ftell(bc) - 27;
252 ogg_new_buf(ogg, idx);
254 if (get_buffer (bc, os->segments, nsegs) < nsegs)
261 for (i = 0; i < nsegs; i++)
262 size += os->segments[i];
264 if (flags & OGG_FLAG_CONT || os->incomplete){
266 while (os->segp < os->nsegs){
267 int seg = os->segments[os->segp++];
272 os->sync_pos = os->page_pos;
276 os->sync_pos = os->page_pos;
279 if (os->bufsize - os->bufpos < size){
280 uint8_t *nb = av_malloc (os->bufsize *= 2);
281 memcpy (nb, os->buf, os->bufpos);
286 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
300 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
302 struct ogg *ogg = s->priv_data;
304 struct ogg_stream *os;
306 int segp = 0, psize = 0;
309 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
316 if (ogg_read_page (s, &idx) < 0)
320 os = ogg->streams + idx;
323 av_log (s, AV_LOG_DEBUG,
324 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
325 idx, os->pstart, os->psize, os->segp, os->nsegs);
330 os->codec = ogg_find_codec (os->buf, os->bufpos);
343 while (os->segp < os->nsegs){
344 int ss = os->segments[os->segp++];
352 if (!complete && os->segp == os->nsegs){
359 av_log (s, AV_LOG_DEBUG,
360 "ogg_packet: idx %i, frame size %i, start %i\n",
361 idx, os->psize, os->pstart);
368 int hdr = os->codec->header (s, idx);
369 os->header = os->seq;
374 s->data_offset = os->sync_pos;
376 os->pstart += os->psize;
381 if (os->header > -1 && os->seq > os->header){
384 if (os->codec && os->codec->packet)
385 os->codec->packet (s, idx);
389 *dstart = os->pstart;
393 *fpos = os->sync_pos;
394 os->pstart += os->psize;
396 os->sync_pos = os->page_pos;
399 // determine whether there are more complete packets in this page
400 // if not, the page's granule will apply to this packet
402 for (i = os->segp; i < os->nsegs; i++)
403 if (os->segments[i] < 255) {
409 if (os->segp == os->nsegs)
416 ogg_get_headers (AVFormatContext * s)
418 struct ogg *ogg = s->priv_data;
421 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
423 }while (!ogg->headers);
426 av_log (s, AV_LOG_DEBUG, "found headers\n");
433 ogg_get_length (AVFormatContext * s)
435 struct ogg *ogg = s->priv_data;
439 if(url_is_streamed(s->pb))
443 if (s->duration != AV_NOPTS_VALUE)
446 size = url_fsize(s->pb);
449 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
452 url_fseek (s->pb, end, SEEK_SET);
454 while (!ogg_read_page (s, &i)){
455 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
456 ogg->streams[i].codec)
461 s->streams[idx]->duration =
462 ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
463 if (s->streams[idx]->start_time != AV_NOPTS_VALUE)
464 s->streams[idx]->duration -= s->streams[idx]->start_time;
475 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
477 struct ogg *ogg = s->priv_data;
480 //linear headers seek from start
481 if (ogg_get_headers (s) < 0){
485 for (i = 0; i < ogg->nstreams; i++)
486 if (ogg->streams[i].header < 0)
487 ogg->streams[i].codec = NULL;
489 //linear granulepos seek from end
492 //fill the extradata in the per codec callbacks
496 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
498 struct ogg *ogg = s->priv_data;
499 struct ogg_stream *os = ogg->streams + idx;
500 int64_t pts = AV_NOPTS_VALUE;
503 *dts = AV_NOPTS_VALUE;
505 if (os->lastpts != AV_NOPTS_VALUE) {
507 os->lastpts = AV_NOPTS_VALUE;
509 if (os->lastdts != AV_NOPTS_VALUE) {
512 os->lastdts = AV_NOPTS_VALUE;
515 if (os->granule != -1LL) {
516 if (os->codec && os->codec->granule_is_start)
517 pts = ogg_gptopts(s, idx, os->granule, dts);
519 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
522 av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
528 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
531 struct ogg_stream *os;
538 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
540 }while (idx < 0 || !s->streams[idx]);
543 os = ogg->streams + idx;
546 if (av_new_packet (pkt, psize) < 0)
548 pkt->stream_index = idx;
549 memcpy (pkt->data, os->buf + pstart, psize);
551 pkt->pts = ogg_calc_pts(s, idx, &pkt->dts);
552 pkt->flags = os->pflags;
553 pkt->duration = os->pduration;
561 ogg_read_close (AVFormatContext * s)
563 struct ogg *ogg = s->priv_data;
566 for (i = 0; i < ogg->nstreams; i++){
567 av_free (ogg->streams[i].buf);
568 av_free (ogg->streams[i].private);
570 av_free (ogg->streams);
576 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
579 struct ogg *ogg = s->priv_data;
580 ByteIOContext *bc = s->pb;
581 int64_t pts = AV_NOPTS_VALUE;
583 url_fseek(bc, *pos_arg, SEEK_SET);
586 while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
587 if (i == stream_index) {
588 pts = ogg_calc_pts(s, i, NULL);
590 if (pts != AV_NOPTS_VALUE)
597 static int ogg_probe(AVProbeData *p)
599 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
600 p->buf[2] == 'g' && p->buf[3] == 'S' &&
601 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
602 return AVPROBE_SCORE_MAX;
607 AVInputFormat ogg_demuxer = {
609 NULL_IF_CONFIG_SMALL("Ogg"),
618 .metadata_conv = ff_vorbiscomment_metadata_conv,