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