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