New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / codecs / libtremor / vorbisfile.c
blobca18ecb3f785c334a0cb2b1fe47e56c8df24c2c7
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
4 * *
5 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
6 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
11 * *
12 ********************************************************************
14 function: stdio-based convenience library for opening/seeking/decoding
15 last mod: $Id$
17 ********************************************************************/
19 #include "config-tremor.h"
20 #include <stdio.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <math.h>
24 #include "system.h"
26 #include "ivorbiscodec.h"
27 #include "ivorbisfile.h"
29 #include "os.h"
30 #include "misc.h"
32 /* A 'chained bitstream' is a Vorbis bitstream that contains more than
33 one logical bitstream arranged end to end (the only form of Ogg
34 multiplexing allowed in a Vorbis bitstream; grouping [parallel
35 multiplexing] is not allowed in Vorbis) */
37 /* A Vorbis file can be played beginning to end (streamed) without
38 worrying ahead of time about chaining (see decoder_example.c). If
39 we have the whole file, however, and want random access
40 (seeking/scrubbing) or desire to know the total length/time of a
41 file, we need to account for the possibility of chaining. */
43 /* We can handle things a number of ways; we can determine the entire
44 bitstream structure right off the bat, or find pieces on demand.
45 This example determines and caches structure for the entire
46 bitstream, but builds a virtual decoder on the fly when moving
47 between links in the chain. */
49 /* There are also different ways to implement seeking. Enough
50 information exists in an Ogg bitstream to seek to
51 sample-granularity positions in the output. Or, one can seek by
52 picking some portion of the stream roughly in the desired area if
53 we only want coarse navigation through the stream. */
55 /*************************************************************************
56 * Many, many internal helpers. The intention is not to be confusing;
57 * rampant duplication and monolithic function implementation would be
58 * harder to understand anyway. The high level functions are last. Begin
59 * grokking near the end of the file */
62 /* read a little more data from the file/pipe into the ogg_sync framer */
63 static long _get_data(OggVorbis_File *vf){
64 if(vf->datasource){
65 char *buffer=(char *)ogg_sync_bufferin(vf->oy,CHUNKSIZE);
66 long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
67 if(bytes>0)ogg_sync_wrote(vf->oy,bytes);
68 return(bytes);
69 }else
70 return(0);
73 /* save a tiny smidge of verbosity to make the code more readable */
74 static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
75 if(vf->datasource){
76 (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
77 vf->offset=offset;
78 ogg_sync_reset(vf->oy);
79 }else{
80 /* shouldn't happen unless someone writes a broken callback */
81 return;
85 /* The read/seek functions track absolute position within the stream */
87 /* from the head of the stream, get the next page. boundary specifies
88 if the function is allowed to fetch more data from the stream (and
89 how much) or only use internally buffered data.
91 boundary: -1) unbounded search
92 0) read no additional data; use cached only
93 n) search for a new page beginning for n bytes
95 return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
96 n) found a page at absolute offset n
98 produces a refcounted page */
100 static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
101 ogg_int64_t boundary){
102 if(boundary>0)boundary+=vf->offset;
103 while(1){
104 long more;
106 if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
107 more=ogg_sync_pageseek(vf->oy,og);
109 if(more<0){
110 /* skipped n bytes */
111 vf->offset-=more;
112 }else{
113 if(more==0){
114 /* send more paramedics */
115 if(!boundary)return(OV_FALSE);
117 long ret=_get_data(vf);
118 if(ret==0)return(OV_EOF);
119 if(ret<0)return(OV_EREAD);
121 }else{
122 /* got a page. Return the offset at the page beginning,
123 advance the internal offset past the page end */
124 ogg_int64_t ret=vf->offset;
125 vf->offset+=more;
126 return(ret);
133 /* find the latest page beginning before the current stream cursor
134 position. Much dirtier than the above as Ogg doesn't have any
135 backward search linkage. no 'readp' as it will certainly have to
136 read. */
137 /* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */
139 static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
140 ogg_int64_t begin=vf->offset;
141 ogg_int64_t end=begin;
142 ogg_int64_t ret;
143 ogg_int64_t offset=-1;
145 while(offset==-1){
146 begin-=CHUNKSIZE;
147 if(begin<0)
148 begin=0;
149 _seek_helper(vf,begin);
150 while(vf->offset<end){
151 ret=_get_next_page(vf,og,end-vf->offset);
152 if(ret==OV_EREAD)return(OV_EREAD);
153 if(ret<0){
154 break;
155 }else{
156 offset=ret;
161 /* we have the offset. Actually snork and hold the page now */
162 _seek_helper(vf,offset);
163 ret=_get_next_page(vf,og,CHUNKSIZE);
164 if(ret<0)
165 /* this shouldn't be possible */
166 return(OV_EFAULT);
168 return(offset);
171 /* finds each bitstream link one at a time using a bisection search
172 (has to begin by knowing the offset of the lb's initial page).
173 Recurses for each link so it can alloc the link storage after
174 finding them all, then unroll and fill the cache at the same time */
175 static int _bisect_forward_serialno(OggVorbis_File *vf,
176 ogg_int64_t begin,
177 ogg_int64_t searched,
178 ogg_int64_t end,
179 ogg_uint32_t currentno,
180 long m){
181 ogg_int64_t endsearched=end;
182 ogg_int64_t next=end;
183 ogg_page og={0,0,0,0};
184 ogg_int64_t ret;
186 /* the below guards against garbage seperating the last and
187 first pages of two links. */
188 while(searched<endsearched){
189 ogg_int64_t bisect;
191 if(endsearched-searched<CHUNKSIZE){
192 bisect=searched;
193 }else{
194 bisect=(searched+endsearched)/2;
197 _seek_helper(vf,bisect);
198 ret=_get_next_page(vf,&og,-1);
199 if(ret==OV_EREAD)return(OV_EREAD);
200 if(ret<0 || ogg_page_serialno(&og)!=currentno){
201 endsearched=bisect;
202 if(ret>=0)next=ret;
203 }else{
204 searched=ret+og.header_len+og.body_len;
206 ogg_page_release(&og);
209 _seek_helper(vf,next);
210 ret=_get_next_page(vf,&og,-1);
211 if(ret==OV_EREAD)return(OV_EREAD);
213 if(searched>=end || ret<0){
214 ogg_page_release(&og);
215 vf->links=m+1;
216 vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
217 vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
218 vf->offsets[m+1]=searched;
219 }else{
220 ret=_bisect_forward_serialno(vf,next,vf->offset,
221 end,ogg_page_serialno(&og),m+1);
222 ogg_page_release(&og);
223 if(ret==OV_EREAD)return(OV_EREAD);
226 vf->offsets[m]=begin;
227 vf->serialnos[m]=currentno;
228 return(0);
231 /* uses the local ogg_stream storage in vf; this is important for
232 non-streaming input sources */
233 /* consumes the page that's passed in (if any) */
235 static int _fetch_headers(OggVorbis_File *vf,
236 vorbis_info *vi,
237 vorbis_comment *vc,
238 ogg_uint32_t *serialno,
239 ogg_page *og_ptr){
240 ogg_page og={0,0,0,0};
241 ogg_packet op={0,0,0,0,0,0};
242 int i,ret;
244 if(!og_ptr){
245 ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
246 if(llret==OV_EREAD)return(OV_EREAD);
247 if(llret<0)return OV_ENOTVORBIS;
248 og_ptr=&og;
251 ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
252 if(serialno)*serialno=vf->os->serialno;
253 vf->ready_state=STREAMSET;
255 /* extract the initial header from the first page and verify that the
256 Ogg bitstream is in fact Vorbis data */
258 vorbis_info_init(vi);
259 vorbis_comment_init(vc);
261 i=0;
262 while(i<3){
263 ogg_stream_pagein(vf->os,og_ptr);
264 while(i<3){
265 int result=ogg_stream_packetout(vf->os,&op);
266 if(result==0)break;
267 if(result==-1){
268 ret=OV_EBADHEADER;
269 goto bail_header;
271 if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
272 goto bail_header;
274 i++;
276 if(i<3)
277 if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
278 ret=OV_EBADHEADER;
279 goto bail_header;
283 ogg_packet_release(&op);
284 ogg_page_release(&og);
285 return 0;
287 bail_header:
288 ogg_packet_release(&op);
289 ogg_page_release(&og);
290 vorbis_info_clear(vi);
291 vorbis_comment_clear(vc);
292 vf->ready_state=OPENED;
294 return ret;
297 /* last step of the OggVorbis_File initialization; get all the
298 vorbis_info structs and PCM positions. Only called by the seekable
299 initialization (local stream storage is hacked slightly; pay
300 attention to how that's done) */
302 /* this is void and does not propogate errors up because we want to be
303 able to open and use damaged bitstreams as well as we can. Just
304 watch out for missing information for links in the OggVorbis_File
305 struct */
306 static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){
307 ogg_page og={0,0,0,0};
308 int i;
309 ogg_int64_t ret;
311 vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
312 vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
313 vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
314 vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
316 for(i=0;i<vf->links;i++){
317 if(i==0){
318 /* we already grabbed the initial header earlier. Just set the offset */
319 vf->dataoffsets[i]=dataoffset;
320 _seek_helper(vf,dataoffset);
322 }else{
324 /* seek to the location of the initial header */
326 _seek_helper(vf,vf->offsets[i]);
327 if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
328 vf->dataoffsets[i]=-1;
329 }else{
330 vf->dataoffsets[i]=vf->offset;
334 /* fetch beginning PCM offset */
336 if(vf->dataoffsets[i]!=-1){
337 ogg_int64_t accumulated=0,pos;
338 long lastblock=-1;
339 int result;
341 ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);
343 while(1){
344 ogg_packet op={0,0,0,0,0,0};
346 ret=_get_next_page(vf,&og,-1);
347 if(ret<0)
348 /* this should not be possible unless the file is
349 truncated/mangled */
350 break;
352 if(ogg_page_serialno(&og)!=vf->serialnos[i])
353 break;
355 pos=ogg_page_granulepos(&og);
357 /* count blocksizes of all frames in the page */
358 ogg_stream_pagein(vf->os,&og);
359 while((result=ogg_stream_packetout(vf->os,&op))){
360 if(result>0){ /* ignore holes */
361 long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);
362 if(lastblock!=-1)
363 accumulated+=(lastblock+thisblock)>>2;
364 lastblock=thisblock;
367 ogg_packet_release(&op);
369 if(pos!=-1){
370 /* pcm offset of last packet on the first audio page */
371 accumulated= pos-accumulated;
372 break;
376 /* less than zero? This is a stream with samples trimmed off
377 the beginning, a normal occurrence; set the offset to zero */
378 if(accumulated<0)accumulated=0;
380 vf->pcmlengths[i*2]=accumulated;
383 /* get the PCM length of this link. To do this,
384 get the last page of the stream */
386 ogg_int64_t end=vf->offsets[i+1];
387 _seek_helper(vf,end);
389 while(1){
390 ret=_get_prev_page(vf,&og);
391 if(ret<0){
392 /* this should not be possible */
393 vorbis_info_clear(vf->vi+i);
394 vorbis_comment_clear(vf->vc+i);
395 break;
397 if(ogg_page_granulepos(&og)!=-1){
398 vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
399 break;
401 vf->offset=ret;
405 ogg_page_release(&og);
408 static void _make_decode_ready(OggVorbis_File *vf){
409 if(vf->ready_state!=STREAMSET)return;
410 if(vf->seekable){
411 vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);
412 }else{
413 vorbis_synthesis_init(&vf->vd,vf->vi);
415 vorbis_block_init(&vf->vd,&vf->vb);
416 vf->ready_state=INITSET;
417 vf->bittrack=0;
418 vf->samptrack=0;
419 return;
422 static int _open_seekable2(OggVorbis_File *vf){
423 ogg_uint32_t serialno=vf->current_serialno;
424 ogg_uint32_t tempserialno;
425 ogg_int64_t dataoffset=vf->offset, end;
426 ogg_page og={0,0,0,0};
428 /* we're partially open and have a first link header state in
429 storage in vf */
430 /* we can seek, so set out learning all about this file */
431 (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
432 vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
434 /* We get the offset for the last page of the physical bitstream.
435 Most OggVorbis files will contain a single logical bitstream */
436 end=_get_prev_page(vf,&og);
437 if(end<0)return(end);
439 /* more than one logical bitstream? */
440 tempserialno=ogg_page_serialno(&og);
441 ogg_page_release(&og);
443 if(tempserialno!=serialno){
445 /* Chained bitstream. Bisect-search each logical bitstream
446 section. Do so based on serial number only */
447 if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
449 }else{
451 /* Only one logical bitstream */
452 if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
456 /* the initial header memory is referenced by vf after; don't free it */
457 _prefetch_all_headers(vf,dataoffset);
458 return(ov_raw_seek(vf,0));
461 /* clear out the current logical bitstream decoder */
462 static void _decode_clear(OggVorbis_File *vf){
463 vorbis_dsp_clear(&vf->vd);
464 vorbis_block_clear(&vf->vb);
465 vf->ready_state=OPENED;
468 /* fetch and process a packet. Handles the case where we're at a
469 bitstream boundary and dumps the decoding machine. If the decoding
470 machine is unloaded, it loads it. It also keeps pcm_offset up to
471 date (seek and read both use this. seek uses a special hack with
472 readp).
474 return: <0) error, OV_HOLE (lost packet) or OV_EOF
475 0) need more data (only if readp==0)
476 1) got a packet
479 static int _fetch_and_process_packet(OggVorbis_File *vf,
480 int readp,
481 int spanp) ICODE_ATTR_TREMOR_NOT_MDCT;
482 static int _fetch_and_process_packet(OggVorbis_File *vf,
483 int readp,
484 int spanp){
485 ogg_page og={0,0,0,0};
486 ogg_packet op={0,0,0,0,0,0};
487 int ret=0;
489 /* handle one packet. Try to fetch it from current stream state */
490 /* extract packets from page */
491 while(1){
493 /* process a packet if we can. If the machine isn't loaded,
494 neither is a page */
495 if(vf->ready_state==INITSET){
496 while(1) {
497 int result=ogg_stream_packetout(vf->os,&op);
498 ogg_int64_t granulepos;
500 if(result<0){
501 ret=OV_HOLE; /* hole in the data. */
502 goto cleanup;
504 if(result>0){
505 /* got a packet. process it */
506 granulepos=op.granulepos;
507 if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy
508 header handling. The
509 header packets aren't
510 audio, so if/when we
511 submit them,
512 vorbis_synthesis will
513 reject them */
515 /* suck in the synthesis data and track bitrate */
517 int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
518 /* for proper use of libvorbis within libvorbisfile,
519 oldsamples will always be zero. */
520 if(oldsamples){
521 ret=OV_EFAULT;
522 goto cleanup;
525 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
526 vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
527 vf->bittrack+=op.bytes*8;
530 /* update the pcm offset. */
531 if(granulepos!=-1 && !op.e_o_s){
532 int link=(vf->seekable?vf->current_link:0);
533 int i,samples;
535 /* this packet has a pcm_offset on it (the last packet
536 completed on a page carries the offset) After processing
537 (above), we know the pcm position of the *last* sample
538 ready to be returned. Find the offset of the *first*
540 As an aside, this trick is inaccurate if we begin
541 reading anew right at the last page; the end-of-stream
542 granulepos declares the last frame in the stream, and the
543 last packet of the last page may be a partial frame.
544 So, we need a previous granulepos from an in-sequence page
545 to have a reference point. Thus the !op.e_o_s clause
546 above */
548 if(vf->seekable && link>0)
549 granulepos-=vf->pcmlengths[link*2];
550 if(granulepos<0)granulepos=0; /* actually, this
551 shouldn't be possible
552 here unless the stream
553 is very broken */
555 samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
557 granulepos-=samples;
558 for(i=0;i<link;i++)
559 granulepos+=vf->pcmlengths[i*2+1];
560 vf->pcm_offset=granulepos;
562 ret=1;
563 goto cleanup;
566 else
567 break;
571 if(vf->ready_state>=OPENED){
572 int ret;
573 if(!readp){
574 ret=0;
575 goto cleanup;
577 if((ret=_get_next_page(vf,&og,-1))<0){
578 ret=OV_EOF; /* eof. leave unitialized */
579 goto cleanup;
582 /* bitrate tracking; add the header's bytes here, the body bytes
583 are done by packet above */
584 vf->bittrack+=og.header_len*8;
586 /* has our decoding just traversed a bitstream boundary? */
587 if(vf->ready_state==INITSET){
588 if(vf->current_serialno!=ogg_page_serialno(&og)){
589 if(!spanp){
590 ret=OV_EOF;
591 goto cleanup;
594 _decode_clear(vf);
596 if(!vf->seekable){
597 vorbis_info_clear(vf->vi);
598 vorbis_comment_clear(vf->vc);
604 /* Do we need to load a new machine before submitting the page? */
605 /* This is different in the seekable and non-seekable cases.
607 In the seekable case, we already have all the header
608 information loaded and cached; we just initialize the machine
609 with it and continue on our merry way.
611 In the non-seekable (streaming) case, we'll only be at a
612 boundary if we just left the previous logical bitstream and
613 we're now nominally at the header of the next bitstream
616 if(vf->ready_state!=INITSET){
617 int link;
619 if(vf->ready_state<STREAMSET){
620 if(vf->seekable){
621 vf->current_serialno=ogg_page_serialno(&og);
623 /* match the serialno to bitstream section. We use this rather than
624 offset positions to avoid problems near logical bitstream
625 boundaries */
626 for(link=0;link<vf->links;link++)
627 if(vf->serialnos[link]==vf->current_serialno)break;
628 if(link==vf->links){
629 ret=OV_EBADLINK; /* sign of a bogus stream. error out,
630 leave machine uninitialized */
631 goto cleanup;
634 vf->current_link=link;
636 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
637 vf->ready_state=STREAMSET;
639 }else{
640 /* we're streaming */
641 /* fetch the three header packets, build the info struct */
643 int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
644 if(ret) goto cleanup;
645 vf->current_link++;
646 link=0;
650 _make_decode_ready(vf);
652 ogg_stream_pagein(vf->os,&og);
654 cleanup:
655 ogg_packet_release(&op);
656 ogg_page_release(&og);
657 return ret;
660 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
661 long ibytes, ov_callbacks callbacks){
662 int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
663 int ret;
665 memset(vf,0,sizeof(*vf));
666 vf->datasource=f;
667 vf->callbacks = callbacks;
669 /* init the framing state */
670 vf->oy=ogg_sync_create();
672 /* perhaps some data was previously read into a buffer for testing
673 against other stream types. Allow initialization from this
674 previously read data (as we may be reading from a non-seekable
675 stream) */
676 if(initial){
677 char *buffer=(char *)ogg_sync_bufferin(vf->oy,ibytes);
678 memcpy(buffer,initial,ibytes);
679 ogg_sync_wrote(vf->oy,ibytes);
682 /* can we seek? Stevens suggests the seek test was portable */
683 if(offsettest!=-1)vf->seekable=1;
685 /* No seeking yet; Set up a 'single' (current) logical bitstream
686 entry for partial open */
687 vf->links=1;
688 vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
689 vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
690 vf->os=ogg_stream_create(-1); /* fill in the serialno later */
692 /* Try to fetch the headers, maintaining all the storage */
693 if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
694 vf->datasource=NULL;
695 ov_clear(vf);
696 }else if(vf->ready_state < PARTOPEN)
697 vf->ready_state=PARTOPEN;
698 return(ret);
701 static int _ov_open2(OggVorbis_File *vf){
702 if(vf->ready_state < OPENED)
703 vf->ready_state=OPENED;
704 if(vf->seekable){
705 int ret=_open_seekable2(vf);
706 if(ret){
707 vf->datasource=NULL;
708 ov_clear(vf);
710 return(ret);
712 return 0;
716 /* clear out the OggVorbis_File struct */
717 int ov_clear(OggVorbis_File *vf){
718 if(vf){
719 vorbis_block_clear(&vf->vb);
720 vorbis_dsp_clear(&vf->vd);
721 ogg_stream_destroy(vf->os);
723 if(vf->vi && vf->links){
724 int i;
725 for(i=0;i<vf->links;i++){
726 vorbis_info_clear(vf->vi+i);
727 vorbis_comment_clear(vf->vc+i);
729 _ogg_free(vf->vi);
730 _ogg_free(vf->vc);
732 if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
733 if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
734 if(vf->serialnos)_ogg_free(vf->serialnos);
735 if(vf->offsets)_ogg_free(vf->offsets);
736 ogg_sync_destroy(vf->oy);
738 if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
739 memset(vf,0,sizeof(*vf));
741 #ifdef DEBUG_LEAKS
742 _VDBG_dump();
743 #endif
744 return(0);
747 /* inspects the OggVorbis file and finds/documents all the logical
748 bitstreams contained in it. Tries to be tolerant of logical
749 bitstream sections that are truncated/woogie.
751 return: -1) error
752 0) OK
755 int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
756 ov_callbacks callbacks){
757 #if defined(CPU_COLDFIRE)
758 /* this seems to be the closest we get to an init function, let's init emac
759 here. rounding is disabled because of MULT31_SHIFT15, which will be
760 inaccurate with rounding in its current incarnation */
761 coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
762 #endif
763 int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
764 if(ret)return ret;
765 return _ov_open2(vf);
768 /* returns: total PCM length (samples) of content if i==-1 PCM length
769 (samples) of that logical bitstream for i==0 to n
770 OV_EINVAL if the stream is not seekable (we can't know the
771 length) or only partially open
773 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
774 if(vf->ready_state<OPENED)return(OV_EINVAL);
775 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
776 if(i<0){
777 ogg_int64_t acc=0;
778 int i;
779 for(i=0;i<vf->links;i++)
780 acc+=ov_pcm_total(vf,i);
781 return(acc);
782 }else{
783 return(vf->pcmlengths[i*2+1]);
787 /* returns: total milliseconds of content if i==-1
788 milliseconds in that logical bitstream for i==0 to n
789 OV_EINVAL if the stream is not seekable (we can't know the
790 length) or only partially open
792 ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
793 if(vf->ready_state<OPENED)return(OV_EINVAL);
794 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
795 if(i<0){
796 ogg_int64_t acc=0;
797 int i;
798 for(i=0;i<vf->links;i++)
799 acc+=ov_time_total(vf,i);
800 return(acc);
801 }else{
802 return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
806 /* seek to an offset relative to the *compressed* data. This also
807 scans packets to update the PCM cursor. It will cross a logical
808 bitstream boundary, but only if it can't get any packets out of the
809 tail of the bitstream we seek to (so no surprises).
811 returns zero on success, nonzero on failure */
813 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
814 ogg_stream_state *work_os=NULL;
815 ogg_page og={0,0,0,0};
816 ogg_packet op={0,0,0,0,0,0};
818 if(vf->ready_state<OPENED)return(OV_EINVAL);
819 if(!vf->seekable)
820 return(OV_ENOSEEK); /* don't dump machine if we can't seek */
822 if(pos<0 || pos>vf->end)return(OV_EINVAL);
824 /* don't yet clear out decoding machine (if it's initialized), in
825 the case we're in the same link. Restart the decode lapping, and
826 let _fetch_and_process_packet deal with a potential bitstream
827 boundary */
828 vf->pcm_offset=-1;
829 ogg_stream_reset_serialno(vf->os,
830 vf->current_serialno); /* must set serialno */
831 vorbis_synthesis_restart(&vf->vd);
833 _seek_helper(vf,pos);
835 /* we need to make sure the pcm_offset is set, but we don't want to
836 advance the raw cursor past good packets just to get to the first
837 with a granulepos. That's not equivalent behavior to beginning
838 decoding as immediately after the seek position as possible.
840 So, a hack. We use two stream states; a local scratch state and
841 the shared vf->os stream state. We use the local state to
842 scan, and the shared state as a buffer for later decode.
844 Unfortuantely, on the last page we still advance to last packet
845 because the granulepos on the last page is not necessarily on a
846 packet boundary, and we need to make sure the granpos is
847 correct.
851 int lastblock=0;
852 int accblock=0;
853 int thisblock;
854 int eosflag=0;
856 work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */
857 while(1){
858 if(vf->ready_state>=STREAMSET){
859 /* snarf/scan a packet if we can */
860 int result=ogg_stream_packetout(work_os,&op);
862 if(result>0){
864 if(vf->vi[vf->current_link].codec_setup){
865 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
866 if(thisblock<0){
867 ogg_stream_packetout(vf->os,NULL);
868 thisblock=0;
869 }else{
871 if(eosflag)
872 ogg_stream_packetout(vf->os,NULL);
873 else
874 if(lastblock)accblock+=(lastblock+thisblock)>>2;
877 if(op.granulepos!=-1){
878 int i,link=vf->current_link;
879 ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
880 if(granulepos<0)granulepos=0;
882 for(i=0;i<link;i++)
883 granulepos+=vf->pcmlengths[i*2+1];
884 vf->pcm_offset=granulepos-accblock;
885 break;
887 lastblock=thisblock;
888 continue;
889 }else
890 ogg_stream_packetout(vf->os,NULL);
894 if(!lastblock){
895 if(_get_next_page(vf,&og,-1)<0){
896 vf->pcm_offset=ov_pcm_total(vf,-1);
897 break;
899 }else{
900 /* huh? Bogus stream with packets but no granulepos */
901 vf->pcm_offset=-1;
902 break;
905 /* has our decoding just traversed a bitstream boundary? */
906 if(vf->ready_state>=STREAMSET)
907 if(vf->current_serialno!=ogg_page_serialno(&og)){
908 _decode_clear(vf); /* clear out stream state */
909 ogg_stream_destroy(work_os);
912 if(vf->ready_state<STREAMSET){
913 int link;
915 vf->current_serialno=ogg_page_serialno(&og);
916 for(link=0;link<vf->links;link++)
917 if(vf->serialnos[link]==vf->current_serialno)break;
918 if(link==vf->links)
919 goto seek_error; /* sign of a bogus stream. error out,
920 leave machine uninitialized */
922 vf->current_link=link;
924 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
925 ogg_stream_reset_serialno(work_os,vf->current_serialno);
926 vf->ready_state=STREAMSET;
931 ogg_page dup;
932 ogg_page_dup(&dup,&og);
933 eosflag=ogg_page_eos(&og);
934 ogg_stream_pagein(vf->os,&og);
935 ogg_stream_pagein(work_os,&dup);
940 ogg_packet_release(&op);
941 ogg_page_release(&og);
942 ogg_stream_destroy(work_os);
943 vf->bittrack=0;
944 vf->samptrack=0;
945 return(0);
947 seek_error:
948 ogg_packet_release(&op);
949 ogg_page_release(&og);
951 /* dump the machine so we're in a known state */
952 vf->pcm_offset=-1;
953 ogg_stream_destroy(work_os);
954 _decode_clear(vf);
955 return OV_EBADLINK;
958 /* Page granularity seek (faster than sample granularity because we
959 don't do the last bit of decode to find a specific sample).
961 Seek to the last [granule marked] page preceeding the specified pos
962 location, such that decoding past the returned point will quickly
963 arrive at the requested position. */
964 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
965 int link=-1;
966 ogg_int64_t result=0;
967 ogg_int64_t total=ov_pcm_total(vf,-1);
968 ogg_page og={0,0,0,0};
969 ogg_packet op={0,0,0,0,0,0};
971 if(vf->ready_state<OPENED)return(OV_EINVAL);
972 if(!vf->seekable)return(OV_ENOSEEK);
973 if(pos<0 || pos>total)return(OV_EINVAL);
975 /* which bitstream section does this pcm offset occur in? */
976 for(link=vf->links-1;link>=0;link--){
977 total-=vf->pcmlengths[link*2+1];
978 if(pos>=total)break;
981 /* search within the logical bitstream for the page with the highest
982 pcm_pos preceeding (or equal to) pos. There is a danger here;
983 missing pages or incorrect frame number information in the
984 bitstream could make our task impossible. Account for that (it
985 would be an error condition) */
987 /* new search algorithm by HB (Nicholas Vinen) */
989 ogg_int64_t end=vf->offsets[link+1];
990 ogg_int64_t begin=vf->offsets[link];
991 ogg_int64_t begintime = vf->pcmlengths[link*2];
992 ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
993 ogg_int64_t target=pos-total+begintime;
994 ogg_int64_t best=begin;
996 while(begin<end){
997 ogg_int64_t bisect;
999 if(end-begin<CHUNKSIZE){
1000 bisect=begin;
1001 }else{
1002 /* take a (pretty decent) guess. */
1003 bisect=begin +
1004 (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
1005 if(bisect<=begin)
1006 bisect=begin+1;
1009 _seek_helper(vf,bisect);
1011 while(begin<end){
1012 result=_get_next_page(vf,&og,end-vf->offset);
1013 if(result==OV_EREAD) goto seek_error;
1014 if(result<0){
1015 if(bisect<=begin+1)
1016 end=begin; /* found it */
1017 else{
1018 if(bisect==0) goto seek_error;
1019 bisect-=CHUNKSIZE;
1020 if(bisect<=begin)bisect=begin+1;
1021 _seek_helper(vf,bisect);
1023 }else{
1024 ogg_int64_t granulepos=ogg_page_granulepos(&og);
1025 if(granulepos==-1)continue;
1026 if(granulepos<target){
1027 best=result; /* raw offset of packet with granulepos */
1028 begin=vf->offset; /* raw offset of next page */
1029 begintime=granulepos;
1031 if(target-begintime>44100)break;
1032 bisect=begin; /* *not* begin + 1 */
1033 }else{
1034 if(bisect<=begin+1)
1035 end=begin; /* found it */
1036 else{
1037 if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1038 end=result;
1039 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1040 if(bisect<=begin)bisect=begin+1;
1041 _seek_helper(vf,bisect);
1042 }else{
1043 end=result;
1044 endtime=granulepos;
1045 break;
1053 /* found our page. seek to it, update pcm offset. Easier case than
1054 raw_seek, don't keep packets preceeding granulepos. */
1057 /* seek */
1058 _seek_helper(vf,best);
1059 vf->pcm_offset=-1;
1061 if(_get_next_page(vf,&og,-1)<0){
1062 ogg_page_release(&og);
1063 return(OV_EOF); /* shouldn't happen */
1066 if(link!=vf->current_link){
1067 /* Different link; dump entire decode machine */
1068 _decode_clear(vf);
1070 vf->current_link=link;
1071 vf->current_serialno=ogg_page_serialno(&og);
1072 vf->ready_state=STREAMSET;
1074 }else{
1075 vorbis_synthesis_restart(&vf->vd);
1078 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
1079 ogg_stream_pagein(vf->os,&og);
1081 /* pull out all but last packet; the one with granulepos */
1082 while(1){
1083 result=ogg_stream_packetpeek(vf->os,&op);
1084 if(result==0){
1085 /* !!! the packet finishing this page originated on a
1086 preceeding page. Keep fetching previous pages until we
1087 get one with a granulepos or without the 'continued' flag
1088 set. Then just use raw_seek for simplicity. */
1090 _seek_helper(vf,best);
1092 while(1){
1093 result=_get_prev_page(vf,&og);
1094 if(result<0) goto seek_error;
1095 if(ogg_page_granulepos(&og)>-1 ||
1096 !ogg_page_continued(&og)){
1097 return ov_raw_seek(vf,result);
1099 vf->offset=result;
1102 if(result<0){
1103 result = OV_EBADPACKET;
1104 goto seek_error;
1106 if(op.granulepos!=-1){
1107 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1108 if(vf->pcm_offset<0)vf->pcm_offset=0;
1109 vf->pcm_offset+=total;
1110 break;
1111 }else
1112 result=ogg_stream_packetout(vf->os,NULL);
1117 /* verify result */
1118 if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1119 result=OV_EFAULT;
1120 goto seek_error;
1122 vf->bittrack=0;
1123 vf->samptrack=0;
1125 ogg_page_release(&og);
1126 ogg_packet_release(&op);
1127 return(0);
1129 seek_error:
1131 ogg_page_release(&og);
1132 ogg_packet_release(&op);
1134 /* dump machine so we're in a known state */
1135 vf->pcm_offset=-1;
1136 _decode_clear(vf);
1137 return (int)result;
1140 /* seek to a sample offset relative to the decompressed pcm stream
1141 returns zero on success, nonzero on failure */
1143 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1144 ogg_packet op={0,0,0,0,0,0};
1145 ogg_page og={0,0,0,0};
1147 int thisblock,lastblock=0;
1148 int ret=ov_pcm_seek_page(vf,pos);
1149 if(ret<0)return(ret);
1150 _make_decode_ready(vf);
1152 /* discard leading packets we don't need for the lapping of the
1153 position we want; don't decode them */
1155 while(1){
1157 int ret=ogg_stream_packetpeek(vf->os,&op);
1158 if(ret>0){
1159 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1160 if(thisblock<0){
1161 ogg_stream_packetout(vf->os,NULL);
1162 continue; /* non audio packet */
1164 if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1166 if(vf->pcm_offset+((thisblock+
1167 vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1169 /* remove the packet from packet queue and track its granulepos */
1170 ogg_stream_packetout(vf->os,NULL);
1171 vorbis_synthesis(&vf->vb,&op,0); /* set up a vb with
1172 only tracking, no
1173 pcm_decode */
1174 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
1176 /* end of logical stream case is hard, especially with exact
1177 length positioning. */
1179 if(op.granulepos>-1){
1180 int i;
1181 /* always believe the stream markers */
1182 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1183 if(vf->pcm_offset<0)vf->pcm_offset=0;
1184 for(i=0;i<vf->current_link;i++)
1185 vf->pcm_offset+=vf->pcmlengths[i*2+1];
1188 lastblock=thisblock;
1190 }else{
1191 if(ret<0 && ret!=OV_HOLE)break;
1193 /* suck in a new page */
1194 if(_get_next_page(vf,&og,-1)<0)break;
1195 if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
1197 if(vf->ready_state<STREAMSET){
1198 int link;
1200 vf->current_serialno=ogg_page_serialno(&og);
1201 for(link=0;link<vf->links;link++)
1202 if(vf->serialnos[link]==vf->current_serialno)break;
1203 if(link==vf->links){
1204 ogg_page_release(&og);
1205 ogg_packet_release(&op);
1206 return(OV_EBADLINK);
1208 vf->current_link=link;
1210 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
1211 vf->ready_state=STREAMSET;
1212 _make_decode_ready(vf);
1213 lastblock=0;
1216 ogg_stream_pagein(vf->os,&og);
1220 vf->bittrack=0;
1221 vf->samptrack=0;
1222 /* discard samples until we reach the desired position. Crossing a
1223 logical bitstream boundary with abandon is OK. */
1224 while(vf->pcm_offset<pos){
1225 ogg_int64_t target=pos-vf->pcm_offset;
1226 long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1228 if(samples>target)samples=target;
1229 vorbis_synthesis_read(&vf->vd,samples);
1230 vf->pcm_offset+=samples;
1232 if(samples<target)
1233 if(_fetch_and_process_packet(vf,1,1)<=0)
1234 vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1237 ogg_page_release(&og);
1238 ogg_packet_release(&op);
1239 return 0;
1242 /* seek to a playback time relative to the decompressed pcm stream
1243 returns zero on success, nonzero on failure */
1244 int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
1245 /* translate time to PCM position and call ov_pcm_seek */
1247 int link=-1;
1248 ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
1249 ogg_int64_t time_total=ov_time_total(vf,-1);
1251 if(vf->ready_state<OPENED)return(OV_EINVAL);
1252 if(!vf->seekable)return(OV_ENOSEEK);
1253 if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
1255 /* which bitstream section does this time offset occur in? */
1256 for(link=vf->links-1;link>=0;link--){
1257 pcm_total-=vf->pcmlengths[link*2+1];
1258 time_total-=ov_time_total(vf,link);
1259 if(milliseconds>=time_total)break;
1262 /* enough information to convert time offset to pcm offset */
1264 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
1265 return(ov_pcm_seek(vf,target));
1269 /* tell the current stream offset cursor. Note that seek followed by
1270 tell will likely not give the set offset due to caching */
1271 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1272 if(vf->ready_state<OPENED)return(OV_EINVAL);
1273 return(vf->offset);
1276 /* return time offset (milliseconds) of next PCM sample to be read */
1277 ogg_int64_t ov_time_tell(OggVorbis_File *vf) ICODE_ATTR_TREMOR_NOT_MDCT;
1278 ogg_int64_t ov_time_tell(OggVorbis_File *vf){
1279 int link=0;
1280 ogg_int64_t pcm_total=0;
1281 ogg_int64_t time_total=0;
1283 if(vf->ready_state<OPENED)return(OV_EINVAL);
1284 if(vf->seekable){
1285 pcm_total=ov_pcm_total(vf,-1);
1286 time_total=ov_time_total(vf,-1);
1288 /* which bitstream section does this time offset occur in? */
1289 for(link=vf->links-1;link>=0;link--){
1290 pcm_total-=vf->pcmlengths[link*2+1];
1291 time_total-=ov_time_total(vf,link);
1292 if(vf->pcm_offset>=pcm_total)break;
1296 return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1299 /* link: -1) return the vorbis_info struct for the bitstream section
1300 currently being decoded
1301 0-n) to request information for a specific bitstream section
1303 In the case of a non-seekable bitstream, any call returns the
1304 current bitstream. NULL in the case that the machine is not
1305 initialized */
1307 vorbis_info *ov_info(OggVorbis_File *vf,int link){
1308 if(vf->seekable){
1309 if(link<0)
1310 if(vf->ready_state>=STREAMSET)
1311 return vf->vi+vf->current_link;
1312 else
1313 return vf->vi;
1314 else
1315 if(link>=vf->links)
1316 return NULL;
1317 else
1318 return vf->vi+link;
1319 }else{
1320 return vf->vi;
1324 /* input values: pcm_channels) a float vector per channel of output
1325 length) the sample length being read by the app
1327 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1328 0) EOF
1329 n) number of samples of PCM actually returned. The
1330 below works on a packet-by-packet basis, so the
1331 return length is not related to the 'length' passed
1332 in, just guaranteed to fit.
1334 *section) set to the logical bitstream number */
1336 long ov_read_fixed(OggVorbis_File *vf,ogg_int32_t ***pcm_channels,int length,
1337 int *bitstream){
1338 if(vf->ready_state<OPENED)return(OV_EINVAL);
1340 while(1){
1341 if(vf->ready_state==INITSET){
1342 ogg_int32_t **pcm;
1343 long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1344 if(samples){
1345 if(pcm_channels)*pcm_channels=pcm;
1346 if(samples>length)samples=length;
1347 vorbis_synthesis_read(&vf->vd,samples);
1348 vf->pcm_offset+=samples;
1349 if(bitstream)*bitstream=vf->current_link;
1350 return samples;
1355 /* suck in another packet */
1357 int ret=_fetch_and_process_packet(vf,1,1);
1358 if(ret==OV_EOF)return(0);
1359 if(ret<=0)return(ret);