Add support for speex in ogg
[libav.git] / libavformat / oggdec.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 "oggdec.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 &speex_codec,
42 &vorbis_codec,
43 &theora_codec,
44 &flac_codec,
45 &old_flac_codec,
46 &ogm_video_codec,
47 &ogm_audio_codec,
48 &ogm_text_codec,
49 &ogm_old_codec,
50 NULL
51 };
52
53 //FIXME We could avoid some structure duplication
54 static int
55 ogg_save (AVFormatContext * s)
56 {
57 ogg_t *ogg = s->priv_data;
58 ogg_state_t *ost =
59 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
60 int i;
61 ost->pos = url_ftell (s->pb);
62 ost->curidx = ogg->curidx;
63 ost->next = ogg->state;
64 ost->nstreams = ogg->nstreams;
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
79 static int
80 ogg_restore (AVFormatContext * s, int discard)
81 {
82 ogg_t *ogg = s->priv_data;
83 ByteIOContext *bc = s->pb;
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;
98 ogg->nstreams = ost->nstreams;
99 memcpy(ogg->streams, ost->streams,
100 ost->nstreams * sizeof(*ogg->streams));
101 }
102
103 av_free (ost);
104
105 return 0;
106 }
107
108 static int
109 ogg_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
129 static ogg_codec_t *
130 ogg_find_codec (uint8_t * buf, int size)
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
142 static int
143 ogg_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
154 static int
155 ogg_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;
169 os->buf = av_malloc(os->bufsize);
170 os->header = -1;
171
172 st = av_new_stream (s, idx);
173 if (!st)
174 return AVERROR(ENOMEM);
175
176 av_set_pts_info(st, 64, 1, 1000000);
177
178 return idx;
179 }
180
181 static int
182 ogg_new_buf(ogg_t *ogg, int idx)
183 {
184 ogg_stream_t *os = ogg->streams + idx;
185 uint8_t *nb = av_malloc(os->bufsize);
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
198 static int
199 ogg_read_page (AVFormatContext * s, int *str)
200 {
201 ByteIOContext *bc = s->pb;
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;
211 uint8_t sync[4];
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
255 if(os->psize > 0)
256 ogg_new_buf(ogg, idx);
257
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){
282 uint8_t *nb = av_malloc (os->bufsize *= 2);
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
302 static int
303 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
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){
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){
382 os->pflags = 0;
383 if (os->codec && os->codec->packet)
384 os->codec->packet (s, idx);
385 if (str)
386 *str = idx;
387 if (dstart)
388 *dstart = os->pstart;
389 if (dsize)
390 *dsize = os->psize;
391 os->pstart += os->psize;
392 os->psize = 0;
393 }
394
395 os->seq++;
396 if (os->segp == os->nsegs)
397 ogg->curidx = -1;
398
399 return 0;
400 }
401
402 static int
403 ogg_get_headers (AVFormatContext * s)
404 {
405 ogg_t *ogg = s->priv_data;
406
407 do{
408 if (ogg_packet (s, NULL, NULL, NULL) < 0)
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
419 static uint64_t
420 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
421 {
422 ogg_t *ogg = s->priv_data;
423 ogg_stream_t *os = ogg->streams + i;
424 uint64_t pts = AV_NOPTS_VALUE;
425
426 if(os->codec->gptopts){
427 pts = os->codec->gptopts(s, i, gp);
428 } else {
429 pts = gp;
430 }
431
432 return pts;
433 }
434
435
436 static int
437 ogg_get_length (AVFormatContext * s)
438 {
439 ogg_t *ogg = s->priv_data;
440 int idx = -1, i;
441 offset_t size, end;
442
443 if(url_is_streamed(s->pb))
444 return 0;
445
446 // already set
447 if (s->duration != AV_NOPTS_VALUE)
448 return 0;
449
450 size = url_fsize(s->pb);
451 if(size < 0)
452 return 0;
453 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
454
455 ogg_save (s);
456 url_fseek (s->pb, end, SEEK_SET);
457
458 while (!ogg_read_page (s, &i)){
459 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
460 ogg->streams[i].codec)
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
469 ogg->size = size;
470 ogg_restore (s, 0);
471 ogg_save (s);
472 while (!ogg_read_page (s, &i)) {
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);
481
482 return 0;
483 }
484
485
486 static int
487 ogg_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
504 static int
505 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
506 {
507 ogg_t *ogg;
508 ogg_stream_t *os;
509 int idx = -1;
510 int pstart, psize;
511
512 //Get an ogg packet
513 do{
514 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
515 return AVERROR(EIO);
516 }while (idx < 0 || !s->streams[idx]);
517
518 ogg = s->priv_data;
519 os = ogg->streams + idx;
520
521 //Alloc a pkt
522 if (av_new_packet (pkt, psize) < 0)
523 return AVERROR(EIO);
524 pkt->stream_index = idx;
525 memcpy (pkt->data, os->buf + pstart, psize);
526 if (os->lastgp != -1LL){
527 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
528 os->lastgp = -1;
529 }
530
531 pkt->flags = os->pflags;
532
533 return psize;
534 }
535
536
537 static int
538 ogg_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);
545 av_free (ogg->streams[i].private);
546 }
547 av_free (ogg->streams);
548 return 0;
549 }
550
551
552 static int64_t
553 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
554 int64_t pos_limit)
555 {
556 ogg_t *ogg = s->priv_data;
557 ByteIOContext *bc = s->pb;
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;
573 }
574
575 static int ogg_probe(AVProbeData *p)
576 {
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
585 AVInputFormat ogg_demuxer = {
586 "ogg",
587 "Ogg",
588 sizeof (ogg_t),
589 ogg_probe,
590 ogg_read_header,
591 ogg_read_packet,
592 ogg_read_close,
593 NULL,
594 ogg_read_timestamp,
595 .extensions = "ogg",
596 };