Make xvmc.h an installed header, applications like MPlayer need it.
[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
77be08ee 40static const struct ogg_codec * const ogg_codecs[] = {
547ea47d
RD
41 &ff_speex_codec,
42 &ff_vorbis_codec,
43 &ff_theora_codec,
44 &ff_flac_codec,
45 &ff_old_flac_codec,
46 &ff_ogm_video_codec,
47 &ff_ogm_audio_codec,
48 &ff_ogm_text_codec,
49 &ff_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{
77be08ee
MR
57 struct ogg *ogg = s->priv_data;
58 struct ogg_state *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++){
77be08ee 68 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
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{
77be08ee 82 struct ogg *ogg = s->priv_data;
899681cd 83 ByteIOContext *bc = s->pb;
77be08ee 84 struct ogg_state *ost = ogg->state;
9146ca37
MR
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
77be08ee 109ogg_reset (struct ogg * ogg)
9146ca37
MR
110{
111 int i;
112
113 for (i = 0; i < ogg->nstreams; i++){
77be08ee 114 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
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
77be08ee 129static const struct ogg_codec *
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
77be08ee 143ogg_find_stream (struct ogg * ogg, int serial)
9146ca37
MR
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
77be08ee 158 struct ogg *ogg = s->priv_data;
9146ca37
MR
159 int idx = ogg->nstreams++;
160 AVStream *st;
77be08ee 161 struct ogg_stream *os;
9146ca37
MR
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
77be08ee 182ogg_new_buf(struct ogg *ogg, int idx)
12a195e3 183{
77be08ee 184 struct ogg_stream *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;
77be08ee
MR
202 struct ogg *ogg = s->priv_data;
203 struct ogg_stream *os;
9146ca37
MR
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 304{
77be08ee 305 struct ogg *ogg = s->priv_data;
9146ca37 306 int idx;
77be08ee 307 struct ogg_stream *os;
9146ca37
MR
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{
77be08ee 405 struct ogg *ogg = s->priv_data;
9146ca37
MR
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{
77be08ee
MR
422 struct ogg *ogg = s->priv_data;
423 struct ogg_stream *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{
77be08ee 439 struct ogg *ogg = s->priv_data;
9146ca37 440 int idx = -1, i;
bc5c918e 441 int64_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
MR
470 ogg_restore (s, 0);
471
472 return 0;
473}
474
475
476static int
477ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
478{
77be08ee 479 struct ogg *ogg = s->priv_data;
9146ca37
MR
480 ogg->curidx = -1;
481 //linear headers seek from start
482 if (ogg_get_headers (s) < 0){
483 return -1;
484 }
485
486 //linear granulepos seek from end
487 ogg_get_length (s);
488
489 //fill the extradata in the per codec callbacks
490 return 0;
491}
492
493
494static int
495ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
496{
77be08ee
MR
497 struct ogg *ogg;
498 struct ogg_stream *os;
9146ca37 499 int idx = -1;
12a195e3 500 int pstart, psize;
9146ca37 501
115329f1 502 //Get an ogg packet
9146ca37 503 do{
12a195e3 504 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
6f3e0b21 505 return AVERROR(EIO);
9146ca37
MR
506 }while (idx < 0 || !s->streams[idx]);
507
508 ogg = s->priv_data;
509 os = ogg->streams + idx;
510
511 //Alloc a pkt
12a195e3 512 if (av_new_packet (pkt, psize) < 0)
6f3e0b21 513 return AVERROR(EIO);
9146ca37 514 pkt->stream_index = idx;
12a195e3 515 memcpy (pkt->data, os->buf + pstart, psize);
9146ca37
MR
516 if (os->lastgp != -1LL){
517 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
518 os->lastgp = -1;
519 }
12a195e3 520
e1a794b2
MR
521 pkt->flags = os->pflags;
522
12a195e3 523 return psize;
9146ca37
MR
524}
525
526
527static int
528ogg_read_close (AVFormatContext * s)
529{
77be08ee 530 struct ogg *ogg = s->priv_data;
9146ca37
MR
531 int i;
532
533 for (i = 0; i < ogg->nstreams; i++){
534 av_free (ogg->streams[i].buf);
1ed923ea 535 av_free (ogg->streams[i].private);
9146ca37
MR
536 }
537 av_free (ogg->streams);
538 return 0;
539}
540
541
9146ca37
MR
542static int64_t
543ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
544 int64_t pos_limit)
545{
77be08ee 546 struct ogg *ogg = s->priv_data;
899681cd 547 ByteIOContext *bc = s->pb;
a1f29b95
RD
548 int64_t pts = AV_NOPTS_VALUE;
549 int i;
550 url_fseek(bc, *pos_arg, SEEK_SET);
551 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
552 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
553 ogg->streams[i].codec && i == stream_index) {
554 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
555 // FIXME: this is the position of the packet after the one with above
556 // pts.
557 *pos_arg = url_ftell(bc);
558 break;
559 }
560 }
561 ogg_reset(ogg);
562 return pts;
9146ca37 563}
9146ca37 564
2e70e4aa
MR
565static int ogg_probe(AVProbeData *p)
566{
2e70e4aa
MR
567 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
568 p->buf[2] == 'g' && p->buf[3] == 'S' &&
569 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
570 return AVPROBE_SCORE_MAX;
571 else
572 return 0;
573}
574
ff70e601 575AVInputFormat ogg_demuxer = {
9146ca37 576 "ogg",
bde15e74 577 NULL_IF_CONFIG_SMALL("Ogg"),
77be08ee 578 sizeof (struct ogg),
2e70e4aa 579 ogg_probe,
9146ca37
MR
580 ogg_read_header,
581 ogg_read_packet,
582 ogg_read_close,
ce3132be 583 NULL,
a1f29b95 584 ogg_read_timestamp,
9146ca37
MR
585 .extensions = "ogg",
586};