Implement framedrop.
[libav.git] / libavformat / oggdec.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>
a0ddef24 34#include "oggdec.h"
9146ca37
MR
35#include "avformat.h"
36
37#define MAX_PAGE_SIZE 65307
38#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
77be08ee 40static const struct ogg_codec * const ogg_codecs[] = {
24ca518b 41 &ff_dirac_codec,
547ea47d
RD
42 &ff_speex_codec,
43 &ff_vorbis_codec,
44 &ff_theora_codec,
45 &ff_flac_codec,
24ca518b 46 &ff_old_dirac_codec,
547ea47d
RD
47 &ff_old_flac_codec,
48 &ff_ogm_video_codec,
49 &ff_ogm_audio_codec,
50 &ff_ogm_text_codec,
51 &ff_ogm_old_codec,
9146ca37
MR
52 NULL
53};
54
9146ca37
MR
55//FIXME We could avoid some structure duplication
56static int
57ogg_save (AVFormatContext * s)
58{
77be08ee
MR
59 struct ogg *ogg = s->priv_data;
60 struct ogg_state *ost =
ad3aa874 61 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
9146ca37 62 int i;
899681cd 63 ost->pos = url_ftell (s->pb);
9146ca37
MR
64 ost->curidx = ogg->curidx;
65 ost->next = ogg->state;
20be72c8 66 ost->nstreams = ogg->nstreams;
9146ca37
MR
67 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
68
69 for (i = 0; i < ogg->nstreams; i++){
77be08ee 70 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
71 os->buf = av_malloc (os->bufsize);
72 memset (os->buf, 0, os->bufsize);
73 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
74 }
75
76 ogg->state = ost;
77
78 return 0;
79}
80
81static int
82ogg_restore (AVFormatContext * s, int discard)
83{
77be08ee 84 struct ogg *ogg = s->priv_data;
899681cd 85 ByteIOContext *bc = s->pb;
77be08ee 86 struct ogg_state *ost = ogg->state;
9146ca37
MR
87 int i;
88
89 if (!ost)
90 return 0;
91
92 ogg->state = ost->next;
93
94 if (!discard){
95 for (i = 0; i < ogg->nstreams; i++)
96 av_free (ogg->streams[i].buf);
97
98 url_fseek (bc, ost->pos, SEEK_SET);
99 ogg->curidx = ost->curidx;
20be72c8
MR
100 ogg->nstreams = ost->nstreams;
101 memcpy(ogg->streams, ost->streams,
102 ost->nstreams * sizeof(*ogg->streams));
9146ca37
MR
103 }
104
105 av_free (ost);
106
107 return 0;
108}
109
110static int
77be08ee 111ogg_reset (struct ogg * ogg)
9146ca37
MR
112{
113 int i;
114
115 for (i = 0; i < ogg->nstreams; i++){
77be08ee 116 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
117 os->bufpos = 0;
118 os->pstart = 0;
119 os->psize = 0;
120 os->granule = -1;
5e15c7d9 121 os->lastpts = AV_NOPTS_VALUE;
2d4970d8 122 os->lastdts = AV_NOPTS_VALUE;
9146ca37
MR
123 os->nsegs = 0;
124 os->segp = 0;
ecc0027b 125 os->incomplete = 0;
9146ca37
MR
126 }
127
128 ogg->curidx = -1;
129
130 return 0;
131}
132
77be08ee 133static const struct ogg_codec *
2d2f443d 134ogg_find_codec (uint8_t * buf, int size)
9146ca37
MR
135{
136 int i;
137
138 for (i = 0; ogg_codecs[i]; i++)
139 if (size >= ogg_codecs[i]->magicsize &&
140 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
141 return ogg_codecs[i];
142
143 return NULL;
144}
145
146static int
77be08ee 147ogg_find_stream (struct ogg * ogg, int serial)
9146ca37
MR
148{
149 int i;
150
151 for (i = 0; i < ogg->nstreams; i++)
152 if (ogg->streams[i].serial == serial)
153 return i;
154
155 return -1;
156}
157
158static int
159ogg_new_stream (AVFormatContext * s, uint32_t serial)
160{
161
77be08ee 162 struct ogg *ogg = s->priv_data;
9146ca37
MR
163 int idx = ogg->nstreams++;
164 AVStream *st;
77be08ee 165 struct ogg_stream *os;
9146ca37
MR
166
167 ogg->streams = av_realloc (ogg->streams,
168 ogg->nstreams * sizeof (*ogg->streams));
169 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
170 os = ogg->streams + idx;
171 os->serial = serial;
172 os->bufsize = DECODER_BUFFER_SIZE;
40c5e1fa 173 os->buf = av_malloc(os->bufsize);
9146ca37
MR
174 os->header = -1;
175
176 st = av_new_stream (s, idx);
177 if (!st)
769e10f0 178 return AVERROR(ENOMEM);
9146ca37
MR
179
180 av_set_pts_info(st, 64, 1, 1000000);
9146ca37
MR
181
182 return idx;
183}
184
185static int
77be08ee 186ogg_new_buf(struct ogg *ogg, int idx)
12a195e3 187{
77be08ee 188 struct ogg_stream *os = ogg->streams + idx;
ea02862a 189 uint8_t *nb = av_malloc(os->bufsize);
12a195e3
MR
190 int size = os->bufpos - os->pstart;
191 if(os->buf){
192 memcpy(nb, os->buf + os->pstart, size);
193 av_free(os->buf);
194 }
195 os->buf = nb;
196 os->bufpos = size;
197 os->pstart = 0;
198
199 return 0;
200}
201
202static int
9146ca37
MR
203ogg_read_page (AVFormatContext * s, int *str)
204{
899681cd 205 ByteIOContext *bc = s->pb;
77be08ee
MR
206 struct ogg *ogg = s->priv_data;
207 struct ogg_stream *os;
9146ca37
MR
208 int i = 0;
209 int flags, nsegs;
210 uint64_t gp;
211 uint32_t serial;
212 uint32_t seq;
213 uint32_t crc;
214 int size, idx;
191e8ca7 215 uint8_t sync[4];
9146ca37
MR
216 int sp = 0;
217
218 if (get_buffer (bc, sync, 4) < 4)
219 return -1;
220
221 do{
222 int c;
223
224 if (sync[sp & 3] == 'O' &&
225 sync[(sp + 1) & 3] == 'g' &&
226 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
227 break;
228
229 c = url_fgetc (bc);
230 if (c < 0)
231 return -1;
232 sync[sp++ & 3] = c;
233 }while (i++ < MAX_PAGE_SIZE);
234
235 if (i >= MAX_PAGE_SIZE){
236 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
237 return -1;
238 }
239
240 if (url_fgetc (bc) != 0) /* version */
241 return -1;
242
243 flags = url_fgetc (bc);
244 gp = get_le64 (bc);
245 serial = get_le32 (bc);
246 seq = get_le32 (bc);
247 crc = get_le32 (bc);
248 nsegs = url_fgetc (bc);
249
250 idx = ogg_find_stream (ogg, serial);
251 if (idx < 0){
252 idx = ogg_new_stream (s, serial);
253 if (idx < 0)
254 return -1;
255 }
256
257 os = ogg->streams + idx;
258
40c5e1fa 259 if(os->psize > 0)
12a195e3
MR
260 ogg_new_buf(ogg, idx);
261
9146ca37
MR
262 if (get_buffer (bc, os->segments, nsegs) < nsegs)
263 return -1;
264
265 os->nsegs = nsegs;
266 os->segp = 0;
267
268 size = 0;
269 for (i = 0; i < nsegs; i++)
270 size += os->segments[i];
271
ecc0027b 272 if (flags & OGG_FLAG_CONT || os->incomplete){
9146ca37
MR
273 if (!os->psize){
274 while (os->segp < os->nsegs){
275 int seg = os->segments[os->segp++];
276 os->pstart += seg;
277 if (seg < 255)
bad4a6bb 278 break;
9146ca37
MR
279 }
280 }
281 }else{
bad4a6bb 282 os->psize = 0;
9146ca37
MR
283 }
284
285 if (os->bufsize - os->bufpos < size){
2d2f443d 286 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
287 memcpy (nb, os->buf, os->bufpos);
288 av_free (os->buf);
289 os->buf = nb;
290 }
291
292 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
293 return -1;
294
9146ca37
MR
295 os->bufpos += size;
296 os->granule = gp;
297 os->flags = flags;
298
299 if (str)
300 *str = idx;
301
302 return 0;
303}
304
305static int
12a195e3 306ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
9146ca37 307{
77be08ee 308 struct ogg *ogg = s->priv_data;
5e15c7d9 309 int idx, i;
77be08ee 310 struct ogg_stream *os;
9146ca37
MR
311 int complete = 0;
312 int segp = 0, psize = 0;
313
314#if 0
315 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
316#endif
317
318 do{
319 idx = ogg->curidx;
320
321 while (idx < 0){
322 if (ogg_read_page (s, &idx) < 0)
323 return -1;
324 }
325
326 os = ogg->streams + idx;
327
328#if 0
329 av_log (s, AV_LOG_DEBUG,
330 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
331 idx, os->pstart, os->psize, os->segp, os->nsegs);
332#endif
333
334 if (!os->codec){
335 if (os->header < 0){
336 os->codec = ogg_find_codec (os->buf, os->bufpos);
337 if (!os->codec){
338 os->header = 0;
339 return 0;
340 }
341 }else{
342 return 0;
343 }
344 }
345
346 segp = os->segp;
347 psize = os->psize;
348
349 while (os->segp < os->nsegs){
350 int ss = os->segments[os->segp++];
351 os->psize += ss;
352 if (ss < 255){
353 complete = 1;
354 break;
355 }
356 }
357
358 if (!complete && os->segp == os->nsegs){
9146ca37 359 ogg->curidx = -1;
ecc0027b 360 os->incomplete = 1;
9146ca37
MR
361 }
362 }while (!complete);
363
364#if 0
365 av_log (s, AV_LOG_DEBUG,
366 "ogg_packet: idx %i, frame size %i, start %i\n",
367 idx, os->psize, os->pstart);
368#endif
369
370 ogg->curidx = idx;
ecc0027b 371 os->incomplete = 0;
9146ca37 372
be4a1132 373 if (!ogg->headers){
9146ca37 374 int hdr = os->codec->header (s, idx);
be4a1132 375 os->header = os->seq;
9146ca37 376 if (!hdr){
bad4a6bb
PR
377 os->segp = segp;
378 os->psize = psize;
379 ogg->headers = 1;
9146ca37 380 }else{
bad4a6bb
PR
381 os->pstart += os->psize;
382 os->psize = 0;
9146ca37
MR
383 }
384 }
385
386 if (os->header > -1 && os->seq > os->header){
e1a794b2 387 os->pflags = 0;
15299b38 388 os->pduration = 0;
9146ca37
MR
389 if (os->codec && os->codec->packet)
390 os->codec->packet (s, idx);
391 if (str)
392 *str = idx;
12a195e3
MR
393 if (dstart)
394 *dstart = os->pstart;
395 if (dsize)
396 *dsize = os->psize;
397 os->pstart += os->psize;
398 os->psize = 0;
9146ca37
MR
399 }
400
5e15c7d9
DC
401 // determine whether there are more complete packets in this page
402 // if not, the page's granule will apply to this packet
403 os->page_end = 1;
404 for (i = os->segp; i < os->nsegs; i++)
405 if (os->segments[i] < 255) {
406 os->page_end = 0;
407 break;
408 }
409
9146ca37
MR
410 os->seq++;
411 if (os->segp == os->nsegs)
412 ogg->curidx = -1;
413
414 return 0;
415}
416
417static int
418ogg_get_headers (AVFormatContext * s)
419{
77be08ee 420 struct ogg *ogg = s->priv_data;
9146ca37
MR
421
422 do{
12a195e3 423 if (ogg_packet (s, NULL, NULL, NULL) < 0)
9146ca37
MR
424 return -1;
425 }while (!ogg->headers);
426
427#if 0
428 av_log (s, AV_LOG_DEBUG, "found headers\n");
429#endif
430
431 return 0;
432}
433
434static uint64_t
2d4970d8 435ogg_gptopts (AVFormatContext * s, int i, uint64_t gp, int64_t *dts)
9146ca37 436{
77be08ee
MR
437 struct ogg *ogg = s->priv_data;
438 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
439 uint64_t pts = AV_NOPTS_VALUE;
440
1ed923ea 441 if(os->codec->gptopts){
2d4970d8 442 pts = os->codec->gptopts(s, i, gp, dts);
3644cb8f 443 } else {
1ed923ea 444 pts = gp;
2d4970d8
DC
445 if (dts)
446 *dts = pts;
9146ca37
MR
447 }
448
449 return pts;
450}
451
452
453static int
454ogg_get_length (AVFormatContext * s)
455{
77be08ee 456 struct ogg *ogg = s->priv_data;
9146ca37 457 int idx = -1, i;
bc5c918e 458 int64_t size, end;
69599eea 459
ceeacce6 460 if(url_is_streamed(s->pb))
69599eea 461 return 0;
9146ca37
MR
462
463// already set
464 if (s->duration != AV_NOPTS_VALUE)
465 return 0;
466
899681cd 467 size = url_fsize(s->pb);
56466d7b
MR
468 if(size < 0)
469 return 0;
ddd94932 470 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
56466d7b 471
9146ca37 472 ogg_save (s);
899681cd 473 url_fseek (s->pb, end, SEEK_SET);
9146ca37
MR
474
475 while (!ogg_read_page (s, &i)){
e22f2aaf
MR
476 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
477 ogg->streams[i].codec)
9146ca37
MR
478 idx = i;
479 }
480
481 if (idx != -1){
482 s->streams[idx]->duration =
2d4970d8 483 ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
9146ca37
MR
484 }
485
56466d7b 486 ogg->size = size;
9146ca37
MR
487 ogg_restore (s, 0);
488
489 return 0;
490}
491
492
493static int
494ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
495{
77be08ee 496 struct ogg *ogg = s->priv_data;
c9da676d 497 int i;
9146ca37
MR
498 ogg->curidx = -1;
499 //linear headers seek from start
500 if (ogg_get_headers (s) < 0){
bad4a6bb 501 return -1;
9146ca37
MR
502 }
503
c9da676d
RD
504 for (i = 0; i < ogg->nstreams; i++)
505 if (ogg->streams[i].header < 0)
506 ogg->streams[i].codec = NULL;
507
9146ca37
MR
508 //linear granulepos seek from end
509 ogg_get_length (s);
510
511 //fill the extradata in the per codec callbacks
512 return 0;
513}
514
515
516static int
517ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
518{
77be08ee
MR
519 struct ogg *ogg;
520 struct ogg_stream *os;
9146ca37 521 int idx = -1;
12a195e3 522 int pstart, psize;
9146ca37 523
115329f1 524 //Get an ogg packet
9146ca37 525 do{
12a195e3 526 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
6f3e0b21 527 return AVERROR(EIO);
9146ca37
MR
528 }while (idx < 0 || !s->streams[idx]);
529
530 ogg = s->priv_data;
531 os = ogg->streams + idx;
532
533 //Alloc a pkt
12a195e3 534 if (av_new_packet (pkt, psize) < 0)
6f3e0b21 535 return AVERROR(EIO);
9146ca37 536 pkt->stream_index = idx;
12a195e3 537 memcpy (pkt->data, os->buf + pstart, psize);
5e15c7d9
DC
538
539 if (os->lastpts != AV_NOPTS_VALUE) {
540 pkt->pts = os->lastpts;
541 os->lastpts = AV_NOPTS_VALUE;
542 }
2d4970d8
DC
543 if (os->lastdts != AV_NOPTS_VALUE) {
544 pkt->dts = os->lastdts;
545 os->lastdts = AV_NOPTS_VALUE;
546 }
5e15c7d9
DC
547 if (os->page_end) {
548 if (os->granule != -1LL) {
549 if (os->codec && os->codec->granule_is_start)
2d4970d8 550 pkt->pts = ogg_gptopts(s, idx, os->granule, &pkt->dts);
5e15c7d9 551 else
2d4970d8 552 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
5e15c7d9
DC
553 os->granule = -1LL;
554 } else
555 av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
9146ca37 556 }
12a195e3 557
e1a794b2 558 pkt->flags = os->pflags;
15299b38 559 pkt->duration = os->pduration;
e1a794b2 560
12a195e3 561 return psize;
9146ca37
MR
562}
563
564
565static int
566ogg_read_close (AVFormatContext * s)
567{
77be08ee 568 struct ogg *ogg = s->priv_data;
9146ca37
MR
569 int i;
570
571 for (i = 0; i < ogg->nstreams; i++){
572 av_free (ogg->streams[i].buf);
1ed923ea 573 av_free (ogg->streams[i].private);
9146ca37
MR
574 }
575 av_free (ogg->streams);
576 return 0;
577}
578
579
9146ca37
MR
580static int64_t
581ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
582 int64_t pos_limit)
583{
77be08ee 584 struct ogg *ogg = s->priv_data;
899681cd 585 ByteIOContext *bc = s->pb;
a1f29b95
RD
586 int64_t pts = AV_NOPTS_VALUE;
587 int i;
588 url_fseek(bc, *pos_arg, SEEK_SET);
589 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
590 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
591 ogg->streams[i].codec && i == stream_index) {
2d4970d8 592 pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
a1f29b95
RD
593 // FIXME: this is the position of the packet after the one with above
594 // pts.
595 *pos_arg = url_ftell(bc);
596 break;
597 }
598 }
599 ogg_reset(ogg);
600 return pts;
9146ca37 601}
9146ca37 602
2e70e4aa
MR
603static int ogg_probe(AVProbeData *p)
604{
2e70e4aa
MR
605 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
606 p->buf[2] == 'g' && p->buf[3] == 'S' &&
607 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
608 return AVPROBE_SCORE_MAX;
609 else
610 return 0;
611}
612
ff70e601 613AVInputFormat ogg_demuxer = {
9146ca37 614 "ogg",
bde15e74 615 NULL_IF_CONFIG_SMALL("Ogg"),
77be08ee 616 sizeof (struct ogg),
2e70e4aa 617 ogg_probe,
9146ca37
MR
618 ogg_read_header,
619 ogg_read_packet,
620 ogg_read_close,
ce3132be 621 NULL,
a1f29b95 622 ogg_read_timestamp,
9146ca37 623 .extensions = "ogg",
d7bb185f 624 .metadata_conv = ff_vorbiscomment_metadata_conv,
9146ca37 625};