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