Add support for speex in ogg
[libav.git] / libavformat / oggdec.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>
a0ddef24 34#include "oggdec.h"
9146ca37
MR
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[] = {
cb4ddf77 41 &speex_codec,
9146ca37 42 &vorbis_codec,
1ed923ea 43 &theora_codec,
bcfc40ae 44 &flac_codec,
880e3ef4 45 &old_flac_codec,
e1203ac0
MR
46 &ogm_video_codec,
47 &ogm_audio_codec,
2331e31c 48 &ogm_text_codec,
e1203ac0 49 &ogm_old_codec,
9146ca37
MR
50 NULL
51};
52
9146ca37
MR
53//FIXME We could avoid some structure duplication
54static int
55ogg_save (AVFormatContext * s)
56{
57 ogg_t *ogg = s->priv_data;
58 ogg_state_t *ost =
ad3aa874 59 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
9146ca37 60 int i;
899681cd 61 ost->pos = url_ftell (s->pb);
9146ca37
MR
62 ost->curidx = ogg->curidx;
63 ost->next = ogg->state;
20be72c8 64 ost->nstreams = ogg->nstreams;
9146ca37
MR
65 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
66
67 for (i = 0; i < ogg->nstreams; i++){
68 ogg_stream_t *os = ogg->streams + i;
69 os->buf = av_malloc (os->bufsize);
70 memset (os->buf, 0, os->bufsize);
71 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
72 }
73
74 ogg->state = ost;
75
76 return 0;
77}
78
79static int
80ogg_restore (AVFormatContext * s, int discard)
81{
82 ogg_t *ogg = s->priv_data;
899681cd 83 ByteIOContext *bc = s->pb;
9146ca37
MR
84 ogg_state_t *ost = ogg->state;
85 int i;
86
87 if (!ost)
88 return 0;
89
90 ogg->state = ost->next;
91
92 if (!discard){
93 for (i = 0; i < ogg->nstreams; i++)
94 av_free (ogg->streams[i].buf);
95
96 url_fseek (bc, ost->pos, SEEK_SET);
97 ogg->curidx = ost->curidx;
20be72c8
MR
98 ogg->nstreams = ost->nstreams;
99 memcpy(ogg->streams, ost->streams,
100 ost->nstreams * sizeof(*ogg->streams));
9146ca37
MR
101 }
102
103 av_free (ost);
104
105 return 0;
106}
107
108static int
109ogg_reset (ogg_t * ogg)
110{
111 int i;
112
113 for (i = 0; i < ogg->nstreams; i++){
114 ogg_stream_t *os = ogg->streams + i;
115 os->bufpos = 0;
116 os->pstart = 0;
117 os->psize = 0;
118 os->granule = -1;
119 os->lastgp = -1;
120 os->nsegs = 0;
121 os->segp = 0;
122 }
123
124 ogg->curidx = -1;
125
126 return 0;
127}
128
129static ogg_codec_t *
2d2f443d 130ogg_find_codec (uint8_t * buf, int size)
9146ca37
MR
131{
132 int i;
133
134 for (i = 0; ogg_codecs[i]; i++)
135 if (size >= ogg_codecs[i]->magicsize &&
136 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
137 return ogg_codecs[i];
138
139 return NULL;
140}
141
142static int
143ogg_find_stream (ogg_t * ogg, int serial)
144{
145 int i;
146
147 for (i = 0; i < ogg->nstreams; i++)
148 if (ogg->streams[i].serial == serial)
149 return i;
150
151 return -1;
152}
153
154static int
155ogg_new_stream (AVFormatContext * s, uint32_t serial)
156{
157
158 ogg_t *ogg = s->priv_data;
159 int idx = ogg->nstreams++;
160 AVStream *st;
161 ogg_stream_t *os;
162
163 ogg->streams = av_realloc (ogg->streams,
164 ogg->nstreams * sizeof (*ogg->streams));
165 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
166 os = ogg->streams + idx;
167 os->serial = serial;
168 os->bufsize = DECODER_BUFFER_SIZE;
40c5e1fa 169 os->buf = av_malloc(os->bufsize);
9146ca37
MR
170 os->header = -1;
171
172 st = av_new_stream (s, idx);
173 if (!st)
769e10f0 174 return AVERROR(ENOMEM);
9146ca37
MR
175
176 av_set_pts_info(st, 64, 1, 1000000);
9146ca37
MR
177
178 return idx;
179}
180
181static int
12a195e3
MR
182ogg_new_buf(ogg_t *ogg, int idx)
183{
184 ogg_stream_t *os = ogg->streams + idx;
ea02862a 185 uint8_t *nb = av_malloc(os->bufsize);
12a195e3
MR
186 int size = os->bufpos - os->pstart;
187 if(os->buf){
188 memcpy(nb, os->buf + os->pstart, size);
189 av_free(os->buf);
190 }
191 os->buf = nb;
192 os->bufpos = size;
193 os->pstart = 0;
194
195 return 0;
196}
197
198static int
9146ca37
MR
199ogg_read_page (AVFormatContext * s, int *str)
200{
899681cd 201 ByteIOContext *bc = s->pb;
9146ca37
MR
202 ogg_t *ogg = s->priv_data;
203 ogg_stream_t *os;
204 int i = 0;
205 int flags, nsegs;
206 uint64_t gp;
207 uint32_t serial;
208 uint32_t seq;
209 uint32_t crc;
210 int size, idx;
191e8ca7 211 uint8_t sync[4];
9146ca37
MR
212 int sp = 0;
213
214 if (get_buffer (bc, sync, 4) < 4)
215 return -1;
216
217 do{
218 int c;
219
220 if (sync[sp & 3] == 'O' &&
221 sync[(sp + 1) & 3] == 'g' &&
222 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
223 break;
224
225 c = url_fgetc (bc);
226 if (c < 0)
227 return -1;
228 sync[sp++ & 3] = c;
229 }while (i++ < MAX_PAGE_SIZE);
230
231 if (i >= MAX_PAGE_SIZE){
232 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
233 return -1;
234 }
235
236 if (url_fgetc (bc) != 0) /* version */
237 return -1;
238
239 flags = url_fgetc (bc);
240 gp = get_le64 (bc);
241 serial = get_le32 (bc);
242 seq = get_le32 (bc);
243 crc = get_le32 (bc);
244 nsegs = url_fgetc (bc);
245
246 idx = ogg_find_stream (ogg, serial);
247 if (idx < 0){
248 idx = ogg_new_stream (s, serial);
249 if (idx < 0)
250 return -1;
251 }
252
253 os = ogg->streams + idx;
254
40c5e1fa 255 if(os->psize > 0)
12a195e3
MR
256 ogg_new_buf(ogg, idx);
257
9146ca37
MR
258 if (get_buffer (bc, os->segments, nsegs) < nsegs)
259 return -1;
260
261 os->nsegs = nsegs;
262 os->segp = 0;
263
264 size = 0;
265 for (i = 0; i < nsegs; i++)
266 size += os->segments[i];
267
268 if (flags & OGG_FLAG_CONT){
269 if (!os->psize){
270 while (os->segp < os->nsegs){
271 int seg = os->segments[os->segp++];
272 os->pstart += seg;
273 if (seg < 255)
274 break;
275 }
276 }
277 }else{
278 os->psize = 0;
279 }
280
281 if (os->bufsize - os->bufpos < size){
2d2f443d 282 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
283 memcpy (nb, os->buf, os->bufpos);
284 av_free (os->buf);
285 os->buf = nb;
286 }
287
288 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
289 return -1;
290
291 os->lastgp = os->granule;
292 os->bufpos += size;
293 os->granule = gp;
294 os->flags = flags;
295
296 if (str)
297 *str = idx;
298
299 return 0;
300}
301
302static int
12a195e3 303ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
9146ca37
MR
304{
305 ogg_t *ogg = s->priv_data;
306 int idx;
307 ogg_stream_t *os;
308 int complete = 0;
309 int segp = 0, psize = 0;
310
311#if 0
312 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
313#endif
314
315 do{
316 idx = ogg->curidx;
317
318 while (idx < 0){
319 if (ogg_read_page (s, &idx) < 0)
320 return -1;
321 }
322
323 os = ogg->streams + idx;
324
325#if 0
326 av_log (s, AV_LOG_DEBUG,
327 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
328 idx, os->pstart, os->psize, os->segp, os->nsegs);
329#endif
330
331 if (!os->codec){
332 if (os->header < 0){
333 os->codec = ogg_find_codec (os->buf, os->bufpos);
334 if (!os->codec){
335 os->header = 0;
336 return 0;
337 }
338 }else{
339 return 0;
340 }
341 }
342
343 segp = os->segp;
344 psize = os->psize;
345
346 while (os->segp < os->nsegs){
347 int ss = os->segments[os->segp++];
348 os->psize += ss;
349 if (ss < 255){
350 complete = 1;
351 break;
352 }
353 }
354
355 if (!complete && os->segp == os->nsegs){
9146ca37
MR
356 ogg->curidx = -1;
357 }
358 }while (!complete);
359
360#if 0
361 av_log (s, AV_LOG_DEBUG,
362 "ogg_packet: idx %i, frame size %i, start %i\n",
363 idx, os->psize, os->pstart);
364#endif
365
366 ogg->curidx = idx;
367
368 if (os->header < 0){
369 int hdr = os->codec->header (s, idx);
370 if (!hdr){
371 os->header = os->seq;
372 os->segp = segp;
373 os->psize = psize;
374 ogg->headers = 1;
375 }else{
376 os->pstart += os->psize;
377 os->psize = 0;
378 }
379 }
380
381 if (os->header > -1 && os->seq > os->header){
e1a794b2 382 os->pflags = 0;
9146ca37
MR
383 if (os->codec && os->codec->packet)
384 os->codec->packet (s, idx);
385 if (str)
386 *str = idx;
12a195e3
MR
387 if (dstart)
388 *dstart = os->pstart;
389 if (dsize)
390 *dsize = os->psize;
391 os->pstart += os->psize;
392 os->psize = 0;
9146ca37
MR
393 }
394
395 os->seq++;
396 if (os->segp == os->nsegs)
397 ogg->curidx = -1;
398
399 return 0;
400}
401
402static int
403ogg_get_headers (AVFormatContext * s)
404{
405 ogg_t *ogg = s->priv_data;
406
407 do{
12a195e3 408 if (ogg_packet (s, NULL, NULL, NULL) < 0)
9146ca37
MR
409 return -1;
410 }while (!ogg->headers);
411
412#if 0
413 av_log (s, AV_LOG_DEBUG, "found headers\n");
414#endif
415
416 return 0;
417}
418
419static uint64_t
420ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
421{
1ed923ea
MR
422 ogg_t *ogg = s->priv_data;
423 ogg_stream_t *os = ogg->streams + i;
9146ca37
MR
424 uint64_t pts = AV_NOPTS_VALUE;
425
1ed923ea 426 if(os->codec->gptopts){
bb270c08 427 pts = os->codec->gptopts(s, i, gp);
3644cb8f 428 } else {
1ed923ea 429 pts = gp;
9146ca37
MR
430 }
431
432 return pts;
433}
434
435
436static int
437ogg_get_length (AVFormatContext * s)
438{
439 ogg_t *ogg = s->priv_data;
9146ca37 440 int idx = -1, i;
56466d7b 441 offset_t size, end;
69599eea 442
ceeacce6 443 if(url_is_streamed(s->pb))
69599eea 444 return 0;
9146ca37
MR
445
446// already set
447 if (s->duration != AV_NOPTS_VALUE)
448 return 0;
449
899681cd 450 size = url_fsize(s->pb);
56466d7b
MR
451 if(size < 0)
452 return 0;
453 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
454
9146ca37 455 ogg_save (s);
899681cd 456 url_fseek (s->pb, end, SEEK_SET);
9146ca37
MR
457
458 while (!ogg_read_page (s, &i)){
e22f2aaf
MR
459 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
460 ogg->streams[i].codec)
9146ca37
MR
461 idx = i;
462 }
463
464 if (idx != -1){
465 s->streams[idx]->duration =
466 ogg_gptopts (s, idx, ogg->streams[idx].granule);
467 }
468
56466d7b 469 ogg->size = size;
9146ca37 470 ogg_restore (s, 0);
22ffac70 471 ogg_save (s);
595da759 472 while (!ogg_read_page (s, &i)) {
22ffac70
RD
473 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
474 break;
475 }
476 if (i == idx) {
477 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
478 s->streams[idx]->duration -= s->streams[idx]->start_time;
479 }
480 ogg_restore (s, 0);
9146ca37
MR
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;
12a195e3 510 int pstart, psize;
9146ca37 511
115329f1 512 //Get an ogg packet
9146ca37 513 do{
12a195e3 514 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
6f3e0b21 515 return AVERROR(EIO);
9146ca37
MR
516 }while (idx < 0 || !s->streams[idx]);
517
518 ogg = s->priv_data;
519 os = ogg->streams + idx;
520
521 //Alloc a pkt
12a195e3 522 if (av_new_packet (pkt, psize) < 0)
6f3e0b21 523 return AVERROR(EIO);
9146ca37 524 pkt->stream_index = idx;
12a195e3 525 memcpy (pkt->data, os->buf + pstart, psize);
9146ca37
MR
526 if (os->lastgp != -1LL){
527 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
528 os->lastgp = -1;
529 }
12a195e3 530
e1a794b2
MR
531 pkt->flags = os->pflags;
532
12a195e3 533 return psize;
9146ca37
MR
534}
535
536
537static int
538ogg_read_close (AVFormatContext * s)
539{
540 ogg_t *ogg = s->priv_data;
541 int i;
542
543 for (i = 0; i < ogg->nstreams; i++){
544 av_free (ogg->streams[i].buf);
1ed923ea 545 av_free (ogg->streams[i].private);
9146ca37
MR
546 }
547 av_free (ogg->streams);
548 return 0;
549}
550
551
9146ca37
MR
552static int64_t
553ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
554 int64_t pos_limit)
555{
556 ogg_t *ogg = s->priv_data;
899681cd 557 ByteIOContext *bc = s->pb;
a1f29b95
RD
558 int64_t pts = AV_NOPTS_VALUE;
559 int i;
560 url_fseek(bc, *pos_arg, SEEK_SET);
561 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
562 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
563 ogg->streams[i].codec && i == stream_index) {
564 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
565 // FIXME: this is the position of the packet after the one with above
566 // pts.
567 *pos_arg = url_ftell(bc);
568 break;
569 }
570 }
571 ogg_reset(ogg);
572 return pts;
9146ca37 573}
9146ca37 574
2e70e4aa
MR
575static int ogg_probe(AVProbeData *p)
576{
2e70e4aa
MR
577 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
578 p->buf[2] == 'g' && p->buf[3] == 'S' &&
579 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
580 return AVPROBE_SCORE_MAX;
581 else
582 return 0;
583}
584
ff70e601 585AVInputFormat ogg_demuxer = {
9146ca37
MR
586 "ogg",
587 "Ogg",
588 sizeof (ogg_t),
2e70e4aa 589 ogg_probe,
9146ca37
MR
590 ogg_read_header,
591 ogg_read_packet,
592 ogg_read_close,
ce3132be 593 NULL,
a1f29b95 594 ogg_read_timestamp,
9146ca37
MR
595 .extensions = "ogg",
596};