|
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 ******************************************************************** |
|
13 |
|
14 function: stdio-based convenience library for opening/seeking/decoding |
|
15 last mod: $Id: vorbisfile.c,v 1.6 2003/03/30 23:40:56 xiphmont Exp $ |
|
16 |
|
17 ********************************************************************/ |
|
18 |
|
19 #include <stdlib.h> |
|
20 #include <stdio.h> |
|
21 #include <errno.h> |
|
22 #include <string.h> |
|
23 #include <math.h> |
|
24 |
|
25 #include "ivorbiscodec.h" |
|
26 #include "ivorbisfile.h" |
|
27 |
|
28 #include "misc.h" |
|
29 |
|
30 /* A 'chained bitstream' is a Vorbis bitstream that contains more than |
|
31 one logical bitstream arranged end to end (the only form of Ogg |
|
32 multiplexing allowed in a Vorbis bitstream; grouping [parallel |
|
33 multiplexing] is not allowed in Vorbis) */ |
|
34 |
|
35 /* A Vorbis file can be played beginning to end (streamed) without |
|
36 worrying ahead of time about chaining (see decoder_example.c). If |
|
37 we have the whole file, however, and want random access |
|
38 (seeking/scrubbing) or desire to know the total length/time of a |
|
39 file, we need to account for the possibility of chaining. */ |
|
40 |
|
41 /* We can handle things a number of ways; we can determine the entire |
|
42 bitstream structure right off the bat, or find pieces on demand. |
|
43 This example determines and caches structure for the entire |
|
44 bitstream, but builds a virtual decoder on the fly when moving |
|
45 between links in the chain. */ |
|
46 |
|
47 /* There are also different ways to implement seeking. Enough |
|
48 information exists in an Ogg bitstream to seek to |
|
49 sample-granularity positions in the output. Or, one can seek by |
|
50 picking some portion of the stream roughly in the desired area if |
|
51 we only want coarse navigation through the stream. */ |
|
52 |
|
53 /************************************************************************* |
|
54 * Many, many internal helpers. The intention is not to be confusing; |
|
55 * rampant duplication and monolithic function implementation would be |
|
56 * harder to understand anyway. The high level functions are last. Begin |
|
57 * grokking near the end of the file */ |
|
58 |
|
59 |
|
60 /* read a little more data from the file/pipe into the ogg_sync framer */ |
|
61 static long _get_data(OggVorbis_File *vf){ |
|
62 errno=0; |
|
63 if(vf->datasource){ |
|
64 unsigned char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE); |
|
65 long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource); |
|
66 if(bytes>0)ogg_sync_wrote(vf->oy,bytes); |
|
67 if(bytes==0 && errno)return(-1); |
|
68 return(bytes); |
|
69 }else |
|
70 return(0); |
|
71 } |
|
72 |
|
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; |
|
82 } |
|
83 } |
|
84 |
|
85 /* The read/seek functions track absolute position within the stream */ |
|
86 |
|
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. |
|
90 |
|
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 |
|
94 |
|
95 return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) |
|
96 n) found a page at absolute offset n |
|
97 |
|
98 produces a refcounted page */ |
|
99 |
|
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; |
|
105 |
|
106 if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); |
|
107 more=ogg_sync_pageseek(vf->oy,og); |
|
108 |
|
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); |
|
116 { |
|
117 long ret=_get_data(vf); |
|
118 if(ret==0)return(OV_EOF); |
|
119 if(ret<0)return(OV_EREAD); |
|
120 } |
|
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); |
|
127 |
|
128 } |
|
129 } |
|
130 } |
|
131 } |
|
132 |
|
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 */ |
|
138 |
|
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; |
|
144 |
|
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; |
|
157 } |
|
158 } |
|
159 } |
|
160 |
|
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); |
|
167 |
|
168 return(offset); |
|
169 } |
|
170 |
|
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; |
|
185 |
|
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; |
|
190 |
|
191 if(endsearched-searched<CHUNKSIZE){ |
|
192 bisect=searched; |
|
193 }else{ |
|
194 bisect=(searched+endsearched)/2; |
|
195 } |
|
196 |
|
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; |
|
205 } |
|
206 ogg_page_release(&og); |
|
207 } |
|
208 |
|
209 _seek_helper(vf,next); |
|
210 ret=_get_next_page(vf,&og,-1); |
|
211 if(ret==OV_EREAD)return(OV_EREAD); |
|
212 |
|
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); |
|
224 } |
|
225 |
|
226 vf->offsets[m]=begin; |
|
227 vf->serialnos[m]=currentno; |
|
228 return(0); |
|
229 } |
|
230 |
|
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) */ |
|
234 |
|
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; |
|
243 |
|
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; |
|
249 } |
|
250 |
|
251 ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr)); |
|
252 if(serialno)*serialno=vf->os->serialno; |
|
253 vf->ready_state=STREAMSET; |
|
254 |
|
255 /* extract the initial header from the first page and verify that the |
|
256 Ogg bitstream is in fact Vorbis data */ |
|
257 |
|
258 vorbis_info_init(vi); |
|
259 vorbis_comment_init(vc); |
|
260 |
|
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; |
|
270 } |
|
271 if((ret=vorbis_synthesis_headerin(vi,vc,&op))){ |
|
272 goto bail_header; |
|
273 } |
|
274 i++; |
|
275 } |
|
276 if(i<3) |
|
277 if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ |
|
278 ret=OV_EBADHEADER; |
|
279 goto bail_header; |
|
280 } |
|
281 } |
|
282 |
|
283 ogg_packet_release(&op); |
|
284 ogg_page_release(&og); |
|
285 return 0; |
|
286 |
|
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; |
|
293 |
|
294 return ret; |
|
295 } |
|
296 |
|
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) */ |
|
301 |
|
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; |
|
310 |
|
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)); |
|
315 |
|
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); |
|
321 |
|
322 }else{ |
|
323 |
|
324 /* seek to the location of the initial header */ |
|
325 |
|
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; |
|
331 } |
|
332 } |
|
333 |
|
334 /* fetch beginning PCM offset */ |
|
335 |
|
336 if(vf->dataoffsets[i]!=-1){ |
|
337 ogg_int64_t accumulated=0,pos; |
|
338 long lastblock=-1; |
|
339 int result; |
|
340 |
|
341 ogg_stream_reset_serialno(vf->os,vf->serialnos[i]); |
|
342 |
|
343 while(1){ |
|
344 ogg_packet op={0,0,0,0,0,0}; |
|
345 |
|
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; |
|
351 |
|
352 if(ogg_page_serialno(&og)!=vf->serialnos[i]) |
|
353 break; |
|
354 |
|
355 pos=ogg_page_granulepos(&og); |
|
356 |
|
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; |
|
365 } |
|
366 } |
|
367 ogg_packet_release(&op); |
|
368 |
|
369 if(pos!=-1){ |
|
370 /* pcm offset of last packet on the first audio page */ |
|
371 accumulated= pos-accumulated; |
|
372 break; |
|
373 } |
|
374 } |
|
375 |
|
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; |
|
379 |
|
380 vf->pcmlengths[i*2]=accumulated; |
|
381 } |
|
382 |
|
383 /* get the PCM length of this link. To do this, |
|
384 get the last page of the stream */ |
|
385 { |
|
386 ogg_int64_t end=vf->offsets[i+1]; |
|
387 _seek_helper(vf,end); |
|
388 |
|
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; |
|
396 } |
|
397 if(ogg_page_granulepos(&og)!=-1){ |
|
398 vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2]; |
|
399 break; |
|
400 } |
|
401 vf->offset=ret; |
|
402 } |
|
403 } |
|
404 } |
|
405 ogg_page_release(&og); |
|
406 } |
|
407 |
|
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); |
|
414 } |
|
415 vorbis_block_init(&vf->vd,&vf->vb); |
|
416 vf->ready_state=INITSET; |
|
417 vf->bittrack=0; |
|
418 vf->samptrack=0; |
|
419 return; |
|
420 } |
|
421 |
|
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}; |
|
427 |
|
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); |
|
433 |
|
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); |
|
438 |
|
439 /* more than one logical bitstream? */ |
|
440 tempserialno=ogg_page_serialno(&og); |
|
441 ogg_page_release(&og); |
|
442 |
|
443 if(tempserialno!=serialno){ |
|
444 |
|
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); |
|
448 |
|
449 }else{ |
|
450 |
|
451 /* Only one logical bitstream */ |
|
452 if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD); |
|
453 |
|
454 } |
|
455 |
|
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)); |
|
459 } |
|
460 |
|
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; |
|
466 } |
|
467 |
|
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). |
|
473 |
|
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 |
|
477 */ |
|
478 |
|
479 static int _fetch_and_process_packet(OggVorbis_File *vf, |
|
480 int readp, |
|
481 int spanp){ |
|
482 ogg_page og={0,0,0,0}; |
|
483 ogg_packet op={0,0,0,0,0,0}; |
|
484 int ret=0; |
|
485 |
|
486 /* handle one packet. Try to fetch it from current stream state */ |
|
487 /* extract packets from page */ |
|
488 while(1){ |
|
489 |
|
490 /* process a packet if we can. If the machine isn't loaded, |
|
491 neither is a page */ |
|
492 if(vf->ready_state==INITSET){ |
|
493 while(1) { |
|
494 int result=ogg_stream_packetout(vf->os,&op); |
|
495 ogg_int64_t granulepos; |
|
496 |
|
497 if(result<0){ |
|
498 ret=OV_HOLE; /* hole in the data. */ |
|
499 goto cleanup; |
|
500 } |
|
501 if(result>0){ |
|
502 /* got a packet. process it */ |
|
503 granulepos=op.granulepos; |
|
504 if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy |
|
505 header handling. The |
|
506 header packets aren't |
|
507 audio, so if/when we |
|
508 submit them, |
|
509 vorbis_synthesis will |
|
510 reject them */ |
|
511 |
|
512 /* suck in the synthesis data and track bitrate */ |
|
513 { |
|
514 int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); |
|
515 /* for proper use of libvorbis within libvorbisfile, |
|
516 oldsamples will always be zero. */ |
|
517 if(oldsamples){ |
|
518 ret=OV_EFAULT; |
|
519 goto cleanup; |
|
520 } |
|
521 |
|
522 vorbis_synthesis_blockin(&vf->vd,&vf->vb); |
|
523 vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples; |
|
524 vf->bittrack+=op.bytes*8; |
|
525 } |
|
526 |
|
527 /* update the pcm offset. */ |
|
528 if(granulepos!=-1 && !op.e_o_s){ |
|
529 int link=(vf->seekable?vf->current_link:0); |
|
530 int i,samples; |
|
531 |
|
532 /* this packet has a pcm_offset on it (the last packet |
|
533 completed on a page carries the offset) After processing |
|
534 (above), we know the pcm position of the *last* sample |
|
535 ready to be returned. Find the offset of the *first* |
|
536 |
|
537 As an aside, this trick is inaccurate if we begin |
|
538 reading anew right at the last page; the end-of-stream |
|
539 granulepos declares the last frame in the stream, and the |
|
540 last packet of the last page may be a partial frame. |
|
541 So, we need a previous granulepos from an in-sequence page |
|
542 to have a reference point. Thus the !op.e_o_s clause |
|
543 above */ |
|
544 |
|
545 if(vf->seekable && link>0) |
|
546 granulepos-=vf->pcmlengths[link*2]; |
|
547 if(granulepos<0)granulepos=0; /* actually, this |
|
548 shouldn't be possible |
|
549 here unless the stream |
|
550 is very broken */ |
|
551 |
|
552 samples=vorbis_synthesis_pcmout(&vf->vd,NULL); |
|
553 |
|
554 granulepos-=samples; |
|
555 for(i=0;i<link;i++) |
|
556 granulepos+=vf->pcmlengths[i*2+1]; |
|
557 vf->pcm_offset=granulepos; |
|
558 } |
|
559 ret=1; |
|
560 goto cleanup; |
|
561 } |
|
562 } |
|
563 else |
|
564 break; |
|
565 } |
|
566 } |
|
567 |
|
568 if(vf->ready_state>=OPENED){ |
|
569 int ret; |
|
570 if(!readp){ |
|
571 ret=0; |
|
572 goto cleanup; |
|
573 } |
|
574 if((ret=_get_next_page(vf,&og,-1))<0){ |
|
575 ret=OV_EOF; /* eof. leave unitialized */ |
|
576 goto cleanup; |
|
577 } |
|
578 |
|
579 /* bitrate tracking; add the header's bytes here, the body bytes |
|
580 are done by packet above */ |
|
581 vf->bittrack+=og.header_len*8; |
|
582 |
|
583 /* has our decoding just traversed a bitstream boundary? */ |
|
584 if(vf->ready_state==INITSET){ |
|
585 if(vf->current_serialno!=ogg_page_serialno(&og)){ |
|
586 if(!spanp){ |
|
587 ret=OV_EOF; |
|
588 goto cleanup; |
|
589 } |
|
590 |
|
591 _decode_clear(vf); |
|
592 |
|
593 if(!vf->seekable){ |
|
594 vorbis_info_clear(vf->vi); |
|
595 vorbis_comment_clear(vf->vc); |
|
596 } |
|
597 } |
|
598 } |
|
599 } |
|
600 |
|
601 /* Do we need to load a new machine before submitting the page? */ |
|
602 /* This is different in the seekable and non-seekable cases. |
|
603 |
|
604 In the seekable case, we already have all the header |
|
605 information loaded and cached; we just initialize the machine |
|
606 with it and continue on our merry way. |
|
607 |
|
608 In the non-seekable (streaming) case, we'll only be at a |
|
609 boundary if we just left the previous logical bitstream and |
|
610 we're now nominally at the header of the next bitstream |
|
611 */ |
|
612 |
|
613 if(vf->ready_state!=INITSET){ |
|
614 int link; |
|
615 |
|
616 if(vf->ready_state<STREAMSET){ |
|
617 if(vf->seekable){ |
|
618 vf->current_serialno=ogg_page_serialno(&og); |
|
619 |
|
620 /* match the serialno to bitstream section. We use this rather than |
|
621 offset positions to avoid problems near logical bitstream |
|
622 boundaries */ |
|
623 for(link=0;link<vf->links;link++) |
|
624 if(vf->serialnos[link]==vf->current_serialno)break; |
|
625 if(link==vf->links){ |
|
626 ret=OV_EBADLINK; /* sign of a bogus stream. error out, |
|
627 leave machine uninitialized */ |
|
628 goto cleanup; |
|
629 } |
|
630 |
|
631 vf->current_link=link; |
|
632 |
|
633 ogg_stream_reset_serialno(vf->os,vf->current_serialno); |
|
634 vf->ready_state=STREAMSET; |
|
635 |
|
636 }else{ |
|
637 /* we're streaming */ |
|
638 /* fetch the three header packets, build the info struct */ |
|
639 |
|
640 int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og); |
|
641 if(ret) goto cleanup; |
|
642 vf->current_link++; |
|
643 link=0; |
|
644 } |
|
645 } |
|
646 |
|
647 _make_decode_ready(vf); |
|
648 } |
|
649 ogg_stream_pagein(vf->os,&og); |
|
650 } |
|
651 cleanup: |
|
652 ogg_packet_release(&op); |
|
653 ogg_page_release(&og); |
|
654 return ret; |
|
655 } |
|
656 |
|
657 /* if, eg, 64 bit stdio is configured by default, this will build with |
|
658 fseek64 */ |
|
659 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ |
|
660 if(f==NULL)return(-1); |
|
661 return fseek(f,off,whence); |
|
662 } |
|
663 |
|
664 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, |
|
665 long ibytes, ov_callbacks callbacks){ |
|
666 int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1); |
|
667 int ret; |
|
668 |
|
669 memset(vf,0,sizeof(*vf)); |
|
670 vf->datasource=f; |
|
671 vf->callbacks = callbacks; |
|
672 |
|
673 /* init the framing state */ |
|
674 vf->oy=ogg_sync_create(); |
|
675 |
|
676 /* perhaps some data was previously read into a buffer for testing |
|
677 against other stream types. Allow initialization from this |
|
678 previously read data (as we may be reading from a non-seekable |
|
679 stream) */ |
|
680 if(initial){ |
|
681 unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes); |
|
682 memcpy(buffer,initial,ibytes); |
|
683 ogg_sync_wrote(vf->oy,ibytes); |
|
684 } |
|
685 |
|
686 /* can we seek? Stevens suggests the seek test was portable */ |
|
687 if(offsettest!=-1)vf->seekable=1; |
|
688 |
|
689 /* No seeking yet; Set up a 'single' (current) logical bitstream |
|
690 entry for partial open */ |
|
691 vf->links=1; |
|
692 vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); |
|
693 vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); |
|
694 vf->os=ogg_stream_create(-1); /* fill in the serialno later */ |
|
695 |
|
696 /* Try to fetch the headers, maintaining all the storage */ |
|
697 if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){ |
|
698 vf->datasource=NULL; |
|
699 ov_clear(vf); |
|
700 }else if(vf->ready_state < PARTOPEN) |
|
701 vf->ready_state=PARTOPEN; |
|
702 return(ret); |
|
703 } |
|
704 |
|
705 static int _ov_open2(OggVorbis_File *vf){ |
|
706 if(vf->ready_state < OPENED) |
|
707 vf->ready_state=OPENED; |
|
708 if(vf->seekable){ |
|
709 int ret=_open_seekable2(vf); |
|
710 if(ret){ |
|
711 vf->datasource=NULL; |
|
712 ov_clear(vf); |
|
713 } |
|
714 return(ret); |
|
715 } |
|
716 return 0; |
|
717 } |
|
718 |
|
719 |
|
720 /* clear out the OggVorbis_File struct */ |
|
721 int ov_clear(OggVorbis_File *vf){ |
|
722 if(vf){ |
|
723 vorbis_block_clear(&vf->vb); |
|
724 vorbis_dsp_clear(&vf->vd); |
|
725 ogg_stream_destroy(vf->os); |
|
726 |
|
727 if(vf->vi && vf->links){ |
|
728 int i; |
|
729 for(i=0;i<vf->links;i++){ |
|
730 vorbis_info_clear(vf->vi+i); |
|
731 vorbis_comment_clear(vf->vc+i); |
|
732 } |
|
733 _ogg_free(vf->vi); |
|
734 _ogg_free(vf->vc); |
|
735 } |
|
736 if(vf->dataoffsets)_ogg_free(vf->dataoffsets); |
|
737 if(vf->pcmlengths)_ogg_free(vf->pcmlengths); |
|
738 if(vf->serialnos)_ogg_free(vf->serialnos); |
|
739 if(vf->offsets)_ogg_free(vf->offsets); |
|
740 ogg_sync_destroy(vf->oy); |
|
741 |
|
742 if(vf->datasource)(vf->callbacks.close_func)(vf->datasource); |
|
743 memset(vf,0,sizeof(*vf)); |
|
744 } |
|
745 #ifdef DEBUG_LEAKS |
|
746 _VDBG_dump(); |
|
747 #endif |
|
748 return(0); |
|
749 } |
|
750 |
|
751 /* inspects the OggVorbis file and finds/documents all the logical |
|
752 bitstreams contained in it. Tries to be tolerant of logical |
|
753 bitstream sections that are truncated/woogie. |
|
754 |
|
755 return: -1) error |
|
756 0) OK |
|
757 */ |
|
758 |
|
759 int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, |
|
760 ov_callbacks callbacks){ |
|
761 int ret=_ov_open1(f,vf,initial,ibytes,callbacks); |
|
762 if(ret)return ret; |
|
763 return _ov_open2(vf); |
|
764 } |
|
765 |
|
766 int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ |
|
767 ov_callbacks callbacks = { |
|
768 (size_t (*)(void *, size_t, size_t, void *)) fread, |
|
769 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, |
|
770 (int (*)(void *)) fclose, |
|
771 (long (*)(void *)) ftell |
|
772 }; |
|
773 |
|
774 return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); |
|
775 } |
|
776 |
|
777 /* Only partially open the vorbis file; test for Vorbisness, and load |
|
778 the headers for the first chain. Do not seek (although test for |
|
779 seekability). Use ov_test_open to finish opening the file, else |
|
780 ov_clear to close/free it. Same return codes as open. */ |
|
781 |
|
782 int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, |
|
783 ov_callbacks callbacks) |
|
784 { |
|
785 return _ov_open1(f,vf,initial,ibytes,callbacks); |
|
786 } |
|
787 |
|
788 int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ |
|
789 ov_callbacks callbacks = { |
|
790 (size_t (*)(void *, size_t, size_t, void *)) fread, |
|
791 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, |
|
792 (int (*)(void *)) fclose, |
|
793 (long (*)(void *)) ftell |
|
794 }; |
|
795 |
|
796 return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); |
|
797 } |
|
798 |
|
799 int ov_test_open(OggVorbis_File *vf){ |
|
800 if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); |
|
801 return _ov_open2(vf); |
|
802 } |
|
803 |
|
804 /* How many logical bitstreams in this physical bitstream? */ |
|
805 long ov_streams(OggVorbis_File *vf){ |
|
806 return vf->links; |
|
807 } |
|
808 |
|
809 /* Is the FILE * associated with vf seekable? */ |
|
810 long ov_seekable(OggVorbis_File *vf){ |
|
811 return vf->seekable; |
|
812 } |
|
813 |
|
814 /* returns the bitrate for a given logical bitstream or the entire |
|
815 physical bitstream. If the file is open for random access, it will |
|
816 find the *actual* average bitrate. If the file is streaming, it |
|
817 returns the nominal bitrate (if set) else the average of the |
|
818 upper/lower bounds (if set) else -1 (unset). |
|
819 |
|
820 If you want the actual bitrate field settings, get them from the |
|
821 vorbis_info structs */ |
|
822 |
|
823 long ov_bitrate(OggVorbis_File *vf,int i){ |
|
824 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
825 if(i>=vf->links)return(OV_EINVAL); |
|
826 if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); |
|
827 if(i<0){ |
|
828 ogg_int64_t bits=0; |
|
829 int i; |
|
830 for(i=0;i<vf->links;i++) |
|
831 bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; |
|
832 /* This once read: return(rint(bits/ov_time_total(vf,-1))); |
|
833 * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, |
|
834 * so this is slightly transformed to make it work. |
|
835 */ |
|
836 return(bits*1000/ov_time_total(vf,-1)); |
|
837 }else{ |
|
838 if(vf->seekable){ |
|
839 /* return the actual bitrate */ |
|
840 return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i)); |
|
841 }else{ |
|
842 /* return nominal if set */ |
|
843 if(vf->vi[i].bitrate_nominal>0){ |
|
844 return vf->vi[i].bitrate_nominal; |
|
845 }else{ |
|
846 if(vf->vi[i].bitrate_upper>0){ |
|
847 if(vf->vi[i].bitrate_lower>0){ |
|
848 return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; |
|
849 }else{ |
|
850 return vf->vi[i].bitrate_upper; |
|
851 } |
|
852 } |
|
853 return(OV_FALSE); |
|
854 } |
|
855 } |
|
856 } |
|
857 } |
|
858 |
|
859 /* returns the actual bitrate since last call. returns -1 if no |
|
860 additional data to offer since last call (or at beginning of stream), |
|
861 EINVAL if stream is only partially open |
|
862 */ |
|
863 long ov_bitrate_instant(OggVorbis_File *vf){ |
|
864 int link=(vf->seekable?vf->current_link:0); |
|
865 long ret; |
|
866 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
867 if(vf->samptrack==0)return(OV_FALSE); |
|
868 ret=vf->bittrack/vf->samptrack*vf->vi[link].rate; |
|
869 vf->bittrack=0; |
|
870 vf->samptrack=0; |
|
871 return(ret); |
|
872 } |
|
873 |
|
874 /* Guess */ |
|
875 long ov_serialnumber(OggVorbis_File *vf,int i){ |
|
876 if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); |
|
877 if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); |
|
878 if(i<0){ |
|
879 return(vf->current_serialno); |
|
880 }else{ |
|
881 return(vf->serialnos[i]); |
|
882 } |
|
883 } |
|
884 |
|
885 /* returns: total raw (compressed) length of content if i==-1 |
|
886 raw (compressed) length of that logical bitstream for i==0 to n |
|
887 OV_EINVAL if the stream is not seekable (we can't know the length) |
|
888 or if stream is only partially open |
|
889 */ |
|
890 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ |
|
891 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
892 if(!vf->seekable || i>=vf->links)return(OV_EINVAL); |
|
893 if(i<0){ |
|
894 ogg_int64_t acc=0; |
|
895 int i; |
|
896 for(i=0;i<vf->links;i++) |
|
897 acc+=ov_raw_total(vf,i); |
|
898 return(acc); |
|
899 }else{ |
|
900 return(vf->offsets[i+1]-vf->offsets[i]); |
|
901 } |
|
902 } |
|
903 |
|
904 /* returns: total PCM length (samples) of content if i==-1 PCM length |
|
905 (samples) of that logical bitstream for i==0 to n |
|
906 OV_EINVAL if the stream is not seekable (we can't know the |
|
907 length) or only partially open |
|
908 */ |
|
909 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ |
|
910 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
911 if(!vf->seekable || i>=vf->links)return(OV_EINVAL); |
|
912 if(i<0){ |
|
913 ogg_int64_t acc=0; |
|
914 int i; |
|
915 for(i=0;i<vf->links;i++) |
|
916 acc+=ov_pcm_total(vf,i); |
|
917 return(acc); |
|
918 }else{ |
|
919 return(vf->pcmlengths[i*2+1]); |
|
920 } |
|
921 } |
|
922 |
|
923 /* returns: total milliseconds of content if i==-1 |
|
924 milliseconds in that logical bitstream for i==0 to n |
|
925 OV_EINVAL if the stream is not seekable (we can't know the |
|
926 length) or only partially open |
|
927 */ |
|
928 ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){ |
|
929 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
930 if(!vf->seekable || i>=vf->links)return(OV_EINVAL); |
|
931 if(i<0){ |
|
932 ogg_int64_t acc=0; |
|
933 int i; |
|
934 for(i=0;i<vf->links;i++) |
|
935 acc+=ov_time_total(vf,i); |
|
936 return(acc); |
|
937 }else{ |
|
938 return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate); |
|
939 } |
|
940 } |
|
941 |
|
942 /* seek to an offset relative to the *compressed* data. This also |
|
943 scans packets to update the PCM cursor. It will cross a logical |
|
944 bitstream boundary, but only if it can't get any packets out of the |
|
945 tail of the bitstream we seek to (so no surprises). |
|
946 |
|
947 returns zero on success, nonzero on failure */ |
|
948 |
|
949 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ |
|
950 ogg_stream_state *work_os=NULL; |
|
951 ogg_page og={0,0,0,0}; |
|
952 ogg_packet op={0,0,0,0,0,0}; |
|
953 |
|
954 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
955 if(!vf->seekable) |
|
956 return(OV_ENOSEEK); /* don't dump machine if we can't seek */ |
|
957 |
|
958 if(pos<0 || pos>vf->end)return(OV_EINVAL); |
|
959 |
|
960 /* don't yet clear out decoding machine (if it's initialized), in |
|
961 the case we're in the same link. Restart the decode lapping, and |
|
962 let _fetch_and_process_packet deal with a potential bitstream |
|
963 boundary */ |
|
964 vf->pcm_offset=-1; |
|
965 ogg_stream_reset_serialno(vf->os, |
|
966 vf->current_serialno); /* must set serialno */ |
|
967 vorbis_synthesis_restart(&vf->vd); |
|
968 |
|
969 _seek_helper(vf,pos); |
|
970 |
|
971 /* we need to make sure the pcm_offset is set, but we don't want to |
|
972 advance the raw cursor past good packets just to get to the first |
|
973 with a granulepos. That's not equivalent behavior to beginning |
|
974 decoding as immediately after the seek position as possible. |
|
975 |
|
976 So, a hack. We use two stream states; a local scratch state and |
|
977 the shared vf->os stream state. We use the local state to |
|
978 scan, and the shared state as a buffer for later decode. |
|
979 |
|
980 Unfortuantely, on the last page we still advance to last packet |
|
981 because the granulepos on the last page is not necessarily on a |
|
982 packet boundary, and we need to make sure the granpos is |
|
983 correct. |
|
984 */ |
|
985 |
|
986 { |
|
987 int lastblock=0; |
|
988 int accblock=0; |
|
989 int thisblock; |
|
990 int eosflag=0; |
|
991 |
|
992 work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */ |
|
993 while(1){ |
|
994 if(vf->ready_state>=STREAMSET){ |
|
995 /* snarf/scan a packet if we can */ |
|
996 int result=ogg_stream_packetout(work_os,&op); |
|
997 |
|
998 if(result>0){ |
|
999 |
|
1000 if(vf->vi[vf->current_link].codec_setup){ |
|
1001 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); |
|
1002 if(thisblock<0){ |
|
1003 ogg_stream_packetout(vf->os,NULL); |
|
1004 thisblock=0; |
|
1005 }else{ |
|
1006 |
|
1007 if(eosflag) |
|
1008 ogg_stream_packetout(vf->os,NULL); |
|
1009 else |
|
1010 if(lastblock)accblock+=(lastblock+thisblock)>>2; |
|
1011 } |
|
1012 |
|
1013 if(op.granulepos!=-1){ |
|
1014 int i,link=vf->current_link; |
|
1015 ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; |
|
1016 if(granulepos<0)granulepos=0; |
|
1017 |
|
1018 for(i=0;i<link;i++) |
|
1019 granulepos+=vf->pcmlengths[i*2+1]; |
|
1020 vf->pcm_offset=granulepos-accblock; |
|
1021 break; |
|
1022 } |
|
1023 lastblock=thisblock; |
|
1024 continue; |
|
1025 }else |
|
1026 ogg_stream_packetout(vf->os,NULL); |
|
1027 } |
|
1028 } |
|
1029 |
|
1030 if(!lastblock){ |
|
1031 if(_get_next_page(vf,&og,-1)<0){ |
|
1032 vf->pcm_offset=ov_pcm_total(vf,-1); |
|
1033 break; |
|
1034 } |
|
1035 }else{ |
|
1036 /* huh? Bogus stream with packets but no granulepos */ |
|
1037 vf->pcm_offset=-1; |
|
1038 break; |
|
1039 } |
|
1040 |
|
1041 /* has our decoding just traversed a bitstream boundary? */ |
|
1042 if(vf->ready_state>=STREAMSET) |
|
1043 if(vf->current_serialno!=ogg_page_serialno(&og)){ |
|
1044 _decode_clear(vf); /* clear out stream state */ |
|
1045 ogg_stream_destroy(work_os); |
|
1046 } |
|
1047 |
|
1048 if(vf->ready_state<STREAMSET){ |
|
1049 int link; |
|
1050 |
|
1051 vf->current_serialno=ogg_page_serialno(&og); |
|
1052 for(link=0;link<vf->links;link++) |
|
1053 if(vf->serialnos[link]==vf->current_serialno)break; |
|
1054 if(link==vf->links) |
|
1055 goto seek_error; /* sign of a bogus stream. error out, |
|
1056 leave machine uninitialized */ |
|
1057 |
|
1058 vf->current_link=link; |
|
1059 |
|
1060 ogg_stream_reset_serialno(vf->os,vf->current_serialno); |
|
1061 ogg_stream_reset_serialno(work_os,vf->current_serialno); |
|
1062 vf->ready_state=STREAMSET; |
|
1063 |
|
1064 } |
|
1065 |
|
1066 { |
|
1067 ogg_page dup; |
|
1068 ogg_page_dup(&dup,&og); |
|
1069 eosflag=ogg_page_eos(&og); |
|
1070 ogg_stream_pagein(vf->os,&og); |
|
1071 ogg_stream_pagein(work_os,&dup); |
|
1072 } |
|
1073 } |
|
1074 } |
|
1075 |
|
1076 ogg_packet_release(&op); |
|
1077 ogg_page_release(&og); |
|
1078 ogg_stream_destroy(work_os); |
|
1079 vf->bittrack=0; |
|
1080 vf->samptrack=0; |
|
1081 return(0); |
|
1082 |
|
1083 seek_error: |
|
1084 ogg_packet_release(&op); |
|
1085 ogg_page_release(&og); |
|
1086 |
|
1087 /* dump the machine so we're in a known state */ |
|
1088 vf->pcm_offset=-1; |
|
1089 ogg_stream_destroy(work_os); |
|
1090 _decode_clear(vf); |
|
1091 return OV_EBADLINK; |
|
1092 } |
|
1093 |
|
1094 /* Page granularity seek (faster than sample granularity because we |
|
1095 don't do the last bit of decode to find a specific sample). |
|
1096 |
|
1097 Seek to the last [granule marked] page preceeding the specified pos |
|
1098 location, such that decoding past the returned point will quickly |
|
1099 arrive at the requested position. */ |
|
1100 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ |
|
1101 int link=-1; |
|
1102 ogg_int64_t result=0; |
|
1103 ogg_int64_t total=ov_pcm_total(vf,-1); |
|
1104 ogg_page og={0,0,0,0}; |
|
1105 ogg_packet op={0,0,0,0,0,0}; |
|
1106 |
|
1107 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1108 if(!vf->seekable)return(OV_ENOSEEK); |
|
1109 if(pos<0 || pos>total)return(OV_EINVAL); |
|
1110 |
|
1111 /* which bitstream section does this pcm offset occur in? */ |
|
1112 for(link=vf->links-1;link>=0;link--){ |
|
1113 total-=vf->pcmlengths[link*2+1]; |
|
1114 if(pos>=total)break; |
|
1115 } |
|
1116 |
|
1117 /* search within the logical bitstream for the page with the highest |
|
1118 pcm_pos preceeding (or equal to) pos. There is a danger here; |
|
1119 missing pages or incorrect frame number information in the |
|
1120 bitstream could make our task impossible. Account for that (it |
|
1121 would be an error condition) */ |
|
1122 |
|
1123 /* new search algorithm by HB (Nicholas Vinen) */ |
|
1124 { |
|
1125 ogg_int64_t end=vf->offsets[link+1]; |
|
1126 ogg_int64_t begin=vf->offsets[link]; |
|
1127 ogg_int64_t begintime = vf->pcmlengths[link*2]; |
|
1128 ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; |
|
1129 ogg_int64_t target=pos-total+begintime; |
|
1130 ogg_int64_t best=begin; |
|
1131 |
|
1132 while(begin<end){ |
|
1133 ogg_int64_t bisect; |
|
1134 |
|
1135 if(end-begin<CHUNKSIZE){ |
|
1136 bisect=begin; |
|
1137 }else{ |
|
1138 /* take a (pretty decent) guess. */ |
|
1139 bisect=begin + |
|
1140 (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE; |
|
1141 if(bisect<=begin) |
|
1142 bisect=begin+1; |
|
1143 } |
|
1144 |
|
1145 _seek_helper(vf,bisect); |
|
1146 |
|
1147 while(begin<end){ |
|
1148 result=_get_next_page(vf,&og,end-vf->offset); |
|
1149 if(result==OV_EREAD) goto seek_error; |
|
1150 if(result<0){ |
|
1151 if(bisect<=begin+1) |
|
1152 end=begin; /* found it */ |
|
1153 else{ |
|
1154 if(bisect==0) goto seek_error; |
|
1155 bisect-=CHUNKSIZE; |
|
1156 if(bisect<=begin)bisect=begin+1; |
|
1157 _seek_helper(vf,bisect); |
|
1158 } |
|
1159 }else{ |
|
1160 ogg_int64_t granulepos=ogg_page_granulepos(&og); |
|
1161 if(granulepos==-1)continue; |
|
1162 if(granulepos<target){ |
|
1163 best=result; /* raw offset of packet with granulepos */ |
|
1164 begin=vf->offset; /* raw offset of next page */ |
|
1165 begintime=granulepos; |
|
1166 |
|
1167 if(target-begintime>44100)break; |
|
1168 bisect=begin; /* *not* begin + 1 */ |
|
1169 }else{ |
|
1170 if(bisect<=begin+1) |
|
1171 end=begin; /* found it */ |
|
1172 else{ |
|
1173 if(end==vf->offset){ /* we're pretty close - we'd be stuck in */ |
|
1174 end=result; |
|
1175 bisect-=CHUNKSIZE; /* an endless loop otherwise. */ |
|
1176 if(bisect<=begin)bisect=begin+1; |
|
1177 _seek_helper(vf,bisect); |
|
1178 }else{ |
|
1179 end=result; |
|
1180 endtime=granulepos; |
|
1181 break; |
|
1182 } |
|
1183 } |
|
1184 } |
|
1185 } |
|
1186 } |
|
1187 } |
|
1188 |
|
1189 /* found our page. seek to it, update pcm offset. Easier case than |
|
1190 raw_seek, don't keep packets preceeding granulepos. */ |
|
1191 { |
|
1192 |
|
1193 /* seek */ |
|
1194 _seek_helper(vf,best); |
|
1195 vf->pcm_offset=-1; |
|
1196 |
|
1197 if(_get_next_page(vf,&og,-1)<0){ |
|
1198 ogg_page_release(&og); |
|
1199 return(OV_EOF); /* shouldn't happen */ |
|
1200 } |
|
1201 |
|
1202 if(link!=vf->current_link){ |
|
1203 /* Different link; dump entire decode machine */ |
|
1204 _decode_clear(vf); |
|
1205 |
|
1206 vf->current_link=link; |
|
1207 vf->current_serialno=ogg_page_serialno(&og); |
|
1208 vf->ready_state=STREAMSET; |
|
1209 |
|
1210 }else{ |
|
1211 vorbis_synthesis_restart(&vf->vd); |
|
1212 } |
|
1213 |
|
1214 ogg_stream_reset_serialno(vf->os,vf->current_serialno); |
|
1215 ogg_stream_pagein(vf->os,&og); |
|
1216 |
|
1217 /* pull out all but last packet; the one with granulepos */ |
|
1218 while(1){ |
|
1219 result=ogg_stream_packetpeek(vf->os,&op); |
|
1220 if(result==0){ |
|
1221 /* !!! the packet finishing this page originated on a |
|
1222 preceeding page. Keep fetching previous pages until we |
|
1223 get one with a granulepos or without the 'continued' flag |
|
1224 set. Then just use raw_seek for simplicity. */ |
|
1225 |
|
1226 _seek_helper(vf,best); |
|
1227 |
|
1228 while(1){ |
|
1229 result=_get_prev_page(vf,&og); |
|
1230 if(result<0) goto seek_error; |
|
1231 if(ogg_page_granulepos(&og)>-1 || |
|
1232 !ogg_page_continued(&og)){ |
|
1233 return ov_raw_seek(vf,result); |
|
1234 } |
|
1235 vf->offset=result; |
|
1236 } |
|
1237 } |
|
1238 if(result<0){ |
|
1239 result = OV_EBADPACKET; |
|
1240 goto seek_error; |
|
1241 } |
|
1242 if(op.granulepos!=-1){ |
|
1243 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; |
|
1244 if(vf->pcm_offset<0)vf->pcm_offset=0; |
|
1245 vf->pcm_offset+=total; |
|
1246 break; |
|
1247 }else |
|
1248 result=ogg_stream_packetout(vf->os,NULL); |
|
1249 } |
|
1250 } |
|
1251 } |
|
1252 |
|
1253 /* verify result */ |
|
1254 if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ |
|
1255 result=OV_EFAULT; |
|
1256 goto seek_error; |
|
1257 } |
|
1258 vf->bittrack=0; |
|
1259 vf->samptrack=0; |
|
1260 |
|
1261 ogg_page_release(&og); |
|
1262 ogg_packet_release(&op); |
|
1263 return(0); |
|
1264 |
|
1265 seek_error: |
|
1266 |
|
1267 ogg_page_release(&og); |
|
1268 ogg_packet_release(&op); |
|
1269 |
|
1270 /* dump machine so we're in a known state */ |
|
1271 vf->pcm_offset=-1; |
|
1272 _decode_clear(vf); |
|
1273 return (int)result; |
|
1274 } |
|
1275 |
|
1276 /* seek to a sample offset relative to the decompressed pcm stream |
|
1277 returns zero on success, nonzero on failure */ |
|
1278 |
|
1279 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ |
|
1280 ogg_packet op={0,0,0,0,0,0}; |
|
1281 ogg_page og={0,0,0,0}; |
|
1282 int thisblock,lastblock=0; |
|
1283 int ret=ov_pcm_seek_page(vf,pos); |
|
1284 if(ret<0)return(ret); |
|
1285 _make_decode_ready(vf); |
|
1286 |
|
1287 /* discard leading packets we don't need for the lapping of the |
|
1288 position we want; don't decode them */ |
|
1289 |
|
1290 while(1){ |
|
1291 |
|
1292 int ret=ogg_stream_packetpeek(vf->os,&op); |
|
1293 if(ret>0){ |
|
1294 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); |
|
1295 if(thisblock<0){ |
|
1296 ogg_stream_packetout(vf->os,NULL); |
|
1297 continue; /* non audio packet */ |
|
1298 } |
|
1299 if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2; |
|
1300 |
|
1301 if(vf->pcm_offset+((thisblock+ |
|
1302 vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break; |
|
1303 |
|
1304 /* remove the packet from packet queue and track its granulepos */ |
|
1305 ogg_stream_packetout(vf->os,NULL); |
|
1306 vorbis_synthesis(&vf->vb,&op,0); /* set up a vb with |
|
1307 only tracking, no |
|
1308 pcm_decode */ |
|
1309 vorbis_synthesis_blockin(&vf->vd,&vf->vb); |
|
1310 |
|
1311 /* end of logical stream case is hard, especially with exact |
|
1312 length positioning. */ |
|
1313 |
|
1314 if(op.granulepos>-1){ |
|
1315 int i; |
|
1316 /* always believe the stream markers */ |
|
1317 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; |
|
1318 if(vf->pcm_offset<0)vf->pcm_offset=0; |
|
1319 for(i=0;i<vf->current_link;i++) |
|
1320 vf->pcm_offset+=vf->pcmlengths[i*2+1]; |
|
1321 } |
|
1322 |
|
1323 lastblock=thisblock; |
|
1324 |
|
1325 }else{ |
|
1326 if(ret<0 && ret!=OV_HOLE)break; |
|
1327 |
|
1328 /* suck in a new page */ |
|
1329 if(_get_next_page(vf,&og,-1)<0)break; |
|
1330 if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf); |
|
1331 |
|
1332 if(vf->ready_state<STREAMSET){ |
|
1333 int link; |
|
1334 |
|
1335 vf->current_serialno=ogg_page_serialno(&og); |
|
1336 for(link=0;link<vf->links;link++) |
|
1337 if(vf->serialnos[link]==vf->current_serialno)break; |
|
1338 if(link==vf->links){ |
|
1339 ogg_page_release(&og); |
|
1340 ogg_packet_release(&op); |
|
1341 return(OV_EBADLINK); |
|
1342 } |
|
1343 vf->current_link=link; |
|
1344 |
|
1345 ogg_stream_reset_serialno(vf->os,vf->current_serialno); |
|
1346 vf->ready_state=STREAMSET; |
|
1347 _make_decode_ready(vf); |
|
1348 lastblock=0; |
|
1349 } |
|
1350 |
|
1351 ogg_stream_pagein(vf->os,&og); |
|
1352 } |
|
1353 } |
|
1354 |
|
1355 vf->bittrack=0; |
|
1356 vf->samptrack=0; |
|
1357 /* discard samples until we reach the desired position. Crossing a |
|
1358 logical bitstream boundary with abandon is OK. */ |
|
1359 while(vf->pcm_offset<pos){ |
|
1360 ogg_int64_t target=pos-vf->pcm_offset; |
|
1361 long samples=vorbis_synthesis_pcmout(&vf->vd,NULL); |
|
1362 |
|
1363 if(samples>target)samples=target; |
|
1364 vorbis_synthesis_read(&vf->vd,samples); |
|
1365 vf->pcm_offset+=samples; |
|
1366 |
|
1367 if(samples<target) |
|
1368 if(_fetch_and_process_packet(vf,1,1)<=0) |
|
1369 vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */ |
|
1370 } |
|
1371 |
|
1372 ogg_page_release(&og); |
|
1373 ogg_packet_release(&op); |
|
1374 return 0; |
|
1375 } |
|
1376 |
|
1377 /* seek to a playback time relative to the decompressed pcm stream |
|
1378 returns zero on success, nonzero on failure */ |
|
1379 int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){ |
|
1380 /* translate time to PCM position and call ov_pcm_seek */ |
|
1381 |
|
1382 int link=-1; |
|
1383 ogg_int64_t pcm_total=ov_pcm_total(vf,-1); |
|
1384 ogg_int64_t time_total=ov_time_total(vf,-1); |
|
1385 |
|
1386 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1387 if(!vf->seekable)return(OV_ENOSEEK); |
|
1388 if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL); |
|
1389 |
|
1390 /* which bitstream section does this time offset occur in? */ |
|
1391 for(link=vf->links-1;link>=0;link--){ |
|
1392 pcm_total-=vf->pcmlengths[link*2+1]; |
|
1393 time_total-=ov_time_total(vf,link); |
|
1394 if(milliseconds>=time_total)break; |
|
1395 } |
|
1396 |
|
1397 /* enough information to convert time offset to pcm offset */ |
|
1398 { |
|
1399 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; |
|
1400 return(ov_pcm_seek(vf,target)); |
|
1401 } |
|
1402 } |
|
1403 |
|
1404 /* page-granularity version of ov_time_seek |
|
1405 returns zero on success, nonzero on failure */ |
|
1406 int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){ |
|
1407 /* translate time to PCM position and call ov_pcm_seek */ |
|
1408 |
|
1409 int link=-1; |
|
1410 ogg_int64_t pcm_total=ov_pcm_total(vf,-1); |
|
1411 ogg_int64_t time_total=ov_time_total(vf,-1); |
|
1412 |
|
1413 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1414 if(!vf->seekable)return(OV_ENOSEEK); |
|
1415 if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL); |
|
1416 |
|
1417 /* which bitstream section does this time offset occur in? */ |
|
1418 for(link=vf->links-1;link>=0;link--){ |
|
1419 pcm_total-=vf->pcmlengths[link*2+1]; |
|
1420 time_total-=ov_time_total(vf,link); |
|
1421 if(milliseconds>=time_total)break; |
|
1422 } |
|
1423 |
|
1424 /* enough information to convert time offset to pcm offset */ |
|
1425 { |
|
1426 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; |
|
1427 return(ov_pcm_seek_page(vf,target)); |
|
1428 } |
|
1429 } |
|
1430 |
|
1431 /* tell the current stream offset cursor. Note that seek followed by |
|
1432 tell will likely not give the set offset due to caching */ |
|
1433 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ |
|
1434 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1435 return(vf->offset); |
|
1436 } |
|
1437 |
|
1438 /* return PCM offset (sample) of next PCM sample to be read */ |
|
1439 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ |
|
1440 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1441 return(vf->pcm_offset); |
|
1442 } |
|
1443 |
|
1444 /* return time offset (milliseconds) of next PCM sample to be read */ |
|
1445 ogg_int64_t ov_time_tell(OggVorbis_File *vf){ |
|
1446 int link=0; |
|
1447 ogg_int64_t pcm_total=0; |
|
1448 ogg_int64_t time_total=0; |
|
1449 |
|
1450 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1451 if(vf->seekable){ |
|
1452 pcm_total=ov_pcm_total(vf,-1); |
|
1453 time_total=ov_time_total(vf,-1); |
|
1454 |
|
1455 /* which bitstream section does this time offset occur in? */ |
|
1456 for(link=vf->links-1;link>=0;link--){ |
|
1457 pcm_total-=vf->pcmlengths[link*2+1]; |
|
1458 time_total-=ov_time_total(vf,link); |
|
1459 if(vf->pcm_offset>=pcm_total)break; |
|
1460 } |
|
1461 } |
|
1462 |
|
1463 return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate); |
|
1464 } |
|
1465 |
|
1466 /* link: -1) return the vorbis_info struct for the bitstream section |
|
1467 currently being decoded |
|
1468 0-n) to request information for a specific bitstream section |
|
1469 |
|
1470 In the case of a non-seekable bitstream, any call returns the |
|
1471 current bitstream. NULL in the case that the machine is not |
|
1472 initialized */ |
|
1473 |
|
1474 vorbis_info *ov_info(OggVorbis_File *vf,int link){ |
|
1475 if(vf->seekable){ |
|
1476 if(link<0) |
|
1477 if(vf->ready_state>=STREAMSET) |
|
1478 return vf->vi+vf->current_link; |
|
1479 else |
|
1480 return vf->vi; |
|
1481 else |
|
1482 if(link>=vf->links) |
|
1483 return NULL; |
|
1484 else |
|
1485 return vf->vi+link; |
|
1486 }else{ |
|
1487 return vf->vi; |
|
1488 } |
|
1489 } |
|
1490 |
|
1491 /* grr, strong typing, grr, no templates/inheritence, grr */ |
|
1492 vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ |
|
1493 if(vf->seekable){ |
|
1494 if(link<0) |
|
1495 if(vf->ready_state>=STREAMSET) |
|
1496 return vf->vc+vf->current_link; |
|
1497 else |
|
1498 return vf->vc; |
|
1499 else |
|
1500 if(link>=vf->links) |
|
1501 return NULL; |
|
1502 else |
|
1503 return vf->vc+link; |
|
1504 }else{ |
|
1505 return vf->vc; |
|
1506 } |
|
1507 } |
|
1508 |
|
1509 /* up to this point, everything could more or less hide the multiple |
|
1510 logical bitstream nature of chaining from the toplevel application |
|
1511 if the toplevel application didn't particularly care. However, at |
|
1512 the point that we actually read audio back, the multiple-section |
|
1513 nature must surface: Multiple bitstream sections do not necessarily |
|
1514 have to have the same number of channels or sampling rate. |
|
1515 |
|
1516 ov_read returns the sequential logical bitstream number currently |
|
1517 being decoded along with the PCM data in order that the toplevel |
|
1518 application can take action on channel/sample rate changes. This |
|
1519 number will be incremented even for streamed (non-seekable) streams |
|
1520 (for seekable streams, it represents the actual logical bitstream |
|
1521 index within the physical bitstream. Note that the accessor |
|
1522 functions above are aware of this dichotomy). |
|
1523 |
|
1524 input values: buffer) a buffer to hold packed PCM data for return |
|
1525 length) the byte length requested to be placed into buffer |
|
1526 |
|
1527 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) |
|
1528 0) EOF |
|
1529 n) number of bytes of PCM actually returned. The |
|
1530 below works on a packet-by-packet basis, so the |
|
1531 return length is not related to the 'length' passed |
|
1532 in, just guaranteed to fit. |
|
1533 |
|
1534 *section) set to the logical bitstream number */ |
|
1535 |
|
1536 long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ |
|
1537 int i,j; |
|
1538 |
|
1539 ogg_int32_t **pcm; |
|
1540 long samples; |
|
1541 |
|
1542 if(vf->ready_state<OPENED)return(OV_EINVAL); |
|
1543 |
|
1544 while(1){ |
|
1545 if(vf->ready_state==INITSET){ |
|
1546 samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); |
|
1547 if(samples)break; |
|
1548 } |
|
1549 |
|
1550 /* suck in another packet */ |
|
1551 { |
|
1552 int ret=_fetch_and_process_packet(vf,1,1); |
|
1553 if(ret==OV_EOF) |
|
1554 return(0); |
|
1555 if(ret<=0) |
|
1556 return(ret); |
|
1557 } |
|
1558 |
|
1559 } |
|
1560 |
|
1561 if(samples>0){ |
|
1562 |
|
1563 /* yay! proceed to pack data into the byte buffer */ |
|
1564 |
|
1565 long channels=ov_info(vf,-1)->channels; |
|
1566 |
|
1567 if(samples>(bytes_req/(2*channels))) |
|
1568 samples=bytes_req/(2*channels); |
|
1569 |
|
1570 for(i=0;i<channels;i++) { /* It's faster in this order */ |
|
1571 ogg_int32_t *src=pcm[i]; |
|
1572 short *dest=((short *)buffer)+i; |
|
1573 for(j=0;j<samples;j++) { |
|
1574 *dest=CLIP_TO_15(src[j]>>9); |
|
1575 dest+=channels; |
|
1576 } |
|
1577 } |
|
1578 |
|
1579 vorbis_synthesis_read(&vf->vd,samples); |
|
1580 vf->pcm_offset+=samples; |
|
1581 if(bitstream)*bitstream=vf->current_link; |
|
1582 return(samples*2*channels); |
|
1583 }else{ |
|
1584 return(samples); |
|
1585 } |
|
1586 } |