10l: don't allocate a new buffer quite so often
[libav.git] / libavformat / ogg2.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>
34#include "ogg2.h"
35#include "avformat.h"
36
37#define MAX_PAGE_SIZE 65307
38#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40static ogg_codec_t *ogg_codecs[] = {
41 &vorbis_codec,
1ed923ea 42 &theora_codec,
bcfc40ae 43 &flac_codec,
e1203ac0
MR
44 &ogm_video_codec,
45 &ogm_audio_codec,
46 &ogm_old_codec,
9146ca37
MR
47 NULL
48};
49
a9e35095 50#if 0 // CONFIG_MUXERS
9146ca37
MR
51static int
52ogg_write_header (AVFormatContext * avfcontext)
53{
54}
55
56static int
57ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
58{
59}
60
61
62static int
63ogg_write_trailer (AVFormatContext * avfcontext)
64{
65}
66
67
68static AVOutputFormat ogg_oformat = {
69 "ogg",
70 "Ogg Vorbis",
71 "audio/x-vorbis",
72 "ogg",
73 sizeof (OggContext),
74 CODEC_ID_VORBIS,
75 0,
76 ogg_write_header,
77 ogg_write_packet,
78 ogg_write_trailer,
79};
a9e35095 80#endif //CONFIG_MUXERS
9146ca37
MR
81
82//FIXME We could avoid some structure duplication
83static int
84ogg_save (AVFormatContext * s)
85{
86 ogg_t *ogg = s->priv_data;
87 ogg_state_t *ost =
ad3aa874 88 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
9146ca37
MR
89 int i;
90 ost->pos = url_ftell (&s->pb);;
91 ost->curidx = ogg->curidx;
92 ost->next = ogg->state;
93 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
94
95 for (i = 0; i < ogg->nstreams; i++){
96 ogg_stream_t *os = ogg->streams + i;
97 os->buf = av_malloc (os->bufsize);
98 memset (os->buf, 0, os->bufsize);
99 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
100 }
101
102 ogg->state = ost;
103
104 return 0;
105}
106
107static int
108ogg_restore (AVFormatContext * s, int discard)
109{
110 ogg_t *ogg = s->priv_data;
111 ByteIOContext *bc = &s->pb;
112 ogg_state_t *ost = ogg->state;
113 int i;
114
115 if (!ost)
116 return 0;
117
118 ogg->state = ost->next;
119
120 if (!discard){
121 for (i = 0; i < ogg->nstreams; i++)
122 av_free (ogg->streams[i].buf);
123
124 url_fseek (bc, ost->pos, SEEK_SET);
125 ogg->curidx = ost->curidx;
126 memcpy (ogg->streams, ost->streams,
127 ogg->nstreams * sizeof (*ogg->streams));
128 }
129
130 av_free (ost);
131
132 return 0;
133}
134
135static int
136ogg_reset (ogg_t * ogg)
137{
138 int i;
139
140 for (i = 0; i < ogg->nstreams; i++){
141 ogg_stream_t *os = ogg->streams + i;
142 os->bufpos = 0;
143 os->pstart = 0;
144 os->psize = 0;
145 os->granule = -1;
146 os->lastgp = -1;
147 os->nsegs = 0;
148 os->segp = 0;
149 }
150
151 ogg->curidx = -1;
152
153 return 0;
154}
155
156static ogg_codec_t *
2d2f443d 157ogg_find_codec (uint8_t * buf, int size)
9146ca37
MR
158{
159 int i;
160
161 for (i = 0; ogg_codecs[i]; i++)
162 if (size >= ogg_codecs[i]->magicsize &&
163 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
164 return ogg_codecs[i];
165
166 return NULL;
167}
168
169static int
170ogg_find_stream (ogg_t * ogg, int serial)
171{
172 int i;
173
174 for (i = 0; i < ogg->nstreams; i++)
175 if (ogg->streams[i].serial == serial)
176 return i;
177
178 return -1;
179}
180
181static int
182ogg_new_stream (AVFormatContext * s, uint32_t serial)
183{
184
185 ogg_t *ogg = s->priv_data;
186 int idx = ogg->nstreams++;
187 AVStream *st;
188 ogg_stream_t *os;
189
190 ogg->streams = av_realloc (ogg->streams,
191 ogg->nstreams * sizeof (*ogg->streams));
192 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
193 os = ogg->streams + idx;
194 os->serial = serial;
195 os->bufsize = DECODER_BUFFER_SIZE;
40c5e1fa 196 os->buf = av_malloc(os->bufsize);
9146ca37
MR
197 os->header = -1;
198
199 st = av_new_stream (s, idx);
200 if (!st)
201 return AVERROR_NOMEM;
202
203 av_set_pts_info(st, 64, 1, 1000000);
204 st->start_time = 0;
205
206 return idx;
207}
208
209static int
12a195e3
MR
210ogg_new_buf(ogg_t *ogg, int idx)
211{
212 ogg_stream_t *os = ogg->streams + idx;
213 u_char *nb = av_malloc(os->bufsize);
214 int size = os->bufpos - os->pstart;
215 if(os->buf){
216 memcpy(nb, os->buf + os->pstart, size);
217 av_free(os->buf);
218 }
219 os->buf = nb;
220 os->bufpos = size;
221 os->pstart = 0;
222
223 return 0;
224}
225
226static int
9146ca37
MR
227ogg_read_page (AVFormatContext * s, int *str)
228{
229 ByteIOContext *bc = &s->pb;
230 ogg_t *ogg = s->priv_data;
231 ogg_stream_t *os;
232 int i = 0;
233 int flags, nsegs;
234 uint64_t gp;
235 uint32_t serial;
236 uint32_t seq;
237 uint32_t crc;
238 int size, idx;
239 char sync[4];
240 int sp = 0;
241
242 if (get_buffer (bc, sync, 4) < 4)
243 return -1;
244
245 do{
246 int c;
247
248 if (sync[sp & 3] == 'O' &&
249 sync[(sp + 1) & 3] == 'g' &&
250 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
251 break;
252
253 c = url_fgetc (bc);
254 if (c < 0)
255 return -1;
256 sync[sp++ & 3] = c;
257 }while (i++ < MAX_PAGE_SIZE);
258
259 if (i >= MAX_PAGE_SIZE){
260 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
261 return -1;
262 }
263
264 if (url_fgetc (bc) != 0) /* version */
265 return -1;
266
267 flags = url_fgetc (bc);
268 gp = get_le64 (bc);
269 serial = get_le32 (bc);
270 seq = get_le32 (bc);
271 crc = get_le32 (bc);
272 nsegs = url_fgetc (bc);
273
274 idx = ogg_find_stream (ogg, serial);
275 if (idx < 0){
276 idx = ogg_new_stream (s, serial);
277 if (idx < 0)
278 return -1;
279 }
280
281 os = ogg->streams + idx;
282
40c5e1fa 283 if(os->psize > 0)
12a195e3
MR
284 ogg_new_buf(ogg, idx);
285
9146ca37
MR
286 if (get_buffer (bc, os->segments, nsegs) < nsegs)
287 return -1;
288
289 os->nsegs = nsegs;
290 os->segp = 0;
291
292 size = 0;
293 for (i = 0; i < nsegs; i++)
294 size += os->segments[i];
295
296 if (flags & OGG_FLAG_CONT){
297 if (!os->psize){
298 while (os->segp < os->nsegs){
299 int seg = os->segments[os->segp++];
300 os->pstart += seg;
301 if (seg < 255)
302 break;
303 }
304 }
305 }else{
306 os->psize = 0;
307 }
308
309 if (os->bufsize - os->bufpos < size){
2d2f443d 310 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
311 memset (nb, 0, os->bufsize);
312 memcpy (nb, os->buf, os->bufpos);
313 av_free (os->buf);
314 os->buf = nb;
315 }
316
317 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
318 return -1;
319
320 os->lastgp = os->granule;
321 os->bufpos += size;
322 os->granule = gp;
323 os->flags = flags;
324
325 if (str)
326 *str = idx;
327
328 return 0;
329}
330
331static int
12a195e3 332ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
9146ca37
MR
333{
334 ogg_t *ogg = s->priv_data;
335 int idx;
336 ogg_stream_t *os;
337 int complete = 0;
338 int segp = 0, psize = 0;
339
340#if 0
341 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
342#endif
343
344 do{
345 idx = ogg->curidx;
346
347 while (idx < 0){
348 if (ogg_read_page (s, &idx) < 0)
349 return -1;
350 }
351
352 os = ogg->streams + idx;
353
354#if 0
355 av_log (s, AV_LOG_DEBUG,
356 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
357 idx, os->pstart, os->psize, os->segp, os->nsegs);
358#endif
359
360 if (!os->codec){
361 if (os->header < 0){
362 os->codec = ogg_find_codec (os->buf, os->bufpos);
363 if (!os->codec){
364 os->header = 0;
365 return 0;
366 }
367 }else{
368 return 0;
369 }
370 }
371
372 segp = os->segp;
373 psize = os->psize;
374
375 while (os->segp < os->nsegs){
376 int ss = os->segments[os->segp++];
377 os->psize += ss;
378 if (ss < 255){
379 complete = 1;
380 break;
381 }
382 }
383
384 if (!complete && os->segp == os->nsegs){
9146ca37
MR
385 ogg->curidx = -1;
386 }
387 }while (!complete);
388
389#if 0
390 av_log (s, AV_LOG_DEBUG,
391 "ogg_packet: idx %i, frame size %i, start %i\n",
392 idx, os->psize, os->pstart);
393#endif
394
395 ogg->curidx = idx;
396
397 if (os->header < 0){
398 int hdr = os->codec->header (s, idx);
399 if (!hdr){
400 os->header = os->seq;
401 os->segp = segp;
402 os->psize = psize;
403 ogg->headers = 1;
404 }else{
405 os->pstart += os->psize;
406 os->psize = 0;
407 }
408 }
409
410 if (os->header > -1 && os->seq > os->header){
411 if (os->codec && os->codec->packet)
412 os->codec->packet (s, idx);
413 if (str)
414 *str = idx;
12a195e3
MR
415 if (dstart)
416 *dstart = os->pstart;
417 if (dsize)
418 *dsize = os->psize;
419 os->pstart += os->psize;
420 os->psize = 0;
9146ca37
MR
421 }
422
423 os->seq++;
424 if (os->segp == os->nsegs)
425 ogg->curidx = -1;
426
427 return 0;
428}
429
430static int
431ogg_get_headers (AVFormatContext * s)
432{
433 ogg_t *ogg = s->priv_data;
434
435 do{
12a195e3 436 if (ogg_packet (s, NULL, NULL, NULL) < 0)
9146ca37
MR
437 return -1;
438 }while (!ogg->headers);
439
440#if 0
441 av_log (s, AV_LOG_DEBUG, "found headers\n");
442#endif
443
444 return 0;
445}
446
447static uint64_t
448ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
449{
1ed923ea
MR
450 ogg_t *ogg = s->priv_data;
451 ogg_stream_t *os = ogg->streams + i;
9146ca37
MR
452 uint64_t pts = AV_NOPTS_VALUE;
453
1ed923ea 454 if(os->codec->gptopts){
bb270c08 455 pts = os->codec->gptopts(s, i, gp);
3644cb8f 456 } else {
1ed923ea 457 pts = gp;
9146ca37
MR
458 }
459
460 return pts;
461}
462
463
464static int
465ogg_get_length (AVFormatContext * s)
466{
467 ogg_t *ogg = s->priv_data;
9146ca37 468 int idx = -1, i;
56466d7b 469 offset_t size, end;
69599eea
MR
470
471 if(s->pb.is_streamed)
472 return 0;
9146ca37
MR
473
474// already set
475 if (s->duration != AV_NOPTS_VALUE)
476 return 0;
477
56466d7b
MR
478 size = url_fsize(&s->pb);
479 if(size < 0)
480 return 0;
481 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
482
9146ca37 483 ogg_save (s);
56466d7b 484 url_fseek (&s->pb, end, SEEK_SET);
9146ca37
MR
485
486 while (!ogg_read_page (s, &i)){
487 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
488 idx = i;
489 }
490
491 if (idx != -1){
492 s->streams[idx]->duration =
493 ogg_gptopts (s, idx, ogg->streams[idx].granule);
494 }
495
56466d7b 496 ogg->size = size;
9146ca37
MR
497 ogg_restore (s, 0);
498
499 return 0;
500}
501
502
503static int
504ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
505{
506 ogg_t *ogg = s->priv_data;
507 ogg->curidx = -1;
508 //linear headers seek from start
509 if (ogg_get_headers (s) < 0){
510 return -1;
511 }
512
513 //linear granulepos seek from end
514 ogg_get_length (s);
515
516 //fill the extradata in the per codec callbacks
517 return 0;
518}
519
520
521static int
522ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
523{
524 ogg_t *ogg;
525 ogg_stream_t *os;
526 int idx = -1;
12a195e3 527 int pstart, psize;
9146ca37 528
115329f1 529 //Get an ogg packet
9146ca37 530 do{
12a195e3 531 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
9146ca37
MR
532 return AVERROR_IO;
533 }while (idx < 0 || !s->streams[idx]);
534
535 ogg = s->priv_data;
536 os = ogg->streams + idx;
537
538 //Alloc a pkt
12a195e3 539 if (av_new_packet (pkt, psize) < 0)
9146ca37
MR
540 return AVERROR_IO;
541 pkt->stream_index = idx;
12a195e3 542 memcpy (pkt->data, os->buf + pstart, psize);
9146ca37
MR
543 if (os->lastgp != -1LL){
544 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
545 os->lastgp = -1;
546 }
12a195e3
MR
547
548 return psize;
9146ca37
MR
549}
550
551
552static int
553ogg_read_close (AVFormatContext * s)
554{
555 ogg_t *ogg = s->priv_data;
556 int i;
557
558 for (i = 0; i < ogg->nstreams; i++){
559 av_free (ogg->streams[i].buf);
1ed923ea 560 av_free (ogg->streams[i].private);
9146ca37
MR
561 }
562 av_free (ogg->streams);
563 return 0;
564}
565
566
567static int
568ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
569 int flags)
570{
56466d7b 571 AVStream *st = s->streams[stream_index];
9146ca37
MR
572 ogg_t *ogg = s->priv_data;
573 ByteIOContext *bc = &s->pb;
574 uint64_t min = 0, max = ogg->size;
56466d7b 575 uint64_t tmin = 0, tmax = st->duration;
9146ca37
MR
576 int64_t pts = AV_NOPTS_VALUE;
577
578 ogg_save (s);
579
580 while (min <= max){
17929c04 581 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
9146ca37
MR
582 int i = -1;
583
584 url_fseek (bc, p, SEEK_SET);
585
586 while (!ogg_read_page (s, &i)){
56466d7b
MR
587 if (i == stream_index && ogg->streams[i].granule != 0 &&
588 ogg->streams[i].granule != -1)
9146ca37
MR
589 break;
590 }
591
592 if (i == -1)
593 break;
594
595 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
596 p = url_ftell (bc);
597
56466d7b 598 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
9146ca37
MR
599 break;
600
601 if (pts > target_ts){
602 max = p;
603 tmax = pts;
604 }else{
605 min = p;
606 tmin = pts;
607 }
608 }
609
56466d7b 610 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
9146ca37
MR
611 ogg_restore (s, 1);
612 ogg_reset (ogg);
613 }else{
614 ogg_restore (s, 0);
615 pts = AV_NOPTS_VALUE;
616 }
617
618 return pts;
619
620#if 0
621 //later...
622 int64_t pos;
623 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
624 return -1;
625 pos = url_ftell (&s->pb);
626 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
627#endif
628
629}
630
631#if 0
632static int64_t
633ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
634 int64_t pos_limit)
635{
636 ogg_t *ogg = s->priv_data;
637 ByteIOContext *bc = &s->pb;
638 int64_t pos, pts;
639
640 if (*pos_arg < 0)
641 return AV_NOPTS_VALUE;
642
643 pos = *pos_arg;
644}
645#endif
646
2e70e4aa
MR
647static int ogg_probe(AVProbeData *p)
648{
649 if (p->buf_size < 6)
650 return 0;
651 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
652 p->buf[2] == 'g' && p->buf[3] == 'S' &&
653 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
654 return AVPROBE_SCORE_MAX;
655 else
656 return 0;
657}
658
9146ca37
MR
659static AVInputFormat ogg_iformat = {
660 "ogg",
661 "Ogg",
662 sizeof (ogg_t),
2e70e4aa 663 ogg_probe,
9146ca37
MR
664 ogg_read_header,
665 ogg_read_packet,
666 ogg_read_close,
667 ogg_read_seek,
115329f1 668// ogg_read_timestamp,
9146ca37
MR
669 .extensions = "ogg",
670};
671
672int
673ogg_init (void)
674{
a9e35095 675#if 0 // CONFIG_MUXERS
9146ca37
MR
676 av_register_output_format (&ogg_oformat);
677#endif
678 av_register_input_format (&ogg_iformat);
679 return 0;
680}