Remove debug line.
[FFMpeg-mirror/ordered_chapters.git] / libavformat / ogg2.c
blob64e7733d56915a44f204adfbff4566b080748116
1 /*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
6 */
8 /**
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.
30 **/
33 #include <stdio.h>
34 #include "ogg2.h"
35 #include "avformat.h"
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 static ogg_codec_t *ogg_codecs[] = {
41 &vorbis_codec,
42 &theora_codec,
43 &flac_codec,
44 &ogm_video_codec,
45 &ogm_audio_codec,
46 &ogm_old_codec,
47 NULL
50 #if 0 // CONFIG_MUXERS
51 static int
52 ogg_write_header (AVFormatContext * avfcontext)
56 static int
57 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
62 static int
63 ogg_write_trailer (AVFormatContext * avfcontext)
68 AVOutputFormat ogg_muxer = {
69 "ogg",
70 "Ogg Vorbis",
71 "audio/x-vorbis",
72 "ogg",
73 sizeof (OggContext),
74 CODEC_ID_VORBIS,
76 ogg_write_header,
77 ogg_write_packet,
78 ogg_write_trailer,
80 #endif //CONFIG_MUXERS
82 //FIXME We could avoid some structure duplication
83 static int
84 ogg_save (AVFormatContext * s)
86 ogg_t *ogg = s->priv_data;
87 ogg_state_t *ost =
88 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
89 int i;
90 ost->pos = url_ftell (&s->pb);;
91 ost->curidx = ogg->curidx;
92 ost->next = ogg->state;
93 ost->nstreams = ogg->nstreams;
94 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
96 for (i = 0; i < ogg->nstreams; i++){
97 ogg_stream_t *os = ogg->streams + i;
98 os->buf = av_malloc (os->bufsize);
99 memset (os->buf, 0, os->bufsize);
100 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
103 ogg->state = ost;
105 return 0;
108 static int
109 ogg_restore (AVFormatContext * s, int discard)
111 ogg_t *ogg = s->priv_data;
112 ByteIOContext *bc = &s->pb;
113 ogg_state_t *ost = ogg->state;
114 int i;
116 if (!ost)
117 return 0;
119 ogg->state = ost->next;
121 if (!discard){
122 for (i = 0; i < ogg->nstreams; i++)
123 av_free (ogg->streams[i].buf);
125 url_fseek (bc, ost->pos, SEEK_SET);
126 ogg->curidx = ost->curidx;
127 ogg->nstreams = ost->nstreams;
128 memcpy(ogg->streams, ost->streams,
129 ost->nstreams * sizeof(*ogg->streams));
132 av_free (ost);
134 return 0;
137 static int
138 ogg_reset (ogg_t * ogg)
140 int i;
142 for (i = 0; i < ogg->nstreams; i++){
143 ogg_stream_t *os = ogg->streams + i;
144 os->bufpos = 0;
145 os->pstart = 0;
146 os->psize = 0;
147 os->granule = -1;
148 os->lastgp = -1;
149 os->nsegs = 0;
150 os->segp = 0;
153 ogg->curidx = -1;
155 return 0;
158 static ogg_codec_t *
159 ogg_find_codec (uint8_t * buf, int size)
161 int i;
163 for (i = 0; ogg_codecs[i]; i++)
164 if (size >= ogg_codecs[i]->magicsize &&
165 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
166 return ogg_codecs[i];
168 return NULL;
171 static int
172 ogg_find_stream (ogg_t * ogg, int serial)
174 int i;
176 for (i = 0; i < ogg->nstreams; i++)
177 if (ogg->streams[i].serial == serial)
178 return i;
180 return -1;
183 static int
184 ogg_new_stream (AVFormatContext * s, uint32_t serial)
187 ogg_t *ogg = s->priv_data;
188 int idx = ogg->nstreams++;
189 AVStream *st;
190 ogg_stream_t *os;
192 ogg->streams = av_realloc (ogg->streams,
193 ogg->nstreams * sizeof (*ogg->streams));
194 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
195 os = ogg->streams + idx;
196 os->serial = serial;
197 os->bufsize = DECODER_BUFFER_SIZE;
198 os->buf = av_malloc(os->bufsize);
199 os->header = -1;
201 st = av_new_stream (s, idx);
202 if (!st)
203 return AVERROR_NOMEM;
205 av_set_pts_info(st, 64, 1, 1000000);
207 return idx;
210 static int
211 ogg_new_buf(ogg_t *ogg, int idx)
213 ogg_stream_t *os = ogg->streams + idx;
214 uint8_t *nb = av_malloc(os->bufsize);
215 int size = os->bufpos - os->pstart;
216 if(os->buf){
217 memcpy(nb, os->buf + os->pstart, size);
218 av_free(os->buf);
220 os->buf = nb;
221 os->bufpos = size;
222 os->pstart = 0;
224 return 0;
227 static int
228 ogg_read_page (AVFormatContext * s, int *str)
230 ByteIOContext *bc = &s->pb;
231 ogg_t *ogg = s->priv_data;
232 ogg_stream_t *os;
233 int i = 0;
234 int flags, nsegs;
235 uint64_t gp;
236 uint32_t serial;
237 uint32_t seq;
238 uint32_t crc;
239 int size, idx;
240 uint8_t sync[4];
241 int sp = 0;
243 if (get_buffer (bc, sync, 4) < 4)
244 return -1;
247 int c;
249 if (sync[sp & 3] == 'O' &&
250 sync[(sp + 1) & 3] == 'g' &&
251 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
252 break;
254 c = url_fgetc (bc);
255 if (c < 0)
256 return -1;
257 sync[sp++ & 3] = c;
258 }while (i++ < MAX_PAGE_SIZE);
260 if (i >= MAX_PAGE_SIZE){
261 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
262 return -1;
265 if (url_fgetc (bc) != 0) /* version */
266 return -1;
268 flags = url_fgetc (bc);
269 gp = get_le64 (bc);
270 serial = get_le32 (bc);
271 seq = get_le32 (bc);
272 crc = get_le32 (bc);
273 nsegs = url_fgetc (bc);
275 idx = ogg_find_stream (ogg, serial);
276 if (idx < 0){
277 idx = ogg_new_stream (s, serial);
278 if (idx < 0)
279 return -1;
282 os = ogg->streams + idx;
284 if(os->psize > 0)
285 ogg_new_buf(ogg, idx);
287 if (get_buffer (bc, os->segments, nsegs) < nsegs)
288 return -1;
290 os->nsegs = nsegs;
291 os->segp = 0;
293 size = 0;
294 for (i = 0; i < nsegs; i++)
295 size += os->segments[i];
297 if (flags & OGG_FLAG_CONT){
298 if (!os->psize){
299 while (os->segp < os->nsegs){
300 int seg = os->segments[os->segp++];
301 os->pstart += seg;
302 if (seg < 255)
303 break;
306 }else{
307 os->psize = 0;
310 if (os->bufsize - os->bufpos < size){
311 uint8_t *nb = av_malloc (os->bufsize *= 2);
312 memcpy (nb, os->buf, os->bufpos);
313 av_free (os->buf);
314 os->buf = nb;
317 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
318 return -1;
320 os->lastgp = os->granule;
321 os->bufpos += size;
322 os->granule = gp;
323 os->flags = flags;
325 if (str)
326 *str = idx;
328 return 0;
331 static int
332 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
334 ogg_t *ogg = s->priv_data;
335 int idx;
336 ogg_stream_t *os;
337 int complete = 0;
338 int segp = 0, psize = 0;
340 #if 0
341 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
342 #endif
345 idx = ogg->curidx;
347 while (idx < 0){
348 if (ogg_read_page (s, &idx) < 0)
349 return -1;
352 os = ogg->streams + idx;
354 #if 0
355 av_log (s, AV_LOG_DEBUG,
356 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
357 idx, os->pstart, os->psize, os->segp, os->nsegs);
358 #endif
360 if (!os->codec){
361 if (os->header < 0){
362 os->codec = ogg_find_codec (os->buf, os->bufpos);
363 if (!os->codec){
364 os->header = 0;
365 return 0;
367 }else{
368 return 0;
372 segp = os->segp;
373 psize = os->psize;
375 while (os->segp < os->nsegs){
376 int ss = os->segments[os->segp++];
377 os->psize += ss;
378 if (ss < 255){
379 complete = 1;
380 break;
384 if (!complete && os->segp == os->nsegs){
385 ogg->curidx = -1;
387 }while (!complete);
389 #if 0
390 av_log (s, AV_LOG_DEBUG,
391 "ogg_packet: idx %i, frame size %i, start %i\n",
392 idx, os->psize, os->pstart);
393 #endif
395 ogg->curidx = idx;
397 if (os->header < 0){
398 int hdr = os->codec->header (s, idx);
399 if (!hdr){
400 os->header = os->seq;
401 os->segp = segp;
402 os->psize = psize;
403 ogg->headers = 1;
404 }else{
405 os->pstart += os->psize;
406 os->psize = 0;
410 if (os->header > -1 && os->seq > os->header){
411 if (os->codec && os->codec->packet)
412 os->codec->packet (s, idx);
413 if (str)
414 *str = idx;
415 if (dstart)
416 *dstart = os->pstart;
417 if (dsize)
418 *dsize = os->psize;
419 os->pstart += os->psize;
420 os->psize = 0;
423 os->seq++;
424 if (os->segp == os->nsegs)
425 ogg->curidx = -1;
427 return 0;
430 static int
431 ogg_get_headers (AVFormatContext * s)
433 ogg_t *ogg = s->priv_data;
436 if (ogg_packet (s, NULL, NULL, NULL) < 0)
437 return -1;
438 }while (!ogg->headers);
440 #if 0
441 av_log (s, AV_LOG_DEBUG, "found headers\n");
442 #endif
444 return 0;
447 static uint64_t
448 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
450 ogg_t *ogg = s->priv_data;
451 ogg_stream_t *os = ogg->streams + i;
452 uint64_t pts = AV_NOPTS_VALUE;
454 if(os->codec->gptopts){
455 pts = os->codec->gptopts(s, i, gp);
456 } else {
457 pts = gp;
460 return pts;
464 static int
465 ogg_get_length (AVFormatContext * s)
467 ogg_t *ogg = s->priv_data;
468 int idx = -1, i;
469 offset_t size, end;
471 if(s->pb.is_streamed)
472 return 0;
474 // already set
475 if (s->duration != AV_NOPTS_VALUE)
476 return 0;
478 size = url_fsize(&s->pb);
479 if(size < 0)
480 return 0;
481 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
483 ogg_save (s);
484 url_fseek (&s->pb, end, SEEK_SET);
486 while (!ogg_read_page (s, &i)){
487 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
488 ogg->streams[i].codec)
489 idx = i;
492 if (idx != -1){
493 s->streams[idx]->duration =
494 ogg_gptopts (s, idx, ogg->streams[idx].granule);
497 ogg->size = size;
498 ogg_restore (s, 0);
499 ogg_save (s);
500 while (!ogg_read_page (s, &i)) {
501 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
502 break;
504 if (i == idx) {
505 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
506 s->streams[idx]->duration -= s->streams[idx]->start_time;
508 ogg_restore (s, 0);
510 return 0;
514 static int
515 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
517 ogg_t *ogg = s->priv_data;
518 ogg->curidx = -1;
519 //linear headers seek from start
520 if (ogg_get_headers (s) < 0){
521 return -1;
524 //linear granulepos seek from end
525 ogg_get_length (s);
527 //fill the extradata in the per codec callbacks
528 return 0;
532 static int
533 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
535 ogg_t *ogg;
536 ogg_stream_t *os;
537 int idx = -1;
538 int pstart, psize;
540 //Get an ogg packet
542 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
543 return AVERROR_IO;
544 }while (idx < 0 || !s->streams[idx]);
546 ogg = s->priv_data;
547 os = ogg->streams + idx;
549 //Alloc a pkt
550 if (av_new_packet (pkt, psize) < 0)
551 return AVERROR_IO;
552 pkt->stream_index = idx;
553 memcpy (pkt->data, os->buf + pstart, psize);
554 if (os->lastgp != -1LL){
555 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
556 os->lastgp = -1;
559 return psize;
563 static int
564 ogg_read_close (AVFormatContext * s)
566 ogg_t *ogg = s->priv_data;
567 int i;
569 for (i = 0; i < ogg->nstreams; i++){
570 av_free (ogg->streams[i].buf);
571 av_free (ogg->streams[i].private);
573 av_free (ogg->streams);
574 return 0;
578 static int
579 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
580 int flags)
582 AVStream *st = s->streams[stream_index];
583 ogg_t *ogg = s->priv_data;
584 ByteIOContext *bc = &s->pb;
585 uint64_t min = 0, max = ogg->size;
586 uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
587 int64_t pts = AV_NOPTS_VALUE;
589 ogg_save (s);
591 if ((uint64_t)target_ts < tmin || target_ts < 0)
592 target_ts = tmin;
593 while (min <= max && tmin < tmax){
594 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
595 int i = -1;
597 url_fseek (bc, p, SEEK_SET);
599 while (!ogg_read_page (s, &i)){
600 if (i == stream_index && ogg->streams[i].granule != 0 &&
601 ogg->streams[i].granule != -1)
602 break;
605 if (i == -1)
606 break;
608 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
609 p = url_ftell (bc);
611 if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den)
612 break;
614 if (pts > target_ts){
615 if (max == p && tmax == pts) {
616 // probably our tmin is wrong, causing us to always end up too late in the file
617 tmin = (target_ts + tmin + 1) / 2;
618 if (tmin == target_ts) {
619 url_fseek(bc, min, SEEK_SET);
620 break;
623 max = p;
624 tmax = pts;
625 }else{
626 if (min == p && tmin == pts) {
627 // probably our tmax is wrong, causing us to always end up too early in the file
628 tmax = (target_ts + tmax) / 2;
629 if (tmax == target_ts) {
630 url_fseek(bc, max, SEEK_SET);
631 break;
634 min = p;
635 tmin = pts;
639 if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den){
640 ogg_restore (s, 1);
641 ogg_reset (ogg);
642 }else{
643 ogg_restore (s, 0);
644 pts = AV_NOPTS_VALUE;
647 av_update_cur_dts(s, st, pts);
648 return 0;
650 #if 0
651 //later...
652 int64_t pos;
653 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
654 return -1;
655 pos = url_ftell (&s->pb);
656 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
657 #endif
661 #if 0
662 static int64_t
663 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
664 int64_t pos_limit)
666 ogg_t *ogg = s->priv_data;
667 ByteIOContext *bc = &s->pb;
668 int64_t pos, pts;
670 if (*pos_arg < 0)
671 return AV_NOPTS_VALUE;
673 pos = *pos_arg;
675 #endif
677 static int ogg_probe(AVProbeData *p)
679 if (p->buf_size < 6)
680 return 0;
681 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
682 p->buf[2] == 'g' && p->buf[3] == 'S' &&
683 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
684 return AVPROBE_SCORE_MAX;
685 else
686 return 0;
689 AVInputFormat ogg_demuxer = {
690 "ogg",
691 "Ogg",
692 sizeof (ogg_t),
693 ogg_probe,
694 ogg_read_header,
695 ogg_read_packet,
696 ogg_read_close,
697 ogg_read_seek,
698 // ogg_read_timestamp,
699 .extensions = "ogg",