Typo in softfloat_reciprocal comment.
[FFMpeg-mirror/lagarith.git] / libavformat / oggdec.c
blob129268b390245bc2780e8f7541bae623181a7ec8
1 /*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
6 */
8 /**
9 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
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:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
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 **/
33 #include <stdio.h>
34 #include "oggdec.h"
35 #include "avformat.h"
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 static const struct ogg_codec * const ogg_codecs[] = {
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,
50 NULL
53 //FIXME We could avoid some structure duplication
54 static int
55 ogg_save (AVFormatContext * s)
57 struct ogg *ogg = s->priv_data;
58 struct ogg_state *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));
67 for (i = 0; i < ogg->nstreams; i++){
68 struct ogg_stream *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);
74 ogg->state = ost;
76 return 0;
79 static int
80 ogg_restore (AVFormatContext * s, int discard)
82 struct ogg *ogg = s->priv_data;
83 ByteIOContext *bc = s->pb;
84 struct ogg_state *ost = ogg->state;
85 int i;
87 if (!ost)
88 return 0;
90 ogg->state = ost->next;
92 if (!discard){
93 for (i = 0; i < ogg->nstreams; i++)
94 av_free (ogg->streams[i].buf);
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));
103 av_free (ost);
105 return 0;
108 static int
109 ogg_reset (struct ogg * ogg)
111 int i;
113 for (i = 0; i < ogg->nstreams; i++){
114 struct ogg_stream *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;
124 ogg->curidx = -1;
126 return 0;
129 static const struct ogg_codec *
130 ogg_find_codec (uint8_t * buf, int size)
132 int i;
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];
139 return NULL;
142 static int
143 ogg_find_stream (struct ogg * ogg, int serial)
145 int i;
147 for (i = 0; i < ogg->nstreams; i++)
148 if (ogg->streams[i].serial == serial)
149 return i;
151 return -1;
154 static int
155 ogg_new_stream (AVFormatContext * s, uint32_t serial)
158 struct ogg *ogg = s->priv_data;
159 int idx = ogg->nstreams++;
160 AVStream *st;
161 struct ogg_stream *os;
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;
172 st = av_new_stream (s, idx);
173 if (!st)
174 return AVERROR(ENOMEM);
176 av_set_pts_info(st, 64, 1, 1000000);
178 return idx;
181 static int
182 ogg_new_buf(struct ogg *ogg, int idx)
184 struct ogg_stream *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);
191 os->buf = nb;
192 os->bufpos = size;
193 os->pstart = 0;
195 return 0;
198 static int
199 ogg_read_page (AVFormatContext * s, int *str)
201 ByteIOContext *bc = s->pb;
202 struct ogg *ogg = s->priv_data;
203 struct ogg_stream *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;
214 if (get_buffer (bc, sync, 4) < 4)
215 return -1;
218 int c;
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;
225 c = url_fgetc (bc);
226 if (c < 0)
227 return -1;
228 sync[sp++ & 3] = c;
229 }while (i++ < MAX_PAGE_SIZE);
231 if (i >= MAX_PAGE_SIZE){
232 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
233 return -1;
236 if (url_fgetc (bc) != 0) /* version */
237 return -1;
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);
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;
253 os = ogg->streams + idx;
255 if(os->psize > 0)
256 ogg_new_buf(ogg, idx);
258 if (get_buffer (bc, os->segments, nsegs) < nsegs)
259 return -1;
261 os->nsegs = nsegs;
262 os->segp = 0;
264 size = 0;
265 for (i = 0; i < nsegs; i++)
266 size += os->segments[i];
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;
277 }else{
278 os->psize = 0;
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;
288 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
289 return -1;
291 os->lastgp = os->granule;
292 os->bufpos += size;
293 os->granule = gp;
294 os->flags = flags;
296 if (str)
297 *str = idx;
299 return 0;
302 static int
303 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
305 struct ogg *ogg = s->priv_data;
306 int idx;
307 struct ogg_stream *os;
308 int complete = 0;
309 int segp = 0, psize = 0;
311 #if 0
312 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
313 #endif
316 idx = ogg->curidx;
318 while (idx < 0){
319 if (ogg_read_page (s, &idx) < 0)
320 return -1;
323 os = ogg->streams + idx;
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
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;
338 }else{
339 return 0;
343 segp = os->segp;
344 psize = os->psize;
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;
355 if (!complete && os->segp == os->nsegs){
356 ogg->curidx = -1;
358 }while (!complete);
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
366 ogg->curidx = idx;
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;
381 if (os->header > -1 && os->seq > os->header){
382 os->pflags = 0;
383 os->pduration = 0;
384 if (os->codec && os->codec->packet)
385 os->codec->packet (s, idx);
386 if (str)
387 *str = idx;
388 if (dstart)
389 *dstart = os->pstart;
390 if (dsize)
391 *dsize = os->psize;
392 os->pstart += os->psize;
393 os->psize = 0;
396 os->seq++;
397 if (os->segp == os->nsegs)
398 ogg->curidx = -1;
400 return 0;
403 static int
404 ogg_get_headers (AVFormatContext * s)
406 struct ogg *ogg = s->priv_data;
409 if (ogg_packet (s, NULL, NULL, NULL) < 0)
410 return -1;
411 }while (!ogg->headers);
413 #if 0
414 av_log (s, AV_LOG_DEBUG, "found headers\n");
415 #endif
417 return 0;
420 static uint64_t
421 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
423 struct ogg *ogg = s->priv_data;
424 struct ogg_stream *os = ogg->streams + i;
425 uint64_t pts = AV_NOPTS_VALUE;
427 if(os->codec->gptopts){
428 pts = os->codec->gptopts(s, i, gp);
429 } else {
430 pts = gp;
433 return pts;
437 static int
438 ogg_get_length (AVFormatContext * s)
440 struct ogg *ogg = s->priv_data;
441 int idx = -1, i;
442 int64_t size, end;
444 if(url_is_streamed(s->pb))
445 return 0;
447 // already set
448 if (s->duration != AV_NOPTS_VALUE)
449 return 0;
451 size = url_fsize(s->pb);
452 if(size < 0)
453 return 0;
454 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
456 ogg_save (s);
457 url_fseek (s->pb, end, SEEK_SET);
459 while (!ogg_read_page (s, &i)){
460 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
461 ogg->streams[i].codec)
462 idx = i;
465 if (idx != -1){
466 s->streams[idx]->duration =
467 ogg_gptopts (s, idx, ogg->streams[idx].granule);
470 ogg->size = size;
471 ogg_restore (s, 0);
473 return 0;
477 static int
478 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
480 struct ogg *ogg = s->priv_data;
481 int i;
482 ogg->curidx = -1;
483 //linear headers seek from start
484 if (ogg_get_headers (s) < 0){
485 return -1;
488 for (i = 0; i < ogg->nstreams; i++)
489 if (ogg->streams[i].header < 0)
490 ogg->streams[i].codec = NULL;
492 //linear granulepos seek from end
493 ogg_get_length (s);
495 //fill the extradata in the per codec callbacks
496 return 0;
500 static int
501 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
503 struct ogg *ogg;
504 struct ogg_stream *os;
505 int idx = -1;
506 int pstart, psize;
508 //Get an ogg packet
510 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
511 return AVERROR(EIO);
512 }while (idx < 0 || !s->streams[idx]);
514 ogg = s->priv_data;
515 os = ogg->streams + idx;
517 //Alloc a pkt
518 if (av_new_packet (pkt, psize) < 0)
519 return AVERROR(EIO);
520 pkt->stream_index = idx;
521 memcpy (pkt->data, os->buf + pstart, psize);
522 if (os->lastgp != -1LL){
523 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
524 os->lastgp = -1;
527 pkt->flags = os->pflags;
528 pkt->duration = os->pduration;
530 return psize;
534 static int
535 ogg_read_close (AVFormatContext * s)
537 struct ogg *ogg = s->priv_data;
538 int i;
540 for (i = 0; i < ogg->nstreams; i++){
541 av_free (ogg->streams[i].buf);
542 av_free (ogg->streams[i].private);
544 av_free (ogg->streams);
545 return 0;
549 static int64_t
550 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
551 int64_t pos_limit)
553 struct ogg *ogg = s->priv_data;
554 ByteIOContext *bc = s->pb;
555 int64_t pts = AV_NOPTS_VALUE;
556 int i;
557 url_fseek(bc, *pos_arg, SEEK_SET);
558 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
559 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
560 ogg->streams[i].codec && i == stream_index) {
561 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
562 // FIXME: this is the position of the packet after the one with above
563 // pts.
564 *pos_arg = url_ftell(bc);
565 break;
568 ogg_reset(ogg);
569 return pts;
572 static int ogg_probe(AVProbeData *p)
574 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
575 p->buf[2] == 'g' && p->buf[3] == 'S' &&
576 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
577 return AVPROBE_SCORE_MAX;
578 else
579 return 0;
582 AVInputFormat ogg_demuxer = {
583 "ogg",
584 NULL_IF_CONFIG_SMALL("Ogg"),
585 sizeof (struct ogg),
586 ogg_probe,
587 ogg_read_header,
588 ogg_read_packet,
589 ogg_read_close,
590 NULL,
591 ogg_read_timestamp,
592 .extensions = "ogg",
593 .metadata_conv = ff_vorbiscomment_metadata_conv,