10l: don't allocate a new buffer quite so often
[libav.git] / libavformat / ogg2.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 "ogg2.h"
35 #include "avformat.h"
36
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40 static ogg_codec_t *ogg_codecs[] = {
41 &vorbis_codec,
42 &theora_codec,
43 &flac_codec,
44 &ogm_video_codec,
45 &ogm_audio_codec,
46 &ogm_old_codec,
47 NULL
48 };
49
50 #if 0 // CONFIG_MUXERS
51 static int
52 ogg_write_header (AVFormatContext * avfcontext)
53 {
54 }
55
56 static int
57 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
58 {
59 }
60
61
62 static int
63 ogg_write_trailer (AVFormatContext * avfcontext)
64 {
65 }
66
67
68 static 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 };
80 #endif //CONFIG_MUXERS
81
82 //FIXME We could avoid some structure duplication
83 static int
84 ogg_save (AVFormatContext * s)
85 {
86 ogg_t *ogg = s->priv_data;
87 ogg_state_t *ost =
88 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
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
107 static int
108 ogg_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
135 static int
136 ogg_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
156 static ogg_codec_t *
157 ogg_find_codec (uint8_t * buf, int size)
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
169 static int
170 ogg_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
181 static int
182 ogg_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;
196 os->buf = av_malloc(os->bufsize);
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
209 static int
210 ogg_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
226 static int
227 ogg_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
283 if(os->psize > 0)
284 ogg_new_buf(ogg, idx);
285
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){
310 uint8_t *nb = av_malloc (os->bufsize *= 2);
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
331 static int
332 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
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){
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;
415 if (dstart)
416 *dstart = os->pstart;
417 if (dsize)
418 *dsize = os->psize;
419 os->pstart += os->psize;
420 os->psize = 0;
421 }
422
423 os->seq++;
424 if (os->segp == os->nsegs)
425 ogg->curidx = -1;
426
427 return 0;
428 }
429
430 static int
431 ogg_get_headers (AVFormatContext * s)
432 {
433 ogg_t *ogg = s->priv_data;
434
435 do{
436 if (ogg_packet (s, NULL, NULL, NULL) < 0)
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
447 static uint64_t
448 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
449 {
450 ogg_t *ogg = s->priv_data;
451 ogg_stream_t *os = ogg->streams + i;
452 uint64_t pts = AV_NOPTS_VALUE;
453
454 if(os->codec->gptopts){
455 pts = os->codec->gptopts(s, i, gp);
456 } else {
457 pts = gp;
458 }
459
460 return pts;
461 }
462
463
464 static int
465 ogg_get_length (AVFormatContext * s)
466 {
467 ogg_t *ogg = s->priv_data;
468 int idx = -1, i;
469 offset_t size, end;
470
471 if(s->pb.is_streamed)
472 return 0;
473
474 // already set
475 if (s->duration != AV_NOPTS_VALUE)
476 return 0;
477
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
483 ogg_save (s);
484 url_fseek (&s->pb, end, SEEK_SET);
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
496 ogg->size = size;
497 ogg_restore (s, 0);
498
499 return 0;
500 }
501
502
503 static int
504 ogg_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
521 static int
522 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
523 {
524 ogg_t *ogg;
525 ogg_stream_t *os;
526 int idx = -1;
527 int pstart, psize;
528
529 //Get an ogg packet
530 do{
531 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
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
539 if (av_new_packet (pkt, psize) < 0)
540 return AVERROR_IO;
541 pkt->stream_index = idx;
542 memcpy (pkt->data, os->buf + pstart, psize);
543 if (os->lastgp != -1LL){
544 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
545 os->lastgp = -1;
546 }
547
548 return psize;
549 }
550
551
552 static int
553 ogg_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);
560 av_free (ogg->streams[i].private);
561 }
562 av_free (ogg->streams);
563 return 0;
564 }
565
566
567 static int
568 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
569 int flags)
570 {
571 AVStream *st = s->streams[stream_index];
572 ogg_t *ogg = s->priv_data;
573 ByteIOContext *bc = &s->pb;
574 uint64_t min = 0, max = ogg->size;
575 uint64_t tmin = 0, tmax = st->duration;
576 int64_t pts = AV_NOPTS_VALUE;
577
578 ogg_save (s);
579
580 while (min <= max){
581 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
582 int i = -1;
583
584 url_fseek (bc, p, SEEK_SET);
585
586 while (!ogg_read_page (s, &i)){
587 if (i == stream_index && ogg->streams[i].granule != 0 &&
588 ogg->streams[i].granule != -1)
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
598 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
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
610 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
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
632 static int64_t
633 ogg_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
647 static 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
659 static AVInputFormat ogg_iformat = {
660 "ogg",
661 "Ogg",
662 sizeof (ogg_t),
663 ogg_probe,
664 ogg_read_header,
665 ogg_read_packet,
666 ogg_read_close,
667 ogg_read_seek,
668 // ogg_read_timestamp,
669 .extensions = "ogg",
670 };
671
672 int
673 ogg_init (void)
674 {
675 #if 0 // CONFIG_MUXERS
676 av_register_output_format (&ogg_oformat);
677 #endif
678 av_register_input_format (&ogg_iformat);
679 return 0;
680 }