free codec extradata in av_close_input_file
[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;
196 os->buf = av_malloc (os->bufsize);
197 memset (os->buf, 0, os->bufsize);
198 os->header = -1;
199
200 st = av_new_stream (s, idx);
201 if (!st)
202 return AVERROR_NOMEM;
203
204 av_set_pts_info(st, 64, 1, 1000000);
205 st->start_time = 0;
206
207 return idx;
208}
209
210static int
211ogg_read_page (AVFormatContext * s, int *str)
212{
213 ByteIOContext *bc = &s->pb;
214 ogg_t *ogg = s->priv_data;
215 ogg_stream_t *os;
216 int i = 0;
217 int flags, nsegs;
218 uint64_t gp;
219 uint32_t serial;
220 uint32_t seq;
221 uint32_t crc;
222 int size, idx;
223 char sync[4];
224 int sp = 0;
225
226 if (get_buffer (bc, sync, 4) < 4)
227 return -1;
228
229 do{
230 int c;
231
232 if (sync[sp & 3] == 'O' &&
233 sync[(sp + 1) & 3] == 'g' &&
234 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
235 break;
236
237 c = url_fgetc (bc);
238 if (c < 0)
239 return -1;
240 sync[sp++ & 3] = c;
241 }while (i++ < MAX_PAGE_SIZE);
242
243 if (i >= MAX_PAGE_SIZE){
244 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
245 return -1;
246 }
247
248 if (url_fgetc (bc) != 0) /* version */
249 return -1;
250
251 flags = url_fgetc (bc);
252 gp = get_le64 (bc);
253 serial = get_le32 (bc);
254 seq = get_le32 (bc);
255 crc = get_le32 (bc);
256 nsegs = url_fgetc (bc);
257
258 idx = ogg_find_stream (ogg, serial);
259 if (idx < 0){
260 idx = ogg_new_stream (s, serial);
261 if (idx < 0)
262 return -1;
263 }
264
265 os = ogg->streams + idx;
266
267 if (get_buffer (bc, os->segments, nsegs) < nsegs)
268 return -1;
269
270 os->nsegs = nsegs;
271 os->segp = 0;
272
273 size = 0;
274 for (i = 0; i < nsegs; i++)
275 size += os->segments[i];
276
277 if (flags & OGG_FLAG_CONT){
278 if (!os->psize){
279 while (os->segp < os->nsegs){
280 int seg = os->segments[os->segp++];
281 os->pstart += seg;
282 if (seg < 255)
283 break;
284 }
285 }
286 }else{
287 os->psize = 0;
288 }
289
290 if (os->bufsize - os->bufpos < size){
2d2f443d 291 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
292 memset (nb, 0, os->bufsize);
293 memcpy (nb, os->buf, os->bufpos);
294 av_free (os->buf);
295 os->buf = nb;
296 }
297
298 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
299 return -1;
300
301 os->lastgp = os->granule;
302 os->bufpos += size;
303 os->granule = gp;
304 os->flags = flags;
305
306 if (str)
307 *str = idx;
308
309 return 0;
310}
311
312static int
313ogg_packet (AVFormatContext * s, int *str)
314{
315 ogg_t *ogg = s->priv_data;
316 int idx;
317 ogg_stream_t *os;
318 int complete = 0;
319 int segp = 0, psize = 0;
320
321#if 0
322 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
323#endif
324
325 do{
326 idx = ogg->curidx;
327
328 while (idx < 0){
329 if (ogg_read_page (s, &idx) < 0)
330 return -1;
331 }
332
333 os = ogg->streams + idx;
334
335#if 0
336 av_log (s, AV_LOG_DEBUG,
337 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
338 idx, os->pstart, os->psize, os->segp, os->nsegs);
339#endif
340
341 if (!os->codec){
342 if (os->header < 0){
343 os->codec = ogg_find_codec (os->buf, os->bufpos);
344 if (!os->codec){
345 os->header = 0;
346 return 0;
347 }
348 }else{
349 return 0;
350 }
351 }
352
353 segp = os->segp;
354 psize = os->psize;
355
356 while (os->segp < os->nsegs){
357 int ss = os->segments[os->segp++];
358 os->psize += ss;
359 if (ss < 255){
360 complete = 1;
361 break;
362 }
363 }
364
365 if (!complete && os->segp == os->nsegs){
2d2f443d 366 uint8_t *nb = av_malloc (os->bufsize);
9146ca37
MR
367 int size = os->bufpos - os->pstart;
368 memset (nb, 0, os->bufsize);
369 memcpy (nb, os->buf + os->pstart, size);
370 av_free (os->buf);
371 os->buf = nb;
372 os->bufpos = size;
373 os->pstart = 0;
374 ogg->curidx = -1;
375 }
376 }while (!complete);
377
378#if 0
379 av_log (s, AV_LOG_DEBUG,
380 "ogg_packet: idx %i, frame size %i, start %i\n",
381 idx, os->psize, os->pstart);
382#endif
383
384 ogg->curidx = idx;
385
386 if (os->header < 0){
387 int hdr = os->codec->header (s, idx);
388 if (!hdr){
389 os->header = os->seq;
390 os->segp = segp;
391 os->psize = psize;
392 ogg->headers = 1;
393 }else{
394 os->pstart += os->psize;
395 os->psize = 0;
396 }
397 }
398
399 if (os->header > -1 && os->seq > os->header){
400 if (os->codec && os->codec->packet)
401 os->codec->packet (s, idx);
402 if (str)
403 *str = idx;
404 }
405
406 os->seq++;
407 if (os->segp == os->nsegs)
408 ogg->curidx = -1;
409
410 return 0;
411}
412
413static int
414ogg_get_headers (AVFormatContext * s)
415{
416 ogg_t *ogg = s->priv_data;
417
418 do{
419 if (ogg_packet (s, NULL) < 0)
420 return -1;
421 }while (!ogg->headers);
422
423#if 0
424 av_log (s, AV_LOG_DEBUG, "found headers\n");
425#endif
426
427 return 0;
428}
429
430static uint64_t
431ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
432{
1ed923ea
MR
433 ogg_t *ogg = s->priv_data;
434 ogg_stream_t *os = ogg->streams + i;
9146ca37
MR
435 uint64_t pts = AV_NOPTS_VALUE;
436
1ed923ea 437 if(os->codec->gptopts){
bb270c08 438 pts = os->codec->gptopts(s, i, gp);
3644cb8f 439 } else {
1ed923ea 440 pts = gp;
9146ca37
MR
441 }
442
443 return pts;
444}
445
446
447static int
448ogg_get_length (AVFormatContext * s)
449{
450 ogg_t *ogg = s->priv_data;
9146ca37 451 int idx = -1, i;
56466d7b 452 offset_t size, end;
69599eea
MR
453
454 if(s->pb.is_streamed)
455 return 0;
9146ca37
MR
456
457// already set
458 if (s->duration != AV_NOPTS_VALUE)
459 return 0;
460
56466d7b
MR
461 size = url_fsize(&s->pb);
462 if(size < 0)
463 return 0;
464 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
465
9146ca37 466 ogg_save (s);
56466d7b 467 url_fseek (&s->pb, end, SEEK_SET);
9146ca37
MR
468
469 while (!ogg_read_page (s, &i)){
470 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
471 idx = i;
472 }
473
474 if (idx != -1){
475 s->streams[idx]->duration =
476 ogg_gptopts (s, idx, ogg->streams[idx].granule);
477 }
478
56466d7b 479 ogg->size = size;
9146ca37
MR
480 ogg_restore (s, 0);
481
482 return 0;
483}
484
485
486static int
487ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
488{
489 ogg_t *ogg = s->priv_data;
490 ogg->curidx = -1;
491 //linear headers seek from start
492 if (ogg_get_headers (s) < 0){
493 return -1;
494 }
495
496 //linear granulepos seek from end
497 ogg_get_length (s);
498
499 //fill the extradata in the per codec callbacks
500 return 0;
501}
502
503
504static int
505ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
506{
507 ogg_t *ogg;
508 ogg_stream_t *os;
509 int idx = -1;
510
115329f1 511 //Get an ogg packet
9146ca37
MR
512 do{
513 if (ogg_packet (s, &idx) < 0)
514 return AVERROR_IO;
515 }while (idx < 0 || !s->streams[idx]);
516
517 ogg = s->priv_data;
518 os = ogg->streams + idx;
519
520 //Alloc a pkt
521 if (av_new_packet (pkt, os->psize) < 0)
522 return AVERROR_IO;
523 pkt->stream_index = idx;
524 memcpy (pkt->data, os->buf + os->pstart, os->psize);
525 if (os->lastgp != -1LL){
526 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
527 os->lastgp = -1;
528 }
529 //next
530 os->pstart += os->psize;
531 os->psize = 0;
532 return os->psize;
533}
534
535
536static int
537ogg_read_close (AVFormatContext * s)
538{
539 ogg_t *ogg = s->priv_data;
540 int i;
541
542 for (i = 0; i < ogg->nstreams; i++){
543 av_free (ogg->streams[i].buf);
1ed923ea 544 av_free (ogg->streams[i].private);
9146ca37
MR
545 }
546 av_free (ogg->streams);
547 return 0;
548}
549
550
551static int
552ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
553 int flags)
554{
56466d7b 555 AVStream *st = s->streams[stream_index];
9146ca37
MR
556 ogg_t *ogg = s->priv_data;
557 ByteIOContext *bc = &s->pb;
558 uint64_t min = 0, max = ogg->size;
56466d7b 559 uint64_t tmin = 0, tmax = st->duration;
9146ca37
MR
560 int64_t pts = AV_NOPTS_VALUE;
561
562 ogg_save (s);
563
564 while (min <= max){
17929c04 565 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
9146ca37
MR
566 int i = -1;
567
568 url_fseek (bc, p, SEEK_SET);
569
570 while (!ogg_read_page (s, &i)){
56466d7b
MR
571 if (i == stream_index && ogg->streams[i].granule != 0 &&
572 ogg->streams[i].granule != -1)
9146ca37
MR
573 break;
574 }
575
576 if (i == -1)
577 break;
578
579 pts = ogg_gptopts (s, i, ogg->streams[i].granule);
580 p = url_ftell (bc);
581
56466d7b 582 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
9146ca37
MR
583 break;
584
585 if (pts > target_ts){
586 max = p;
587 tmax = pts;
588 }else{
589 min = p;
590 tmin = pts;
591 }
592 }
593
56466d7b 594 if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
9146ca37
MR
595 ogg_restore (s, 1);
596 ogg_reset (ogg);
597 }else{
598 ogg_restore (s, 0);
599 pts = AV_NOPTS_VALUE;
600 }
601
602 return pts;
603
604#if 0
605 //later...
606 int64_t pos;
607 if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
608 return -1;
609 pos = url_ftell (&s->pb);
610 ogg_read_timestamp (s, stream_index, &pos, pos - 1);
611#endif
612
613}
614
615#if 0
616static int64_t
617ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
618 int64_t pos_limit)
619{
620 ogg_t *ogg = s->priv_data;
621 ByteIOContext *bc = &s->pb;
622 int64_t pos, pts;
623
624 if (*pos_arg < 0)
625 return AV_NOPTS_VALUE;
626
627 pos = *pos_arg;
628}
629#endif
630
2e70e4aa
MR
631static int ogg_probe(AVProbeData *p)
632{
633 if (p->buf_size < 6)
634 return 0;
635 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
636 p->buf[2] == 'g' && p->buf[3] == 'S' &&
637 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
638 return AVPROBE_SCORE_MAX;
639 else
640 return 0;
641}
642
9146ca37
MR
643static AVInputFormat ogg_iformat = {
644 "ogg",
645 "Ogg",
646 sizeof (ogg_t),
2e70e4aa 647 ogg_probe,
9146ca37
MR
648 ogg_read_header,
649 ogg_read_packet,
650 ogg_read_close,
651 ogg_read_seek,
115329f1 652// ogg_read_timestamp,
9146ca37
MR
653 .extensions = "ogg",
654};
655
656int
657ogg_init (void)
658{
a9e35095 659#if 0 // CONFIG_MUXERS
9146ca37
MR
660 av_register_output_format (&ogg_oformat);
661#endif
662 av_register_input_format (&ogg_iformat);
663 return 0;
664}