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