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 ogg_codec_t *ogg_codecs[] = {
45 #if 0 // CONFIG_ENCODERS
47 ogg_write_header (AVFormatContext * avfcontext)
52 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
58 ogg_write_trailer (AVFormatContext * avfcontext)
63 static AVOutputFormat ogg_oformat = {
75 #endif //CONFIG_ENCODERS
77 //FIXME We could avoid some structure duplication
79 ogg_save (AVFormatContext * s)
81 ogg_t *ogg = s->priv_data;
83 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
85 ost->pos = url_ftell (&s->pb);;
86 ost->curidx = ogg->curidx;
87 ost->next = ogg->state;
88 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
90 for (i = 0; i < ogg->nstreams; i++){
91 ogg_stream_t *os = ogg->streams + i;
92 os->buf = av_malloc (os->bufsize);
93 memset (os->buf, 0, os->bufsize);
94 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
103 ogg_restore (AVFormatContext * s, int discard)
105 ogg_t *ogg = s->priv_data;
106 ByteIOContext *bc = &s->pb;
107 ogg_state_t *ost = ogg->state;
113 ogg->state = ost->next;
116 for (i = 0; i < ogg->nstreams; i++)
117 av_free (ogg->streams[i].buf);
119 url_fseek (bc, ost->pos, SEEK_SET);
120 ogg->curidx = ost->curidx;
121 memcpy (ogg->streams, ost->streams,
122 ogg->nstreams * sizeof (*ogg->streams));
131 ogg_reset (ogg_t * ogg)
135 for (i = 0; i < ogg->nstreams; i++){
136 ogg_stream_t *os = ogg->streams + i;
152 ogg_find_codec (uint8_t * buf, int size)
156 for (i = 0; ogg_codecs[i]; i++)
157 if (size >= ogg_codecs[i]->magicsize &&
158 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
159 return ogg_codecs[i];
165 ogg_find_stream (ogg_t * ogg, int serial)
169 for (i = 0; i < ogg->nstreams; i++)
170 if (ogg->streams[i].serial == serial)
177 ogg_new_stream (AVFormatContext * s, uint32_t serial)
180 ogg_t *ogg = s->priv_data;
181 int idx = ogg->nstreams++;
185 ogg->streams = av_realloc (ogg->streams,
186 ogg->nstreams * sizeof (*ogg->streams));
187 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
188 os = ogg->streams + idx;
190 os->bufsize = DECODER_BUFFER_SIZE;
191 os->buf = av_malloc (os->bufsize);
192 memset (os->buf, 0, os->bufsize);
195 st = av_new_stream (s, idx);
197 return AVERROR_NOMEM;
199 av_set_pts_info(st, 64, 1, 1000000);
206 ogg_read_page (AVFormatContext * s, int *str)
208 ByteIOContext *bc = &s->pb;
209 ogg_t *ogg = s->priv_data;
221 if (get_buffer (bc, sync, 4) < 4)
227 if (sync[sp & 3] == 'O' &&
228 sync[(sp + 1) & 3] == 'g' &&
229 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
236 }while (i++ < MAX_PAGE_SIZE);
238 if (i >= MAX_PAGE_SIZE){
239 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
243 if (url_fgetc (bc) != 0) /* version */
246 flags = url_fgetc (bc);
248 serial = get_le32 (bc);
251 nsegs = url_fgetc (bc);
253 idx = ogg_find_stream (ogg, serial);
255 idx = ogg_new_stream (s, serial);
260 os = ogg->streams + idx;
262 if (get_buffer (bc, os->segments, nsegs) < nsegs)
269 for (i = 0; i < nsegs; i++)
270 size += os->segments[i];
272 if (flags & OGG_FLAG_CONT){
274 while (os->segp < os->nsegs){
275 int seg = os->segments[os->segp++];
285 if (os->bufsize - os->bufpos < size){
286 uint8_t *nb = av_malloc (os->bufsize *= 2);
287 memset (nb, 0, os->bufsize);
288 memcpy (nb, os->buf, os->bufpos);
293 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
296 os->lastgp = os->granule;
308 ogg_packet (AVFormatContext * s, int *str)
310 ogg_t *ogg = s->priv_data;
314 int segp = 0, psize = 0;
317 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
324 if (ogg_read_page (s, &idx) < 0)
328 os = ogg->streams + idx;
331 av_log (s, AV_LOG_DEBUG,
332 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
333 idx, os->pstart, os->psize, os->segp, os->nsegs);
338 os->codec = ogg_find_codec (os->buf, os->bufpos);
351 while (os->segp < os->nsegs){
352 int ss = os->segments[os->segp++];
360 if (!complete && os->segp == os->nsegs){
361 uint8_t *nb = av_malloc (os->bufsize);
362 int size = os->bufpos - os->pstart;
363 memset (nb, 0, os->bufsize);
364 memcpy (nb, os->buf + os->pstart, size);
374 av_log (s, AV_LOG_DEBUG,
375 "ogg_packet: idx %i, frame size %i, start %i\n",
376 idx, os->psize, os->pstart);
382 int hdr = os->codec->header (s, idx);
384 os->header = os->seq;
389 os->pstart += os->psize;
394 if (os->header > -1 && os->seq > os->header){
395 if (os->codec && os->codec->packet)
396 os->codec->packet (s, idx);
402 if (os->segp == os->nsegs)
409 ogg_get_headers (AVFormatContext * s)
411 ogg_t *ogg = s->priv_data;
414 if (ogg_packet (s, NULL) < 0)
416 }while (!ogg->headers);
419 av_log (s, AV_LOG_DEBUG, "found headers\n");
426 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
428 AVStream *st = s->streams[i];
429 AVCodecContext *codec = &st->codec;
430 uint64_t pts = AV_NOPTS_VALUE;
432 if (codec->codec_type == CODEC_TYPE_AUDIO){
433 pts = gp * 1000000LL / codec->sample_rate;
434 }else if (codec->codec_type == CODEC_TYPE_VIDEO){
436 pts = gp * 1000000LL / codec->sample_rate;
437 // pts = gp * st->video.frame_rate.den * 27000000LL /
438 // st->video.frame_rate.num;
446 ogg_get_length (AVFormatContext * s)
448 ogg_t *ogg = s->priv_data;
449 URLContext *h = url_fileno (&s->pb);
451 //FIXME: get the right ctx flag to know if is seekable or not
452 // if(ogg->f->flags & URL_FLAG_STREAMED)
456 if (s->duration != AV_NOPTS_VALUE)
460 url_seek (h, -MAX_PAGE_SIZE, SEEK_END);
462 while (!ogg_read_page (s, &i)){
463 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
468 s->streams[idx]->duration =
469 ogg_gptopts (s, idx, ogg->streams[idx].granule);
472 ogg->size = url_filesize(h);
480 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
482 ogg_t *ogg = s->priv_data;
484 //linear headers seek from start
485 if (ogg_get_headers (s) < 0){
489 //linear granulepos seek from end
492 //fill the extradata in the per codec callbacks
498 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
506 if (ogg_packet (s, &idx) < 0)
508 }while (idx < 0 || !s->streams[idx]);
511 os = ogg->streams + idx;
514 if (av_new_packet (pkt, os->psize) < 0)
516 pkt->stream_index = idx;
517 memcpy (pkt->data, os->buf + os->pstart, os->psize);
518 if (os->lastgp != -1LL){
519 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
523 os->pstart += os->psize;
530 ogg_read_close (AVFormatContext * s)
532 ogg_t *ogg = s->priv_data;
535 for (i = 0; i < ogg->nstreams; i++){
536 av_free (ogg->streams[i].buf);
537 av_freep (&s->streams[i]->codec.extradata);
539 av_free (ogg->streams);
545 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
548 ogg_t *ogg = s->priv_data;
549 ByteIOContext *bc = &s->pb;
550 uint64_t min = 0, max = ogg->size;
551 uint64_t tmin = 0, tmax = s->duration;
552 int64_t pts = AV_NOPTS_VALUE;
557 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
560 url_fseek (bc, p, SEEK_SET);
562 while (!ogg_read_page (s, &i)){
563 if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1)
570 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
573 if (ABS (pts - target_ts) < 1000000LL)
576 if (pts > target_ts){
585 if (ABS (pts - target_ts) < 1000000LL){
590 pts = AV_NOPTS_VALUE;
598 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
600 pos = url_ftell (&s->pb);
601 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
608 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
611 ogg_t *ogg = s->priv_data;
612 ByteIOContext *bc = &s->pb;
616 return AV_NOPTS_VALUE;
622 static AVInputFormat ogg_iformat = {
631 // ogg_read_timestamp,
638 #if 0 // CONFIG_ENCODERS
639 av_register_output_format (&ogg_oformat);
641 av_register_input_format (&ogg_iformat);