avio: avio_ prefix for url_fseek
[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 #include "vorbiscomment.h"
37
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
41 static const struct ogg_codec * const ogg_codecs[] = {
42 &ff_skeleton_codec,
43 &ff_dirac_codec,
44 &ff_speex_codec,
45 &ff_vorbis_codec,
46 &ff_theora_codec,
47 &ff_flac_codec,
48 &ff_old_dirac_codec,
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,
54 NULL
55 };
56
57 //FIXME We could avoid some structure duplication
58 static int
59 ogg_save (AVFormatContext * s)
60 {
61 struct ogg *ogg = s->priv_data;
62 struct ogg_state *ost =
63 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64 int i;
65 ost->pos = url_ftell (s->pb);
66 ost->curidx = ogg->curidx;
67 ost->next = ogg->state;
68 ost->nstreams = ogg->nstreams;
69 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70
71 for (i = 0; i < ogg->nstreams; i++){
72 struct ogg_stream *os = ogg->streams + i;
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
83 static int
84 ogg_restore (AVFormatContext * s, int discard)
85 {
86 struct ogg *ogg = s->priv_data;
87 AVIOContext *bc = s->pb;
88 struct ogg_state *ost = ogg->state;
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 avio_seek (bc, ost->pos, SEEK_SET);
101 ogg->curidx = ost->curidx;
102 ogg->nstreams = ost->nstreams;
103 memcpy(ogg->streams, ost->streams,
104 ost->nstreams * sizeof(*ogg->streams));
105 }
106
107 av_free (ost);
108
109 return 0;
110 }
111
112 static int
113 ogg_reset (struct ogg * ogg)
114 {
115 int i;
116
117 for (i = 0; i < ogg->nstreams; i++){
118 struct ogg_stream *os = ogg->streams + i;
119 os->bufpos = 0;
120 os->pstart = 0;
121 os->psize = 0;
122 os->granule = -1;
123 os->lastpts = AV_NOPTS_VALUE;
124 os->lastdts = AV_NOPTS_VALUE;
125 os->sync_pos = -1;
126 os->page_pos = 0;
127 os->nsegs = 0;
128 os->segp = 0;
129 os->incomplete = 0;
130 }
131
132 ogg->curidx = -1;
133
134 return 0;
135 }
136
137 static const struct ogg_codec *
138 ogg_find_codec (uint8_t * buf, int size)
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
150 static int
151 ogg_new_stream (AVFormatContext * s, uint32_t serial)
152 {
153
154 struct ogg *ogg = s->priv_data;
155 int idx = ogg->nstreams++;
156 AVStream *st;
157 struct ogg_stream *os;
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;
165 os->buf = av_malloc(os->bufsize);
166 os->header = -1;
167
168 st = av_new_stream (s, idx);
169 if (!st)
170 return AVERROR(ENOMEM);
171
172 av_set_pts_info(st, 64, 1, 1000000);
173
174 return idx;
175 }
176
177 static int
178 ogg_new_buf(struct ogg *ogg, int idx)
179 {
180 struct ogg_stream *os = ogg->streams + idx;
181 uint8_t *nb = av_malloc(os->bufsize);
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
194 static int
195 ogg_read_page (AVFormatContext * s, int *str)
196 {
197 AVIOContext *bc = s->pb;
198 struct ogg *ogg = s->priv_data;
199 struct ogg_stream *os;
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;
207 uint8_t sync[4];
208 int sp = 0;
209
210 if (avio_read (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 = avio_rl64 (bc);
237 serial = avio_rl32 (bc);
238 seq = avio_rl32 (bc);
239 crc = avio_rl32 (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;
250 os->page_pos = url_ftell(bc) - 27;
251
252 if(os->psize > 0)
253 ogg_new_buf(ogg, idx);
254
255 if (avio_read (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
265 if (flags & OGG_FLAG_CONT || os->incomplete){
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)
271 break;
272 }
273 os->sync_pos = os->page_pos;
274 }
275 }else{
276 os->psize = 0;
277 os->sync_pos = os->page_pos;
278 }
279
280 if (os->bufsize - os->bufpos < size){
281 uint8_t *nb = av_malloc (os->bufsize *= 2);
282 memcpy (nb, os->buf, os->bufpos);
283 av_free (os->buf);
284 os->buf = nb;
285 }
286
287 if (avio_read (bc, os->buf + os->bufpos, size) < size)
288 return -1;
289
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
300 static int
301 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
302 {
303 struct ogg *ogg = s->priv_data;
304 int idx, i;
305 struct ogg_stream *os;
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){
354 ogg->curidx = -1;
355 os->incomplete = 1;
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 if (os->granule == -1)
366 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
367
368 ogg->curidx = idx;
369 os->incomplete = 0;
370
371 if (os->header) {
372 os->header = os->codec->header (s, idx);
373 if (!os->header){
374 os->segp = segp;
375 os->psize = psize;
376
377 // We have reached the first non-header packet in this stream.
378 // Unfortunately more header packets may still follow for others,
379 // so we reset this later unless we are done with the headers
380 // for all streams.
381 ogg->headers = 1;
382
383 // Update the header state for all streams and
384 // compute the data_offset.
385 if (!s->data_offset)
386 s->data_offset = os->sync_pos;
387 for (i = 0; i < ogg->nstreams; i++) {
388 struct ogg_stream *cur_os = ogg->streams + i;
389 if (cur_os->header > 0)
390 ogg->headers = 0;
391
392 // if we have a partial non-header packet, its start is
393 // obviously at or after the data start
394 if (cur_os->incomplete)
395 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
396 }
397 }else{
398 os->pstart += os->psize;
399 os->psize = 0;
400 }
401 } else {
402 os->pflags = 0;
403 os->pduration = 0;
404 if (os->codec && os->codec->packet)
405 os->codec->packet (s, idx);
406 if (str)
407 *str = idx;
408 if (dstart)
409 *dstart = os->pstart;
410 if (dsize)
411 *dsize = os->psize;
412 if (fpos)
413 *fpos = os->sync_pos;
414 os->pstart += os->psize;
415 os->psize = 0;
416 os->sync_pos = os->page_pos;
417 }
418
419 // determine whether there are more complete packets in this page
420 // if not, the page's granule will apply to this packet
421 os->page_end = 1;
422 for (i = os->segp; i < os->nsegs; i++)
423 if (os->segments[i] < 255) {
424 os->page_end = 0;
425 break;
426 }
427
428 if (os->segp == os->nsegs)
429 ogg->curidx = -1;
430
431 return 0;
432 }
433
434 static int
435 ogg_get_headers (AVFormatContext * s)
436 {
437 struct ogg *ogg = s->priv_data;
438
439 do{
440 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
441 return -1;
442 }while (!ogg->headers);
443
444 #if 0
445 av_log (s, AV_LOG_DEBUG, "found headers\n");
446 #endif
447
448 return 0;
449 }
450
451 static int
452 ogg_get_length (AVFormatContext * s)
453 {
454 struct ogg *ogg = s->priv_data;
455 int i;
456 int64_t size, end;
457
458 if(url_is_streamed(s->pb))
459 return 0;
460
461 // already set
462 if (s->duration != AV_NOPTS_VALUE)
463 return 0;
464
465 size = url_fsize(s->pb);
466 if(size < 0)
467 return 0;
468 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
469
470 ogg_save (s);
471 avio_seek (s->pb, end, SEEK_SET);
472
473 while (!ogg_read_page (s, &i)){
474 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
475 ogg->streams[i].codec) {
476 s->streams[i]->duration =
477 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
478 if (s->streams[i]->start_time != AV_NOPTS_VALUE)
479 s->streams[i]->duration -= s->streams[i]->start_time;
480 }
481 }
482
483 ogg_restore (s, 0);
484
485 return 0;
486 }
487
488
489 static int
490 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
491 {
492 struct ogg *ogg = s->priv_data;
493 int i;
494 ogg->curidx = -1;
495 //linear headers seek from start
496 if (ogg_get_headers (s) < 0){
497 return -1;
498 }
499
500 for (i = 0; i < ogg->nstreams; i++)
501 if (ogg->streams[i].header < 0)
502 ogg->streams[i].codec = NULL;
503
504 //linear granulepos seek from end
505 ogg_get_length (s);
506
507 //fill the extradata in the per codec callbacks
508 return 0;
509 }
510
511 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
512 {
513 struct ogg *ogg = s->priv_data;
514 struct ogg_stream *os = ogg->streams + idx;
515 int64_t pts = AV_NOPTS_VALUE;
516
517 if (dts)
518 *dts = AV_NOPTS_VALUE;
519
520 if (os->lastpts != AV_NOPTS_VALUE) {
521 pts = os->lastpts;
522 os->lastpts = AV_NOPTS_VALUE;
523 }
524 if (os->lastdts != AV_NOPTS_VALUE) {
525 if (dts)
526 *dts = os->lastdts;
527 os->lastdts = AV_NOPTS_VALUE;
528 }
529 if (os->page_end) {
530 if (os->granule != -1LL) {
531 if (os->codec && os->codec->granule_is_start)
532 pts = ogg_gptopts(s, idx, os->granule, dts);
533 else
534 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
535 os->granule = -1LL;
536 }
537 }
538 return pts;
539 }
540
541 static int
542 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
543 {
544 struct ogg *ogg;
545 struct ogg_stream *os;
546 int idx = -1;
547 int pstart, psize;
548 int64_t fpos, pts, dts;
549
550 //Get an ogg packet
551 retry:
552 do{
553 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
554 return AVERROR(EIO);
555 }while (idx < 0 || !s->streams[idx]);
556
557 ogg = s->priv_data;
558 os = ogg->streams + idx;
559
560 // pflags might not be set until after this
561 pts = ogg_calc_pts(s, idx, &dts);
562
563 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
564 goto retry;
565 os->keyframe_seek = 0;
566
567 //Alloc a pkt
568 if (av_new_packet (pkt, psize) < 0)
569 return AVERROR(EIO);
570 pkt->stream_index = idx;
571 memcpy (pkt->data, os->buf + pstart, psize);
572
573 pkt->pts = pts;
574 pkt->dts = dts;
575 pkt->flags = os->pflags;
576 pkt->duration = os->pduration;
577 pkt->pos = fpos;
578
579 return psize;
580 }
581
582
583 static int
584 ogg_read_close (AVFormatContext * s)
585 {
586 struct ogg *ogg = s->priv_data;
587 int i;
588
589 for (i = 0; i < ogg->nstreams; i++){
590 av_free (ogg->streams[i].buf);
591 av_free (ogg->streams[i].private);
592 }
593 av_free (ogg->streams);
594 return 0;
595 }
596
597
598 static int64_t
599 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
600 int64_t pos_limit)
601 {
602 struct ogg *ogg = s->priv_data;
603 struct ogg_stream *os = ogg->streams + stream_index;
604 AVIOContext *bc = s->pb;
605 int64_t pts = AV_NOPTS_VALUE;
606 int i;
607 avio_seek(bc, *pos_arg, SEEK_SET);
608 ogg_reset(ogg);
609
610 while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
611 if (i == stream_index) {
612 pts = ogg_calc_pts(s, i, NULL);
613 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
614 pts = AV_NOPTS_VALUE;
615 }
616 if (pts != AV_NOPTS_VALUE)
617 break;
618 }
619 ogg_reset(ogg);
620 return pts;
621 }
622
623 static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
624 {
625 struct ogg *ogg = s->priv_data;
626 struct ogg_stream *os = ogg->streams + stream_index;
627 int ret;
628
629 // Try seeking to a keyframe first. If this fails (very possible),
630 // av_seek_frame will fall back to ignoring keyframes
631 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
632 && !(flags & AVSEEK_FLAG_ANY))
633 os->keyframe_seek = 1;
634
635 ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
636 if (ret < 0)
637 os->keyframe_seek = 0;
638 return ret;
639 }
640
641 static int ogg_probe(AVProbeData *p)
642 {
643 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
644 p->buf[2] == 'g' && p->buf[3] == 'S' &&
645 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
646 return AVPROBE_SCORE_MAX;
647 else
648 return 0;
649 }
650
651 AVInputFormat ff_ogg_demuxer = {
652 "ogg",
653 NULL_IF_CONFIG_SMALL("Ogg"),
654 sizeof (struct ogg),
655 ogg_probe,
656 ogg_read_header,
657 ogg_read_packet,
658 ogg_read_close,
659 ogg_read_seek,
660 ogg_read_timestamp,
661 .extensions = "ogg",
662 .flags = AVFMT_GENERIC_INDEX,
663 };