oggdec: Set data_offset to the right value
[libav.git] / libavformat / oggdec.c
1 /*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
5 *
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 "oggdec.h"
35 #include "avformat.h"
36
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40 static const struct ogg_codec * const ogg_codecs[] = {
41 &ff_dirac_codec,
42 &ff_speex_codec,
43 &ff_vorbis_codec,
44 &ff_theora_codec,
45 &ff_flac_codec,
46 &ff_old_dirac_codec,
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,
52 NULL
53 };
54
55 //FIXME We could avoid some structure duplication
56 static int
57 ogg_save (AVFormatContext * s)
58 {
59 struct ogg *ogg = s->priv_data;
60 struct ogg_state *ost =
61 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
62 int i;
63 ost->pos = url_ftell (s->pb);
64 ost->curidx = ogg->curidx;
65 ost->next = ogg->state;
66 ost->nstreams = ogg->nstreams;
67 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
68
69 for (i = 0; i < ogg->nstreams; i++){
70 struct ogg_stream *os = ogg->streams + i;
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
81 static int
82 ogg_restore (AVFormatContext * s, int discard)
83 {
84 struct ogg *ogg = s->priv_data;
85 ByteIOContext *bc = s->pb;
86 struct ogg_state *ost = ogg->state;
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;
100 ogg->nstreams = ost->nstreams;
101 memcpy(ogg->streams, ost->streams,
102 ost->nstreams * sizeof(*ogg->streams));
103 }
104
105 av_free (ost);
106
107 return 0;
108 }
109
110 static int
111 ogg_reset (struct ogg * ogg)
112 {
113 int i;
114
115 for (i = 0; i < ogg->nstreams; i++){
116 struct ogg_stream *os = ogg->streams + i;
117 os->bufpos = 0;
118 os->pstart = 0;
119 os->psize = 0;
120 os->granule = -1;
121 os->lastpts = AV_NOPTS_VALUE;
122 os->lastdts = AV_NOPTS_VALUE;
123 os->sync_pos = -1;
124 os->page_pos = 0;
125 os->nsegs = 0;
126 os->segp = 0;
127 os->incomplete = 0;
128 }
129
130 ogg->curidx = -1;
131
132 return 0;
133 }
134
135 static const struct ogg_codec *
136 ogg_find_codec (uint8_t * buf, int size)
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
148 static int
149 ogg_find_stream (struct ogg * ogg, int serial)
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
160 static int
161 ogg_new_stream (AVFormatContext * s, uint32_t serial)
162 {
163
164 struct ogg *ogg = s->priv_data;
165 int idx = ogg->nstreams++;
166 AVStream *st;
167 struct ogg_stream *os;
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;
175 os->buf = av_malloc(os->bufsize);
176 os->header = -1;
177
178 st = av_new_stream (s, idx);
179 if (!st)
180 return AVERROR(ENOMEM);
181
182 av_set_pts_info(st, 64, 1, 1000000);
183
184 return idx;
185 }
186
187 static int
188 ogg_new_buf(struct ogg *ogg, int idx)
189 {
190 struct ogg_stream *os = ogg->streams + idx;
191 uint8_t *nb = av_malloc(os->bufsize);
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
204 static int
205 ogg_read_page (AVFormatContext * s, int *str)
206 {
207 ByteIOContext *bc = s->pb;
208 struct ogg *ogg = s->priv_data;
209 struct ogg_stream *os;
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;
217 uint8_t sync[4];
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;
260 os->page_pos = url_ftell(bc) - 27;
261
262 if(os->psize > 0)
263 ogg_new_buf(ogg, idx);
264
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
275 if (flags & OGG_FLAG_CONT || os->incomplete){
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)
281 break;
282 }
283 os->sync_pos = os->page_pos;
284 }
285 }else{
286 os->psize = 0;
287 os->sync_pos = os->page_pos;
288 }
289
290 if (os->bufsize - os->bufpos < size){
291 uint8_t *nb = av_malloc (os->bufsize *= 2);
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
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
310 static int
311 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
312 {
313 struct ogg *ogg = s->priv_data;
314 int idx, i;
315 struct ogg_stream *os;
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){
364 ogg->curidx = -1;
365 os->incomplete = 1;
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;
376 os->incomplete = 0;
377
378 if (!ogg->headers){
379 int hdr = os->codec->header (s, idx);
380 os->header = os->seq;
381 if (!hdr){
382 os->segp = segp;
383 os->psize = psize;
384 ogg->headers = 1;
385 s->data_offset = os->sync_pos;
386 }else{
387 os->pstart += os->psize;
388 os->psize = 0;
389 }
390 }
391
392 if (os->header > -1 && os->seq > os->header){
393 os->pflags = 0;
394 os->pduration = 0;
395 if (os->codec && os->codec->packet)
396 os->codec->packet (s, idx);
397 if (str)
398 *str = idx;
399 if (dstart)
400 *dstart = os->pstart;
401 if (dsize)
402 *dsize = os->psize;
403 if (fpos)
404 *fpos = os->sync_pos;
405 os->pstart += os->psize;
406 os->psize = 0;
407 os->sync_pos = os->page_pos;
408 }
409
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
419 os->seq++;
420 if (os->segp == os->nsegs)
421 ogg->curidx = -1;
422
423 return 0;
424 }
425
426 static int
427 ogg_get_headers (AVFormatContext * s)
428 {
429 struct ogg *ogg = s->priv_data;
430
431 do{
432 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
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
443 static uint64_t
444 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp, int64_t *dts)
445 {
446 struct ogg *ogg = s->priv_data;
447 struct ogg_stream *os = ogg->streams + i;
448 uint64_t pts = AV_NOPTS_VALUE;
449
450 if(os->codec->gptopts){
451 pts = os->codec->gptopts(s, i, gp, dts);
452 } else {
453 pts = gp;
454 if (dts)
455 *dts = pts;
456 }
457
458 return pts;
459 }
460
461
462 static int
463 ogg_get_length (AVFormatContext * s)
464 {
465 struct ogg *ogg = s->priv_data;
466 int idx = -1, i;
467 int64_t size, end;
468
469 if(url_is_streamed(s->pb))
470 return 0;
471
472 // already set
473 if (s->duration != AV_NOPTS_VALUE)
474 return 0;
475
476 size = url_fsize(s->pb);
477 if(size < 0)
478 return 0;
479 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
480
481 ogg_save (s);
482 url_fseek (s->pb, end, SEEK_SET);
483
484 while (!ogg_read_page (s, &i)){
485 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
486 ogg->streams[i].codec)
487 idx = i;
488 }
489
490 if (idx != -1){
491 s->streams[idx]->duration =
492 ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
493 }
494
495 ogg->size = size;
496 ogg_restore (s, 0);
497
498 return 0;
499 }
500
501
502 static int
503 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
504 {
505 struct ogg *ogg = s->priv_data;
506 int i;
507 ogg->curidx = -1;
508 //linear headers seek from start
509 if (ogg_get_headers (s) < 0){
510 return -1;
511 }
512
513 for (i = 0; i < ogg->nstreams; i++)
514 if (ogg->streams[i].header < 0)
515 ogg->streams[i].codec = NULL;
516
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
525 static int
526 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
527 {
528 struct ogg *ogg;
529 struct ogg_stream *os;
530 int idx = -1;
531 int pstart, psize;
532 int64_t fpos;
533
534 //Get an ogg packet
535 do{
536 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
537 return AVERROR(EIO);
538 }while (idx < 0 || !s->streams[idx]);
539
540 ogg = s->priv_data;
541 os = ogg->streams + idx;
542
543 //Alloc a pkt
544 if (av_new_packet (pkt, psize) < 0)
545 return AVERROR(EIO);
546 pkt->stream_index = idx;
547 memcpy (pkt->data, os->buf + pstart, psize);
548
549 if (os->lastpts != AV_NOPTS_VALUE) {
550 pkt->pts = os->lastpts;
551 os->lastpts = AV_NOPTS_VALUE;
552 }
553 if (os->lastdts != AV_NOPTS_VALUE) {
554 pkt->dts = os->lastdts;
555 os->lastdts = AV_NOPTS_VALUE;
556 }
557 if (os->page_end) {
558 if (os->granule != -1LL) {
559 if (os->codec && os->codec->granule_is_start)
560 pkt->pts = ogg_gptopts(s, idx, os->granule, &pkt->dts);
561 else
562 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
563 os->granule = -1LL;
564 } else
565 av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
566 }
567
568 pkt->flags = os->pflags;
569 pkt->duration = os->pduration;
570 pkt->pos = fpos;
571
572 return psize;
573 }
574
575
576 static int
577 ogg_read_close (AVFormatContext * s)
578 {
579 struct ogg *ogg = s->priv_data;
580 int i;
581
582 for (i = 0; i < ogg->nstreams; i++){
583 av_free (ogg->streams[i].buf);
584 av_free (ogg->streams[i].private);
585 }
586 av_free (ogg->streams);
587 return 0;
588 }
589
590
591 static int64_t
592 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
593 int64_t pos_limit)
594 {
595 struct ogg *ogg = s->priv_data;
596 ByteIOContext *bc = s->pb;
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) {
603 pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
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;
612 }
613
614 static int ogg_probe(AVProbeData *p)
615 {
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
624 AVInputFormat ogg_demuxer = {
625 "ogg",
626 NULL_IF_CONFIG_SMALL("Ogg"),
627 sizeof (struct ogg),
628 ogg_probe,
629 ogg_read_header,
630 ogg_read_packet,
631 ogg_read_close,
632 NULL,
633 ogg_read_timestamp,
634 .extensions = "ogg",
635 .metadata_conv = ff_vorbiscomment_metadata_conv,
636 };