1 /********************************************************************
3 * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS DISTRIBUTING. *
8 * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *
9 * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: stdio-based convenience library for opening/seeking/decoding
15 author: Monty <xiphmont@mit.edu>
16 modifications by: Monty
17 last modification date: Nov 02 1999
19 ********************************************************************/
24 #include "vorbisfile.h"
26 /* A 'chained bitstream' is a Vorbis bitstream that contains more than
27 one logical bitstream arranged end to end (the only form of Ogg
28 multiplexing allowed in a Vorbis bitstream; grouping [parallel
29 multiplexing] is not allowed in Vorbis) */
31 /* A Vorbis file can be played beginning to end (streamed) without
32 worrying ahead of time about chaining (see decoder_example.c). If
33 we have the whole file, however, and want random access
34 (seeking/scrubbing) or desire to know the total length/time of a
35 file, we need to account for the possibility of chaining. */
37 /* We can handle things a number of ways; we can determine the entire
38 bitstream structure right off the bat, or find pieces on demand.
39 This example determines and caches structure for the entire
40 bitstream, but builds a virtual decoder on the fly when moving
41 between links in the chain. */
43 /* There are also different ways to implement seeking. Enough
44 information exists in an Ogg bitstream to seek to
45 sample-granularity positions in the output. Or, one can seek by
46 picking some portion of the stream roughtly in the area if we only
47 want course navigation through the stream. */
49 /*************************************************************************
50 * Many, many internal helpers. The intention is not to be confusing;
51 * rampant duplication and monolithic function implementation would be
52 * harder to understand anyway. The high level functions are last. Begin
53 * grokking near the end of the file */
55 /* read a little more data from the file/pipe into the ogg_sync framer */
56 #define CHUNKSIZE 4096
57 static long _get_data(OggVorbis_File *vf){
58 char *buffer=ogg_sync_buffer(&vf->oy,4096);
59 long bytes=fread(buffer,1,4096,vf->f);
60 ogg_sync_wrote(&vf->oy,bytes);
64 /* save a tiny smidge of verbosity to make the code more readable */
65 static void _seek_helper(OggVorbis_File *vf,long offset){
66 fseek(vf->f,offset,SEEK_SET);
68 ogg_sync_reset(&vf->oy);
71 /* The read/seek functions track absolute position within the stream */
73 /* from the head of the stream, get the next page. boundary specifies
74 if the function is allowed to fetch more data from the stream (and
75 how much) or only use internally buffered data.
77 boundary: -1) unbounded search
78 0) read no additional data; use cached only
79 n) search for a new page beginning for n bytes
81 return: -1) did not find a page
82 n) found a page at absolute offset n */
84 static long _get_next_page(OggVorbis_File *vf,ogg_page *og,int boundary){
85 if(boundary>0)boundary+=vf->offset;
89 if(boundary>0 && vf->offset>=boundary)return(-1);
90 more=ogg_sync_pageseek(&vf->oy,og);
97 /* send more paramedics */
98 if(!boundary)return(-1);
99 if(_get_data(vf)<=0)return(-1);
101 /* got a page. Return the offset at the page beginning,
102 advance the internal offset past the page end */
112 /* find the latest page beginning before the current stream cursor
113 position. Much dirtier than the above as Ogg doesn't have any
114 backward search linkage. no 'readp' as it will certainly have to
116 static long _get_prev_page(OggVorbis_File *vf,ogg_page *og){
117 long begin=vf->offset;
123 _seek_helper(vf,begin);
124 while(vf->offset<begin+CHUNKSIZE){
125 ret=_get_next_page(vf,og,begin+CHUNKSIZE-vf->offset);
134 /* we have the offset. Actually snork and hold the page now */
135 _seek_helper(vf,offset);
136 ret=_get_next_page(vf,og,CHUNKSIZE);
138 /* this shouldn't be possible */
139 fprintf(stderr,"Missed page fencepost at end of logical bitstream. "
146 /* finds each bitstream link one at a time using a bisection search
147 (has to begin by knowing the offset of the lb's initial page).
148 Recurses for each link so it can alloc the link storage after
149 finding them all, then unroll and fill the cache at the same time */
150 static void _bisect_forward_serialno(OggVorbis_File *vf,
156 long endsearched=end;
160 /* the below guards against garbage seperating the last and
161 first pages of two links. */
162 while(searched<endsearched){
166 if(endsearched-searched<CHUNKSIZE){
169 bisect=(searched+endsearched)/2;
172 _seek_helper(vf,bisect);
173 ret=_get_next_page(vf,&og,-1);
174 if(ret<0 || ogg_page_serialno(&og)!=currentno){
178 searched=ret+og.header_len+og.body_len;
183 vf->offsets=malloc((m+2)*sizeof(long));
184 vf->offsets[m+1]=searched;
186 _bisect_forward_serialno(vf,next,next,
187 end,ogg_page_serialno(&og),m+1);
190 vf->offsets[m]=begin;
193 /* uses the local ogg_stream storage in vf; this is important for
194 non-streaming input sources */
195 static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,long *serialno){
200 ret=_get_next_page(vf,&og,CHUNKSIZE);
202 fprintf(stderr,"Did not find initial header for bitstream.\n");
206 if(serialno)*serialno=ogg_page_serialno(&og);
207 ogg_stream_init(&vf->os,ogg_page_serialno(&og));
209 /* extract the initial header from the first page and verify that the
210 Ogg bitstream is in fact Vorbis data */
212 vorbis_info_init(vi);
216 ogg_stream_pagein(&vf->os,&og);
218 int result=ogg_stream_packetout(&vf->os,&op);
221 fprintf(stderr,"Corrupt header in logical bitstream. "
225 if(vorbis_info_headerin(vi,&op)){
226 fprintf(stderr,"Illegal header in logical bitstream. "
233 if(_get_next_page(vf,&og,1)<0){
234 fprintf(stderr,"Missing header in logical bitstream. "
242 vorbis_info_clear(vi);
243 ogg_stream_clear(&vf->os);
247 /* last step of the OggVorbis_File initialization; get all the
248 vorbis_info structs and PCM positions. Only called by the seekable
249 initialization (local stream storage is hacked slightly; pay
250 attention to how that's done) */
251 static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first){
255 vf->vi=malloc(vf->links*sizeof(vorbis_info));
256 vf->pcmlengths=malloc(vf->links*sizeof(size64));
257 vf->serialnos=malloc(vf->links*sizeof(long));
259 for(i=0;i<vf->links;i++){
261 /* we already grabbed the initial header earlier. This just
262 saves the waste of grabbing it again */
263 memcpy(vf->vi+i,first,sizeof(vorbis_info));
264 memset(first,0,sizeof(vorbis_info));
267 /* seek to the location of the initial header */
269 _seek_helper(vf,vf->offsets[i]);
270 if(_fetch_headers(vf,vf->vi+i,NULL)==-1){
271 vorbis_info_clear(vf->vi+i);
272 fprintf(stderr,"Error opening logical bitstream #%d.\n\n",i+1);
274 ogg_stream_clear(&vf->os); /* clear local storage. This is not
275 done in _fetch_headers, as that may
276 be called in a non-seekable stream
277 (in which case, we need to preserve
278 the stream local storage) */
282 /* get the serial number and PCM length of this link. To do this,
283 get the last page of the stream */
285 long end=vf->offsets[i+1];
286 _seek_helper(vf,end);
289 ret=_get_prev_page(vf,&og);
291 /* this should not be possible */
292 fprintf(stderr,"Could not find last page of logical "
293 "bitstream #%d\n\n",i);
294 vorbis_info_clear(vf->vi+i);
297 if(ogg_page_frameno(&og)!=-1){
298 vf->serialnos[i]=ogg_page_serialno(&og);
299 vf->pcmlengths[i]=ogg_page_frameno(&og);
307 static int _open_seekable(OggVorbis_File *vf){
313 /* is this even vorbis...? */
314 ret=_fetch_headers(vf,&initial,&serialno);
315 ogg_stream_clear(&vf->os);
316 if(ret==-1)return(-1);
318 /* we can seek, so set out learning all about this file */
320 fseek(vf->f,0,SEEK_END); /* Yes, I know I used lseek earlier. */
321 vf->offset=vf->end=ftell(vf->f);
323 /* We get the offset for the last page of the physical bitstream.
324 Most OggVorbis files will contain a single logical bitstream */
325 end=_get_prev_page(vf,&og);
327 /* moer than one logical bitstream? */
328 if(ogg_page_serialno(&og)!=serialno){
330 /* Chained bitstream. Bisect-search each logical bitstream
331 section. Do so based on serial number only */
332 _bisect_forward_serialno(vf,0,0,end+1,serialno,0);
336 /* Only one logical bitstream */
337 _bisect_forward_serialno(vf,0,end,end+1,serialno,0);
341 _prefetch_all_headers(vf,&initial);
346 static int _open_nonseekable(OggVorbis_File *vf){
350 /* Try to fetch the headers, maintaining all the storage */
351 if(_fetch_headers(vf,&vi,&serialno)==-1)return(-1);
353 /* we cannot seek. Set up a 'single' (current) logical bitstream entry */
355 vf->vi=malloc(sizeof(vorbis_info));
356 vf->serialnos=malloc(sizeof(long));
358 memcpy(vf->vi,&vi,sizeof(vorbis_info));
359 vf->serialnos[0]=serialno;
363 /**********************************************************************
364 * The helpers are over; it's all toplevel interface from here on out */
366 /* clear out the OggVorbis_File struct */
367 int ov_clear(OggVorbis_File *vf){
369 vorbis_block_clear(&vf->vb);
370 vorbis_dsp_clear(&vf->vd);
371 ogg_stream_clear(&vf->os);
373 if(vf->vi && vf->links){
375 for(i=0;i<vf->links;i++)
376 vorbis_info_clear(vf->vi+i);
379 if(vf->pcmlengths)free(vf->pcmlengths);
380 if(vf->serialnos)free(vf->serialnos);
381 if(vf->offsets)free(vf->offsets);
382 ogg_sync_clear(&vf->oy);
383 if(vf->f)fclose(vf->f);
384 memset(vf,0,sizeof(OggVorbis_File));
389 /* inspects the OggVorbis file and finds/documents all the logical
390 bitstreams contained in it. Tries to be tolerant of logical
391 bitstream sections that are truncated/woogie. */
392 int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
393 long offset=lseek(fileno(f),0,SEEK_CUR);
396 memset(vf,0,sizeof(OggVorbis_File));
399 /* init the framing state */
400 ogg_sync_init(&vf->oy);
402 /* perhaps some data was previously read into a buffer for testing
403 against other stream types. Allow initialization from this
404 previously read data (as we may be reading from a non-seekable
407 char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
408 memcpy(buffer,initial,ibytes);
409 ogg_sync_wrote(&vf->oy,ibytes);
412 /* can we seek? Stevens suggests the seek test was portable */
414 ret=_open_seekable(vf);
416 ret=_open_nonseekable(vf);
425 double ov_lbtime(OggVorbis_File *vf,int i){
426 if(i>=0 && i<vf->links)
427 return((float)(vf->pcmlengths[i])/vf->vi[i].rate);
431 double ov_totaltime(OggVorbis_File *vf){
434 for(i=0;i<vf->links;i++)
435 acc+=ov_lbtime(vf,i);
439 /* seek to an offset relative to the *compressed* data */
440 int ov_seek_stream(OggVorbis_File *vf,long pos){
447 /* seek to the beginning of the next logical bitstream within the
448 physical bitstream */
449 int ov_seek_bitstream(OggVorbis_File *vf,long pos){
456 /* seek to an offset relative to the decompressed *output* stream */
457 int ov_seek_pcm(OggVorbis_File *vf,long pos){
463 int ov_seek_time(OggVorbis_File *vf,double seconds){