fix incorrect check for abs_diff_pic_num overflow
[libav.git] / libavformat / ogg2.c
CommitLineData
9146ca37
MR
1/*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
115329f1 5 *
9146ca37
MR
6 */
7
8/**
9 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
10
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:
18
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
21
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**/
31
32
33#include <stdio.h>
34#include "ogg2.h"
35#include "avformat.h"
36
37#define MAX_PAGE_SIZE 65307
38#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40static ogg_codec_t *ogg_codecs[] = {
41 &vorbis_codec,
1ed923ea 42 &theora_codec,
bcfc40ae 43 &flac_codec,
880e3ef4 44 &old_flac_codec,
e1203ac0
MR
45 &ogm_video_codec,
46 &ogm_audio_codec,
47 &ogm_old_codec,
9146ca37
MR
48 NULL
49};
50
a9e35095 51#if 0 // CONFIG_MUXERS
9146ca37
MR
52static int
53ogg_write_header (AVFormatContext * avfcontext)
54{
55}
56
57static int
58ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
59{
60}
61
62
63static int
64ogg_write_trailer (AVFormatContext * avfcontext)
65{
66}
67
68
ff70e601 69AVOutputFormat ogg_muxer = {
9146ca37 70 "ogg",
1367cffd
DB
71 "Ogg format",
72 "application/ogg",
9146ca37
MR
73 "ogg",
74 sizeof (OggContext),
75 CODEC_ID_VORBIS,
76 0,
77 ogg_write_header,
78 ogg_write_packet,
79 ogg_write_trailer,
80};
a9e35095 81#endif //CONFIG_MUXERS
9146ca37
MR
82
83//FIXME We could avoid some structure duplication
84static int
85ogg_save (AVFormatContext * s)
86{
87 ogg_t *ogg = s->priv_data;
88 ogg_state_t *ost =
ad3aa874 89 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
9146ca37
MR
90 int i;
91 ost->pos = url_ftell (&s->pb);;
92 ost->curidx = ogg->curidx;
93 ost->next = ogg->state;
20be72c8 94 ost->nstreams = ogg->nstreams;
9146ca37
MR
95 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
96
97 for (i = 0; i < ogg->nstreams; i++){
98 ogg_stream_t *os = ogg->streams + i;
99 os->buf = av_malloc (os->bufsize);
100 memset (os->buf, 0, os->bufsize);
101 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
102 }
103
104 ogg->state = ost;
105
106 return 0;
107}
108
109static int
110ogg_restore (AVFormatContext * s, int discard)
111{
112 ogg_t *ogg = s->priv_data;
113 ByteIOContext *bc = &s->pb;
114 ogg_state_t *ost = ogg->state;
115 int i;
116
117 if (!ost)
118 return 0;
119
120 ogg->state = ost->next;
121
122 if (!discard){
123 for (i = 0; i < ogg->nstreams; i++)
124 av_free (ogg->streams[i].buf);
125
126 url_fseek (bc, ost->pos, SEEK_SET);
127 ogg->curidx = ost->curidx;
20be72c8
MR
128 ogg->nstreams = ost->nstreams;
129 memcpy(ogg->streams, ost->streams,
130 ost->nstreams * sizeof(*ogg->streams));
9146ca37
MR
131 }
132
133 av_free (ost);
134
135 return 0;
136}
137
138static int
139ogg_reset (ogg_t * ogg)
140{
141 int i;
142
143 for (i = 0; i < ogg->nstreams; i++){
144 ogg_stream_t *os = ogg->streams + i;
145 os->bufpos = 0;
146 os->pstart = 0;
147 os->psize = 0;
148 os->granule = -1;
149 os->lastgp = -1;
150 os->nsegs = 0;
151 os->segp = 0;
152 }
153
154 ogg->curidx = -1;
155
156 return 0;
157}
158
159static ogg_codec_t *
2d2f443d 160ogg_find_codec (uint8_t * buf, int size)
9146ca37
MR
161{
162 int i;
163
164 for (i = 0; ogg_codecs[i]; i++)
165 if (size >= ogg_codecs[i]->magicsize &&
166 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
167 return ogg_codecs[i];
168
169 return NULL;
170}
171
172static int
173ogg_find_stream (ogg_t * ogg, int serial)
174{
175 int i;
176
177 for (i = 0; i < ogg->nstreams; i++)
178 if (ogg->streams[i].serial == serial)
179 return i;
180
181 return -1;
182}
183
184static int
185ogg_new_stream (AVFormatContext * s, uint32_t serial)
186{
187
188 ogg_t *ogg = s->priv_data;
189 int idx = ogg->nstreams++;
190 AVStream *st;
191 ogg_stream_t *os;
192
193 ogg->streams = av_realloc (ogg->streams,
194 ogg->nstreams * sizeof (*ogg->streams));
195 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
196 os = ogg->streams + idx;
197 os->serial = serial;
198 os->bufsize = DECODER_BUFFER_SIZE;
40c5e1fa 199 os->buf = av_malloc(os->bufsize);
9146ca37
MR
200 os->header = -1;
201
202 st = av_new_stream (s, idx);
203 if (!st)
769e10f0 204 return AVERROR(ENOMEM);
9146ca37
MR
205
206 av_set_pts_info(st, 64, 1, 1000000);
9146ca37
MR
207
208 return idx;
209}
210
211static int
12a195e3
MR
212ogg_new_buf(ogg_t *ogg, int idx)
213{
214 ogg_stream_t *os = ogg->streams + idx;
ea02862a 215 uint8_t *nb = av_malloc(os->bufsize);
12a195e3
MR
216 int size = os->bufpos - os->pstart;
217 if(os->buf){
218 memcpy(nb, os->buf + os->pstart, size);
219 av_free(os->buf);
220 }
221 os->buf = nb;
222 os->bufpos = size;
223 os->pstart = 0;
224
225 return 0;
226}
227
228static int
9146ca37
MR
229ogg_read_page (AVFormatContext * s, int *str)
230{
231 ByteIOContext *bc = &s->pb;
232 ogg_t *ogg = s->priv_data;
233 ogg_stream_t *os;
234 int i = 0;
235 int flags, nsegs;
236 uint64_t gp;
237 uint32_t serial;
238 uint32_t seq;
239 uint32_t crc;
240 int size, idx;
191e8ca7 241 uint8_t sync[4];
9146ca37
MR
242 int sp = 0;
243
244 if (get_buffer (bc, sync, 4) < 4)
245 return -1;
246
247 do{
248 int c;
249
250 if (sync[sp & 3] == 'O' &&
251 sync[(sp + 1) & 3] == 'g' &&
252 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
253 break;
254
255 c = url_fgetc (bc);
256 if (c < 0)
257 return -1;
258 sync[sp++ & 3] = c;
259 }while (i++ < MAX_PAGE_SIZE);
260
261 if (i >= MAX_PAGE_SIZE){
262 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
263 return -1;
264 }
265
266 if (url_fgetc (bc) != 0) /* version */
267 return -1;
268
269 flags = url_fgetc (bc);
270 gp = get_le64 (bc);
271 serial = get_le32 (bc);
272 seq = get_le32 (bc);
273 crc = get_le32 (bc);
274 nsegs = url_fgetc (bc);
275
276 idx = ogg_find_stream (ogg, serial);
277 if (idx < 0){
278 idx = ogg_new_stream (s, serial);
279 if (idx < 0)
280 return -1;
281 }
282
283 os = ogg->streams + idx;
284
40c5e1fa 285 if(os->psize > 0)
12a195e3
MR
286 ogg_new_buf(ogg, idx);
287
9146ca37
MR
288 if (get_buffer (bc, os->segments, nsegs) < nsegs)
289 return -1;
290
291 os->nsegs = nsegs;
292 os->segp = 0;
293
294 size = 0;
295 for (i = 0; i < nsegs; i++)
296 size += os->segments[i];
297
298 if (flags & OGG_FLAG_CONT){
299 if (!os->psize){
300 while (os->segp < os->nsegs){
301 int seg = os->segments[os->segp++];
302 os->pstart += seg;
303 if (seg < 255)
304 break;
305 }
306 }
307 }else{
308 os->psize = 0;
309 }
310
311 if (os->bufsize - os->bufpos < size){
2d2f443d 312 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
313 memcpy (nb, os->buf, os->bufpos);
314 av_free (os->buf);
315 os->buf = nb;
316 }
317
318 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
319 return -1;
320
321 os->lastgp = os->granule;
322 os->bufpos += size;
323 os->granule = gp;
324 os->flags = flags;
325
326 if (str)
327 *str = idx;
328
329 return 0;
330}
331
332static int
12a195e3 333ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
9146ca37
MR
334{
335 ogg_t *ogg = s->priv_data;
336 int idx;
337 ogg_stream_t *os;
338 int complete = 0;
339 int segp = 0, psize = 0;
340
341#if 0
342 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
343#endif
344
345 do{
346 idx = ogg->curidx;
347
348 while (idx < 0){
349 if (ogg_read_page (s, &idx) < 0)
350 return -1;
351 }
352
353 os = ogg->streams + idx;
354
355#if 0
356 av_log (s, AV_LOG_DEBUG,
357 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
358 idx, os->pstart, os->psize, os->segp, os->nsegs);
359#endif
360
361 if (!os->codec){
362 if (os->header < 0){
363 os->codec = ogg_find_codec (os->buf, os->bufpos);
364 if (!os->codec){
365 os->header = 0;
366 return 0;
367 }
368 }else{
369 return 0;
370 }
371 }
372
373 segp = os->segp;
374 psize = os->psize;
375
376 while (os->segp < os->nsegs){
377 int ss = os->segments[os->segp++];
378 os->psize += ss;
379 if (ss < 255){
380 complete = 1;
381 break;
382 }
383 }
384
385 if (!complete && os->segp == os->nsegs){
9146ca37
MR
386 ogg->curidx = -1;
387 }
388 }while (!complete);
389
390#if 0
391 av_log (s, AV_LOG_DEBUG,
392 "ogg_packet: idx %i, frame size %i, start %i\n",
393 idx, os->psize, os->pstart);
394#endif
395
396 ogg->curidx = idx;
397
398 if (os->header < 0){
399 int hdr = os->codec->header (s, idx);
400 if (!hdr){
401 os->header = os->seq;
402 os->segp = segp;
403 os->psize = psize;
404 ogg->headers = 1;
405 }else{
406 os->pstart += os->psize;
407 os->psize = 0;
408 }
409 }
410
411 if (os->header > -1 && os->seq > os->header){
412 if (os->codec && os->codec->packet)
413 os->codec->packet (s, idx);
414 if (str)
415 *str = idx;
12a195e3
MR
416 if (dstart)
417 *dstart = os->pstart;
418 if (dsize)
419 *dsize = os->psize;
420 os->pstart += os->psize;
421 os->psize = 0;
9146ca37
MR
422 }
423
424 os->seq++;
425 if (os->segp == os->nsegs)
426 ogg->curidx = -1;
427
428 return 0;
429}
430
431static int
432ogg_get_headers (AVFormatContext * s)
433{
434 ogg_t *ogg = s->priv_data;
435
436 do{
12a195e3 437 if (ogg_packet (s, NULL, NULL, NULL) < 0)
9146ca37
MR
438 return -1;
439 }while (!ogg->headers);
440
441#if 0
442 av_log (s, AV_LOG_DEBUG, "found headers\n");
443#endif
444
445 return 0;
446}
447
448static uint64_t
449ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
450{
1ed923ea
MR
451 ogg_t *ogg = s->priv_data;
452 ogg_stream_t *os = ogg->streams + i;
9146ca37
MR
453 uint64_t pts = AV_NOPTS_VALUE;
454
1ed923ea 455 if(os->codec->gptopts){
bb270c08 456 pts = os->codec->gptopts(s, i, gp);
3644cb8f 457 } else {
1ed923ea 458 pts = gp;
9146ca37
MR
459 }
460
461 return pts;
462}
463
464
465static int
466ogg_get_length (AVFormatContext * s)
467{
468 ogg_t *ogg = s->priv_data;
9146ca37 469 int idx = -1, i;
56466d7b 470 offset_t size, end;
69599eea
MR
471
472 if(s->pb.is_streamed)
473 return 0;
9146ca37
MR
474
475// already set
476 if (s->duration != AV_NOPTS_VALUE)
477 return 0;
478
56466d7b
MR
479 size = url_fsize(&s->pb);
480 if(size < 0)
481 return 0;
482 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
483
9146ca37 484 ogg_save (s);
56466d7b 485 url_fseek (&s->pb, end, SEEK_SET);
9146ca37
MR
486
487 while (!ogg_read_page (s, &i)){
e22f2aaf
MR
488 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
489 ogg->streams[i].codec)
9146ca37
MR
490 idx = i;
491 }
492
493 if (idx != -1){
494 s->streams[idx]->duration =
495 ogg_gptopts (s, idx, ogg->streams[idx].granule);
496 }
497
56466d7b 498 ogg->size = size;
9146ca37 499 ogg_restore (s, 0);
22ffac70 500 ogg_save (s);
595da759 501 while (!ogg_read_page (s, &i)) {
22ffac70
RD
502 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
503 break;
504 }
505 if (i == idx) {
506 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
507 s->streams[idx]->duration -= s->streams[idx]->start_time;
508 }
509 ogg_restore (s, 0);
9146ca37
MR
510
511 return 0;
512}
513
514
515static int
516ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
517{
518 ogg_t *ogg = s->priv_data;
519 ogg->curidx = -1;
520 //linear headers seek from start
521 if (ogg_get_headers (s) < 0){
522 return -1;
523 }
524
525 //linear granulepos seek from end
526 ogg_get_length (s);
527
528 //fill the extradata in the per codec callbacks
529 return 0;
530}
531
532
533static int
534ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
535{
536 ogg_t *ogg;
537 ogg_stream_t *os;
538 int idx = -1;
12a195e3 539 int pstart, psize;
9146ca37 540
115329f1 541 //Get an ogg packet
9146ca37 542 do{
12a195e3 543 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
6f3e0b21 544 return AVERROR(EIO);
9146ca37
MR
545 }while (idx < 0 || !s->streams[idx]);
546
547 ogg = s->priv_data;
548 os = ogg->streams + idx;
549
550 //Alloc a pkt
12a195e3 551 if (av_new_packet (pkt, psize) < 0)
6f3e0b21 552 return AVERROR(EIO);
9146ca37 553 pkt->stream_index = idx;
12a195e3 554 memcpy (pkt->data, os->buf + pstart, psize);
9146ca37
MR
555 if (os->lastgp != -1LL){
556 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
557 os->lastgp = -1;
558 }
12a195e3
MR
559
560 return psize;
9146ca37
MR
561}
562
563
564static int
565ogg_read_close (AVFormatContext * s)
566{
567 ogg_t *ogg = s->priv_data;
568 int i;
569
570 for (i = 0; i < ogg->nstreams; i++){
571 av_free (ogg->streams[i].buf);
1ed923ea 572 av_free (ogg->streams[i].private);
9146ca37
MR
573 }
574 av_free (ogg->streams);
575 return 0;
576}
577
578
579static int
580ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
581 int flags)
582{
56466d7b 583 AVStream *st = s->streams[stream_index];
9146ca37
MR
584 ogg_t *ogg = s->priv_data;
585 ByteIOContext *bc = &s->pb;
586 uint64_t min = 0, max = ogg->size;
22ffac70 587 uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
9146ca37
MR
588 int64_t pts = AV_NOPTS_VALUE;
589
590 ogg_save (s);
591
22ffac70
RD
592 if ((uint64_t)target_ts < tmin || target_ts < 0)
593 target_ts = tmin;
594 while (min <= max && tmin < tmax){
17929c04 595 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
9146ca37
MR
596 int i = -1;
597
598 url_fseek (bc, p, SEEK_SET);
599
600 while (!ogg_read_page (s, &i)){
56466d7b
MR
601 if (i == stream_index && ogg->streams[i].granule != 0 &&
602 ogg->streams[i].granule != -1)
9146ca37
MR
603 break;
604 }
605
606 if (i == -1)
607 break;
608
609 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
610 p = url_ftell (bc);
611
c26abfa5 612 if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den)
9146ca37
MR
613 break;
614
615 if (pts > target_ts){
22ffac70
RD
616 if (max == p && tmax == pts) {
617 // probably our tmin is wrong, causing us to always end up too late in the file
618 tmin = (target_ts + tmin + 1) / 2;
619 if (tmin == target_ts) {
620 url_fseek(bc, min, SEEK_SET);
621 break;
622 }
623 }
9146ca37
MR
624 max = p;
625 tmax = pts;
626 }else{
22ffac70
RD
627 if (min == p && tmin == pts) {
628 // probably our tmax is wrong, causing us to always end up too early in the file
629 tmax = (target_ts + tmax) / 2;
630 if (tmax == target_ts) {
631 url_fseek(bc, max, SEEK_SET);
632 break;
633 }
634 }
9146ca37
MR
635 min = p;
636 tmin = pts;
637 }
638 }
639
c26abfa5 640 if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den){
9146ca37
MR
641 ogg_restore (s, 1);
642 ogg_reset (ogg);
643 }else{
644 ogg_restore (s, 0);
645 pts = AV_NOPTS_VALUE;
646 }
647
22ffac70
RD
648 av_update_cur_dts(s, st, pts);
649 return 0;
9146ca37
MR
650
651#if 0
652 //later...
653 int64_t pos;
654 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
655 return -1;
656 pos = url_ftell (&s->pb);
657 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
658#endif
659
660}
661
662#if 0
663static int64_t
664ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
665 int64_t pos_limit)
666{
667 ogg_t *ogg = s->priv_data;
668 ByteIOContext *bc = &s->pb;
669 int64_t pos, pts;
670
671 if (*pos_arg < 0)
672 return AV_NOPTS_VALUE;
673
674 pos = *pos_arg;
675}
676#endif
677
2e70e4aa
MR
678static int ogg_probe(AVProbeData *p)
679{
2e70e4aa
MR
680 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
681 p->buf[2] == 'g' && p->buf[3] == 'S' &&
682 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
683 return AVPROBE_SCORE_MAX;
684 else
685 return 0;
686}
687
ff70e601 688AVInputFormat ogg_demuxer = {
9146ca37
MR
689 "ogg",
690 "Ogg",
691 sizeof (ogg_t),
2e70e4aa 692 ogg_probe,
9146ca37
MR
693 ogg_read_header,
694 ogg_read_packet,
695 ogg_read_close,
696 ogg_read_seek,
115329f1 697// ogg_read_timestamp,
9146ca37
MR
698 .extensions = "ogg",
699};