Rearranged chaining example into a library interface (vorbisfile.a)
[platform/upstream/libvorbis.git] / lib / vorbisfile.c
1 /********************************************************************
2  *                                                                  *
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.                            *
7  *                                                                  *
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/                                             *
11  *                                                                  *
12  ********************************************************************
13
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
18
19  ********************************************************************/
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "codec.h"
24 #include "vorbisfile.h"
25
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) */
30
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. */
36
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. */
42
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. */
48
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 */
54
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);
61   return(bytes);
62 }
63
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);
67   vf->offset=offset;
68   ogg_sync_reset(&vf->oy);
69 }
70
71 /* The read/seek functions track absolute position within the stream */
72
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.
76
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
80
81    return:   -1) did not find a page 
82               n) found a page at absolute offset n */
83
84 static long _get_next_page(OggVorbis_File *vf,ogg_page *og,int boundary){
85   if(boundary>0)boundary+=vf->offset;
86   while(1){
87     long more;
88
89     if(boundary>0 && vf->offset>=boundary)return(-1);
90     more=ogg_sync_pageseek(&vf->oy,og);
91     
92     if(more<0){
93       /* skipped n bytes */
94       vf->offset-=more;
95     }else{
96       if(more==0){
97         /* send more paramedics */
98         if(!boundary)return(-1);
99         if(_get_data(vf)<=0)return(-1);
100       }else{
101         /* got a page.  Return the offset at the page beginning,
102            advance the internal offset past the page end */
103         long ret=vf->offset;
104         vf->offset+=more;
105         return(ret);
106         
107       }
108     }
109   }
110 }
111
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
115    read. */
116 static long _get_prev_page(OggVorbis_File *vf,ogg_page *og){
117   long begin=vf->offset;
118   long ret;
119   int offset=-1;
120
121   while(offset==-1){
122     begin-=CHUNKSIZE;
123     _seek_helper(vf,begin);
124     while(vf->offset<begin+CHUNKSIZE){
125       ret=_get_next_page(vf,og,begin+CHUNKSIZE-vf->offset);
126       if(ret==-1){
127         break;
128       }else{
129         offset=ret;
130       }
131     }
132   }
133
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);
137   if(ret==-1){
138     /* this shouldn't be possible */
139     fprintf(stderr,"Missed page fencepost at end of logical bitstream. "
140             "Exiting.\n");
141     exit(1);
142   }
143   return(offset);
144 }
145
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,
151                                      long begin,
152                                      long searched,
153                                      long end,
154                                      long currentno,
155                                      long m){
156   long endsearched=end;
157   long next=end;
158   ogg_page og;
159   
160   /* the below guards against garbage seperating the last and
161      first pages of two links. */
162   while(searched<endsearched){
163     long bisect;
164     long ret;
165     
166     if(endsearched-searched<CHUNKSIZE){
167       bisect=searched;
168     }else{
169       bisect=(searched+endsearched)/2;
170     }
171     
172     _seek_helper(vf,bisect);
173     ret=_get_next_page(vf,&og,-1);
174     if(ret<0 || ogg_page_serialno(&og)!=currentno){
175       endsearched=bisect;
176       if(ret>=0)next=ret;
177     }else{
178       searched=ret+og.header_len+og.body_len;
179     }
180   }
181   if(searched>=end){
182     vf->links=m+1;
183     vf->offsets=malloc((m+2)*sizeof(long));
184     vf->offsets[m+1]=searched;
185   }else{
186     _bisect_forward_serialno(vf,next,next,
187                              end,ogg_page_serialno(&og),m+1);
188   }
189   
190   vf->offsets[m]=begin;
191 }
192
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){
196   ogg_page og;
197   ogg_packet op;
198   int i,ret;
199
200   ret=_get_next_page(vf,&og,CHUNKSIZE);
201   if(ret==-1){
202     fprintf(stderr,"Did not find initial header for bitstream.\n");
203     return -1;
204   }
205   
206   if(serialno)*serialno=ogg_page_serialno(&og);
207   ogg_stream_init(&vf->os,ogg_page_serialno(&og));
208   
209   /* extract the initial header from the first page and verify that the
210      Ogg bitstream is in fact Vorbis data */
211   
212   vorbis_info_init(vi);
213   
214   i=0;
215   while(i<3){
216     ogg_stream_pagein(&vf->os,&og);
217     while(i<3){
218       int result=ogg_stream_packetout(&vf->os,&op);
219       if(result==0)break;
220       if(result==-1){
221         fprintf(stderr,"Corrupt header in logical bitstream.  "
222                 "Exiting.\n");
223         goto bail_header;
224       }
225       if(vorbis_info_headerin(vi,&op)){
226         fprintf(stderr,"Illegal header in logical bitstream.  "
227                 "Exiting.\n");
228         goto bail_header;
229       }
230       i++;
231     }
232     if(i<3)
233       if(_get_next_page(vf,&og,1)<0){
234         fprintf(stderr,"Missing header in logical bitstream.  "
235                 "Exiting.\n");
236         goto bail_header;
237       }
238   }
239   return 0; 
240
241  bail_header:
242   vorbis_info_clear(vi);
243   ogg_stream_clear(&vf->os);
244   return -1;
245 }
246
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){
252   ogg_page og;
253   int i,ret;
254   
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));
258   
259   for(i=0;i<vf->links;i++){
260     if(first && i==0){
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));
265     }else{
266
267       /* seek to the location of the initial header */
268
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);
273     
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) */
279       }
280     }
281
282     /* get the serial number and PCM length of this link. To do this,
283        get the last page of the stream */
284     {
285       long end=vf->offsets[i+1];
286       _seek_helper(vf,end);
287
288       while(1){
289         ret=_get_prev_page(vf,&og);
290         if(ret==-1){
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);
295           break;
296         }
297         if(ogg_page_frameno(&og)!=-1){
298           vf->serialnos[i]=ogg_page_serialno(&og);
299           vf->pcmlengths[i]=ogg_page_frameno(&og);
300           break;
301         }
302       }
303     }
304   }
305 }
306
307 static int _open_seekable(OggVorbis_File *vf){
308   vorbis_info initial;
309   long serialno,end;
310   int ret;
311   ogg_page og;
312   
313   /* is this even vorbis...? */
314   ret=_fetch_headers(vf,&initial,&serialno);
315   ogg_stream_clear(&vf->os);
316   if(ret==-1)return(-1);
317   
318   /* we can seek, so set out learning all about this file */
319   vf->seekable=1;
320   fseek(vf->f,0,SEEK_END); /* Yes, I know I used lseek earlier. */
321   vf->offset=vf->end=ftell(vf->f);
322   
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);
326
327   /* moer than one logical bitstream? */
328   if(ogg_page_serialno(&og)!=serialno){
329
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);
333
334   }else{
335
336     /* Only one logical bitstream */
337     _bisect_forward_serialno(vf,0,end,end+1,serialno,0);
338
339   }
340
341   _prefetch_all_headers(vf,&initial);
342
343   return(0);
344 }
345
346 static int _open_nonseekable(OggVorbis_File *vf){
347   vorbis_info vi;
348   long serialno;
349
350   /* Try to fetch the headers, maintaining all the storage */
351   if(_fetch_headers(vf,&vi,&serialno)==-1)return(-1);
352   
353   /* we cannot seek. Set up a 'single' (current) logical bitstream entry  */
354   vf->links=1;
355   vf->vi=malloc(sizeof(vorbis_info));
356   vf->serialnos=malloc(sizeof(long));
357   
358   memcpy(vf->vi,&vi,sizeof(vorbis_info));
359   vf->serialnos[0]=serialno;
360   return 0;
361 }
362  
363 /**********************************************************************
364  * The helpers are over; it's all toplevel interface from here on out */
365  
366 /* clear out the OggVorbis_File struct */
367 int ov_clear(OggVorbis_File *vf){
368   if(vf){
369     vorbis_block_clear(&vf->vb);
370     vorbis_dsp_clear(&vf->vd);
371     ogg_stream_clear(&vf->os);
372     
373     if(vf->vi && vf->links){
374       int i;
375       for(i=0;i<vf->links;i++)
376         vorbis_info_clear(vf->vi+i);
377       free(vf->vi);
378     }
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));
385   }
386   return(0);
387 }
388
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);
394   int ret;
395
396   memset(vf,0,sizeof(OggVorbis_File));
397   vf->f=f;
398
399   /* init the framing state */
400   ogg_sync_init(&vf->oy);
401
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
405      stream) */
406   if(initial){
407     char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
408     memcpy(buffer,initial,ibytes);
409     ogg_sync_wrote(&vf->oy,ibytes);
410   }
411
412   /* can we seek? Stevens suggests the seek test was portable */
413   if(offset!=-1){
414     ret=_open_seekable(vf);
415   }else{
416     ret=_open_nonseekable(vf);
417   }
418   if(ret){
419     vf->f=NULL;
420     ov_clear(vf);
421   }
422   return(ret);
423 }
424
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);
428   return(0);
429 }
430
431 double ov_totaltime(OggVorbis_File *vf){
432   double acc=0;
433   int i;
434   for(i=0;i<vf->links;i++)
435     acc+=ov_lbtime(vf,i);
436   return(acc);
437 }
438
439 /* seek to an offset relative to the *compressed* data */
440 int ov_seek_stream(OggVorbis_File *vf,long pos){
441
442
443
444
445 }
446
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){
450
451
452
453
454 }
455
456 /* seek to an offset relative to the decompressed *output* stream */
457 int ov_seek_pcm(OggVorbis_File *vf,long pos){
458
459
460
461 }
462
463 int ov_seek_time(OggVorbis_File *vf,double seconds){
464
465
466
467 }
468
469
470
471
472
473