Mercurial > hg > sv-dependency-builds
comparison src/libvorbis-1.3.3/lib/vorbisfile.c @ 1:05aa0afa9217
Bring in flac, ogg, vorbis
author | Chris Cannam |
---|---|
date | Tue, 19 Mar 2013 17:37:49 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:c7265573341e | 1:05aa0afa9217 |
---|---|
1 /******************************************************************** | |
2 * * | |
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |
7 * * | |
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * | |
9 * by the Xiph.Org Foundation http://www.xiph.org/ * | |
10 * * | |
11 ******************************************************************** | |
12 | |
13 function: stdio-based convenience library for opening/seeking/decoding | |
14 last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ | |
15 | |
16 ********************************************************************/ | |
17 | |
18 #include <stdlib.h> | |
19 #include <stdio.h> | |
20 #include <errno.h> | |
21 #include <string.h> | |
22 #include <math.h> | |
23 | |
24 #include "vorbis/codec.h" | |
25 | |
26 /* we don't need or want the static callback symbols here */ | |
27 #define OV_EXCLUDE_STATIC_CALLBACKS | |
28 #include "vorbis/vorbisfile.h" | |
29 | |
30 #include "os.h" | |
31 #include "misc.h" | |
32 | |
33 /* A 'chained bitstream' is a Vorbis bitstream that contains more than | |
34 one logical bitstream arranged end to end (the only form of Ogg | |
35 multiplexing allowed in a Vorbis bitstream; grouping [parallel | |
36 multiplexing] is not allowed in Vorbis) */ | |
37 | |
38 /* A Vorbis file can be played beginning to end (streamed) without | |
39 worrying ahead of time about chaining (see decoder_example.c). If | |
40 we have the whole file, however, and want random access | |
41 (seeking/scrubbing) or desire to know the total length/time of a | |
42 file, we need to account for the possibility of chaining. */ | |
43 | |
44 /* We can handle things a number of ways; we can determine the entire | |
45 bitstream structure right off the bat, or find pieces on demand. | |
46 This example determines and caches structure for the entire | |
47 bitstream, but builds a virtual decoder on the fly when moving | |
48 between links in the chain. */ | |
49 | |
50 /* There are also different ways to implement seeking. Enough | |
51 information exists in an Ogg bitstream to seek to | |
52 sample-granularity positions in the output. Or, one can seek by | |
53 picking some portion of the stream roughly in the desired area if | |
54 we only want coarse navigation through the stream. */ | |
55 | |
56 /************************************************************************* | |
57 * Many, many internal helpers. The intention is not to be confusing; | |
58 * rampant duplication and monolithic function implementation would be | |
59 * harder to understand anyway. The high level functions are last. Begin | |
60 * grokking near the end of the file */ | |
61 | |
62 /* read a little more data from the file/pipe into the ogg_sync framer | |
63 */ | |
64 #define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */ | |
65 #define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */ | |
66 | |
67 static long _get_data(OggVorbis_File *vf){ | |
68 errno=0; | |
69 if(!(vf->callbacks.read_func))return(-1); | |
70 if(vf->datasource){ | |
71 char *buffer=ogg_sync_buffer(&vf->oy,READSIZE); | |
72 long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource); | |
73 if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); | |
74 if(bytes==0 && errno)return(-1); | |
75 return(bytes); | |
76 }else | |
77 return(0); | |
78 } | |
79 | |
80 /* save a tiny smidge of verbosity to make the code more readable */ | |
81 static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ | |
82 if(vf->datasource){ | |
83 if(!(vf->callbacks.seek_func)|| | |
84 (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) | |
85 return OV_EREAD; | |
86 vf->offset=offset; | |
87 ogg_sync_reset(&vf->oy); | |
88 }else{ | |
89 /* shouldn't happen unless someone writes a broken callback */ | |
90 return OV_EFAULT; | |
91 } | |
92 return 0; | |
93 } | |
94 | |
95 /* The read/seek functions track absolute position within the stream */ | |
96 | |
97 /* from the head of the stream, get the next page. boundary specifies | |
98 if the function is allowed to fetch more data from the stream (and | |
99 how much) or only use internally buffered data. | |
100 | |
101 boundary: -1) unbounded search | |
102 0) read no additional data; use cached only | |
103 n) search for a new page beginning for n bytes | |
104 | |
105 return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) | |
106 n) found a page at absolute offset n */ | |
107 | |
108 static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, | |
109 ogg_int64_t boundary){ | |
110 if(boundary>0)boundary+=vf->offset; | |
111 while(1){ | |
112 long more; | |
113 | |
114 if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); | |
115 more=ogg_sync_pageseek(&vf->oy,og); | |
116 | |
117 if(more<0){ | |
118 /* skipped n bytes */ | |
119 vf->offset-=more; | |
120 }else{ | |
121 if(more==0){ | |
122 /* send more paramedics */ | |
123 if(!boundary)return(OV_FALSE); | |
124 { | |
125 long ret=_get_data(vf); | |
126 if(ret==0)return(OV_EOF); | |
127 if(ret<0)return(OV_EREAD); | |
128 } | |
129 }else{ | |
130 /* got a page. Return the offset at the page beginning, | |
131 advance the internal offset past the page end */ | |
132 ogg_int64_t ret=vf->offset; | |
133 vf->offset+=more; | |
134 return(ret); | |
135 | |
136 } | |
137 } | |
138 } | |
139 } | |
140 | |
141 /* find the latest page beginning before the current stream cursor | |
142 position. Much dirtier than the above as Ogg doesn't have any | |
143 backward search linkage. no 'readp' as it will certainly have to | |
144 read. */ | |
145 /* returns offset or OV_EREAD, OV_FAULT */ | |
146 static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){ | |
147 ogg_int64_t begin=vf->offset; | |
148 ogg_int64_t end=begin; | |
149 ogg_int64_t ret; | |
150 ogg_int64_t offset=-1; | |
151 | |
152 while(offset==-1){ | |
153 begin-=CHUNKSIZE; | |
154 if(begin<0) | |
155 begin=0; | |
156 | |
157 ret=_seek_helper(vf,begin); | |
158 if(ret)return(ret); | |
159 | |
160 while(vf->offset<end){ | |
161 memset(og,0,sizeof(*og)); | |
162 ret=_get_next_page(vf,og,end-vf->offset); | |
163 if(ret==OV_EREAD)return(OV_EREAD); | |
164 if(ret<0){ | |
165 break; | |
166 }else{ | |
167 offset=ret; | |
168 } | |
169 } | |
170 } | |
171 | |
172 /* In a fully compliant, non-multiplexed stream, we'll still be | |
173 holding the last page. In multiplexed (or noncompliant streams), | |
174 we will probably have to re-read the last page we saw */ | |
175 if(og->header_len==0){ | |
176 ret=_seek_helper(vf,offset); | |
177 if(ret)return(ret); | |
178 | |
179 ret=_get_next_page(vf,og,CHUNKSIZE); | |
180 if(ret<0) | |
181 /* this shouldn't be possible */ | |
182 return(OV_EFAULT); | |
183 } | |
184 | |
185 return(offset); | |
186 } | |
187 | |
188 static void _add_serialno(ogg_page *og,long **serialno_list, int *n){ | |
189 long s = ogg_page_serialno(og); | |
190 (*n)++; | |
191 | |
192 if(*serialno_list){ | |
193 *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n)); | |
194 }else{ | |
195 *serialno_list = _ogg_malloc(sizeof(**serialno_list)); | |
196 } | |
197 | |
198 (*serialno_list)[(*n)-1] = s; | |
199 } | |
200 | |
201 /* returns nonzero if found */ | |
202 static int _lookup_serialno(long s, long *serialno_list, int n){ | |
203 if(serialno_list){ | |
204 while(n--){ | |
205 if(*serialno_list == s) return 1; | |
206 serialno_list++; | |
207 } | |
208 } | |
209 return 0; | |
210 } | |
211 | |
212 static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){ | |
213 long s = ogg_page_serialno(og); | |
214 return _lookup_serialno(s,serialno_list,n); | |
215 } | |
216 | |
217 /* performs the same search as _get_prev_page, but prefers pages of | |
218 the specified serial number. If a page of the specified serialno is | |
219 spotted during the seek-back-and-read-forward, it will return the | |
220 info of last page of the matching serial number instead of the very | |
221 last page. If no page of the specified serialno is seen, it will | |
222 return the info of last page and alter *serialno. */ | |
223 static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, | |
224 long *serial_list, int serial_n, | |
225 int *serialno, ogg_int64_t *granpos){ | |
226 ogg_page og; | |
227 ogg_int64_t begin=vf->offset; | |
228 ogg_int64_t end=begin; | |
229 ogg_int64_t ret; | |
230 | |
231 ogg_int64_t prefoffset=-1; | |
232 ogg_int64_t offset=-1; | |
233 ogg_int64_t ret_serialno=-1; | |
234 ogg_int64_t ret_gran=-1; | |
235 | |
236 while(offset==-1){ | |
237 begin-=CHUNKSIZE; | |
238 if(begin<0) | |
239 begin=0; | |
240 | |
241 ret=_seek_helper(vf,begin); | |
242 if(ret)return(ret); | |
243 | |
244 while(vf->offset<end){ | |
245 ret=_get_next_page(vf,&og,end-vf->offset); | |
246 if(ret==OV_EREAD)return(OV_EREAD); | |
247 if(ret<0){ | |
248 break; | |
249 }else{ | |
250 ret_serialno=ogg_page_serialno(&og); | |
251 ret_gran=ogg_page_granulepos(&og); | |
252 offset=ret; | |
253 | |
254 if(ret_serialno == *serialno){ | |
255 prefoffset=ret; | |
256 *granpos=ret_gran; | |
257 } | |
258 | |
259 if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){ | |
260 /* we fell off the end of the link, which means we seeked | |
261 back too far and shouldn't have been looking in that link | |
262 to begin with. If we found the preferred serial number, | |
263 forget that we saw it. */ | |
264 prefoffset=-1; | |
265 } | |
266 } | |
267 } | |
268 } | |
269 | |
270 /* we're not interested in the page... just the serialno and granpos. */ | |
271 if(prefoffset>=0)return(prefoffset); | |
272 | |
273 *serialno = ret_serialno; | |
274 *granpos = ret_gran; | |
275 return(offset); | |
276 | |
277 } | |
278 | |
279 /* uses the local ogg_stream storage in vf; this is important for | |
280 non-streaming input sources */ | |
281 static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, | |
282 long **serialno_list, int *serialno_n, | |
283 ogg_page *og_ptr){ | |
284 ogg_page og; | |
285 ogg_packet op; | |
286 int i,ret; | |
287 int allbos=0; | |
288 | |
289 if(!og_ptr){ | |
290 ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); | |
291 if(llret==OV_EREAD)return(OV_EREAD); | |
292 if(llret<0)return(OV_ENOTVORBIS); | |
293 og_ptr=&og; | |
294 } | |
295 | |
296 vorbis_info_init(vi); | |
297 vorbis_comment_init(vc); | |
298 vf->ready_state=OPENED; | |
299 | |
300 /* extract the serialnos of all BOS pages + the first set of vorbis | |
301 headers we see in the link */ | |
302 | |
303 while(ogg_page_bos(og_ptr)){ | |
304 if(serialno_list){ | |
305 if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){ | |
306 /* a dupe serialnumber in an initial header packet set == invalid stream */ | |
307 if(*serialno_list)_ogg_free(*serialno_list); | |
308 *serialno_list=0; | |
309 *serialno_n=0; | |
310 ret=OV_EBADHEADER; | |
311 goto bail_header; | |
312 } | |
313 | |
314 _add_serialno(og_ptr,serialno_list,serialno_n); | |
315 } | |
316 | |
317 if(vf->ready_state<STREAMSET){ | |
318 /* we don't have a vorbis stream in this link yet, so begin | |
319 prospective stream setup. We need a stream to get packets */ | |
320 ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr)); | |
321 ogg_stream_pagein(&vf->os,og_ptr); | |
322 | |
323 if(ogg_stream_packetout(&vf->os,&op) > 0 && | |
324 vorbis_synthesis_idheader(&op)){ | |
325 /* vorbis header; continue setup */ | |
326 vf->ready_state=STREAMSET; | |
327 if((ret=vorbis_synthesis_headerin(vi,vc,&op))){ | |
328 ret=OV_EBADHEADER; | |
329 goto bail_header; | |
330 } | |
331 } | |
332 } | |
333 | |
334 /* get next page */ | |
335 { | |
336 ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE); | |
337 if(llret==OV_EREAD){ | |
338 ret=OV_EREAD; | |
339 goto bail_header; | |
340 } | |
341 if(llret<0){ | |
342 ret=OV_ENOTVORBIS; | |
343 goto bail_header; | |
344 } | |
345 | |
346 /* if this page also belongs to our vorbis stream, submit it and break */ | |
347 if(vf->ready_state==STREAMSET && | |
348 vf->os.serialno == ogg_page_serialno(og_ptr)){ | |
349 ogg_stream_pagein(&vf->os,og_ptr); | |
350 break; | |
351 } | |
352 } | |
353 } | |
354 | |
355 if(vf->ready_state!=STREAMSET){ | |
356 ret = OV_ENOTVORBIS; | |
357 goto bail_header; | |
358 } | |
359 | |
360 while(1){ | |
361 | |
362 i=0; | |
363 while(i<2){ /* get a page loop */ | |
364 | |
365 while(i<2){ /* get a packet loop */ | |
366 | |
367 int result=ogg_stream_packetout(&vf->os,&op); | |
368 if(result==0)break; | |
369 if(result==-1){ | |
370 ret=OV_EBADHEADER; | |
371 goto bail_header; | |
372 } | |
373 | |
374 if((ret=vorbis_synthesis_headerin(vi,vc,&op))) | |
375 goto bail_header; | |
376 | |
377 i++; | |
378 } | |
379 | |
380 while(i<2){ | |
381 if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ | |
382 ret=OV_EBADHEADER; | |
383 goto bail_header; | |
384 } | |
385 | |
386 /* if this page belongs to the correct stream, go parse it */ | |
387 if(vf->os.serialno == ogg_page_serialno(og_ptr)){ | |
388 ogg_stream_pagein(&vf->os,og_ptr); | |
389 break; | |
390 } | |
391 | |
392 /* if we never see the final vorbis headers before the link | |
393 ends, abort */ | |
394 if(ogg_page_bos(og_ptr)){ | |
395 if(allbos){ | |
396 ret = OV_EBADHEADER; | |
397 goto bail_header; | |
398 }else | |
399 allbos=1; | |
400 } | |
401 | |
402 /* otherwise, keep looking */ | |
403 } | |
404 } | |
405 | |
406 return 0; | |
407 } | |
408 | |
409 bail_header: | |
410 vorbis_info_clear(vi); | |
411 vorbis_comment_clear(vc); | |
412 vf->ready_state=OPENED; | |
413 | |
414 return ret; | |
415 } | |
416 | |
417 /* Starting from current cursor position, get initial PCM offset of | |
418 next page. Consumes the page in the process without decoding | |
419 audio, however this is only called during stream parsing upon | |
420 seekable open. */ | |
421 static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ | |
422 ogg_page og; | |
423 ogg_int64_t accumulated=0; | |
424 long lastblock=-1; | |
425 int result; | |
426 int serialno = vf->os.serialno; | |
427 | |
428 while(1){ | |
429 ogg_packet op; | |
430 if(_get_next_page(vf,&og,-1)<0) | |
431 break; /* should not be possible unless the file is truncated/mangled */ | |
432 | |
433 if(ogg_page_bos(&og)) break; | |
434 if(ogg_page_serialno(&og)!=serialno) continue; | |
435 | |
436 /* count blocksizes of all frames in the page */ | |
437 ogg_stream_pagein(&vf->os,&og); | |
438 while((result=ogg_stream_packetout(&vf->os,&op))){ | |
439 if(result>0){ /* ignore holes */ | |
440 long thisblock=vorbis_packet_blocksize(vi,&op); | |
441 if(lastblock!=-1) | |
442 accumulated+=(lastblock+thisblock)>>2; | |
443 lastblock=thisblock; | |
444 } | |
445 } | |
446 | |
447 if(ogg_page_granulepos(&og)!=-1){ | |
448 /* pcm offset of last packet on the first audio page */ | |
449 accumulated= ogg_page_granulepos(&og)-accumulated; | |
450 break; | |
451 } | |
452 } | |
453 | |
454 /* less than zero? Either a corrupt file or a stream with samples | |
455 trimmed off the beginning, a normal occurrence; in both cases set | |
456 the offset to zero */ | |
457 if(accumulated<0)accumulated=0; | |
458 | |
459 return accumulated; | |
460 } | |
461 | |
462 /* finds each bitstream link one at a time using a bisection search | |
463 (has to begin by knowing the offset of the lb's initial page). | |
464 Recurses for each link so it can alloc the link storage after | |
465 finding them all, then unroll and fill the cache at the same time */ | |
466 static int _bisect_forward_serialno(OggVorbis_File *vf, | |
467 ogg_int64_t begin, | |
468 ogg_int64_t searched, | |
469 ogg_int64_t end, | |
470 ogg_int64_t endgran, | |
471 int endserial, | |
472 long *currentno_list, | |
473 int currentnos, | |
474 long m){ | |
475 ogg_int64_t pcmoffset; | |
476 ogg_int64_t dataoffset=searched; | |
477 ogg_int64_t endsearched=end; | |
478 ogg_int64_t next=end; | |
479 ogg_int64_t searchgran=-1; | |
480 ogg_page og; | |
481 ogg_int64_t ret,last; | |
482 int serialno = vf->os.serialno; | |
483 | |
484 /* invariants: | |
485 we have the headers and serialnos for the link beginning at 'begin' | |
486 we have the offset and granpos of the last page in the file (potentially | |
487 not a page we care about) | |
488 */ | |
489 | |
490 /* Is the last page in our list of current serialnumbers? */ | |
491 if(_lookup_serialno(endserial,currentno_list,currentnos)){ | |
492 | |
493 /* last page is in the starting serialno list, so we've bisected | |
494 down to (or just started with) a single link. Now we need to | |
495 find the last vorbis page belonging to the first vorbis stream | |
496 for this link. */ | |
497 | |
498 while(endserial != serialno){ | |
499 endserial = serialno; | |
500 vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&endserial,&endgran); | |
501 } | |
502 | |
503 vf->links=m+1; | |
504 if(vf->offsets)_ogg_free(vf->offsets); | |
505 if(vf->serialnos)_ogg_free(vf->serialnos); | |
506 if(vf->dataoffsets)_ogg_free(vf->dataoffsets); | |
507 | |
508 vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets)); | |
509 vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi)); | |
510 vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc)); | |
511 vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos)); | |
512 vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); | |
513 vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); | |
514 | |
515 vf->offsets[m+1]=end; | |
516 vf->offsets[m]=begin; | |
517 vf->pcmlengths[m*2+1]=(endgran<0?0:endgran); | |
518 | |
519 }else{ | |
520 | |
521 long *next_serialno_list=NULL; | |
522 int next_serialnos=0; | |
523 vorbis_info vi; | |
524 vorbis_comment vc; | |
525 | |
526 /* the below guards against garbage seperating the last and | |
527 first pages of two links. */ | |
528 while(searched<endsearched){ | |
529 ogg_int64_t bisect; | |
530 | |
531 if(endsearched-searched<CHUNKSIZE){ | |
532 bisect=searched; | |
533 }else{ | |
534 bisect=(searched+endsearched)/2; | |
535 } | |
536 | |
537 if(bisect != vf->offset){ | |
538 ret=_seek_helper(vf,bisect); | |
539 if(ret)return(ret); | |
540 } | |
541 | |
542 last=_get_next_page(vf,&og,-1); | |
543 if(last==OV_EREAD)return(OV_EREAD); | |
544 if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){ | |
545 endsearched=bisect; | |
546 if(last>=0)next=last; | |
547 }else{ | |
548 searched=vf->offset; | |
549 } | |
550 } | |
551 | |
552 /* Bisection point found */ | |
553 | |
554 /* for the time being, fetch end PCM offset the simple way */ | |
555 { | |
556 int testserial = serialno+1; | |
557 vf->offset = next; | |
558 while(testserial != serialno){ | |
559 testserial = serialno; | |
560 vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&testserial,&searchgran); | |
561 } | |
562 } | |
563 | |
564 if(vf->offset!=next){ | |
565 ret=_seek_helper(vf,next); | |
566 if(ret)return(ret); | |
567 } | |
568 | |
569 ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL); | |
570 if(ret)return(ret); | |
571 serialno = vf->os.serialno; | |
572 dataoffset = vf->offset; | |
573 | |
574 /* this will consume a page, however the next bistection always | |
575 starts with a raw seek */ | |
576 pcmoffset = _initial_pcmoffset(vf,&vi); | |
577 | |
578 ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial, | |
579 next_serialno_list,next_serialnos,m+1); | |
580 if(ret)return(ret); | |
581 | |
582 if(next_serialno_list)_ogg_free(next_serialno_list); | |
583 | |
584 vf->offsets[m+1]=next; | |
585 vf->serialnos[m+1]=serialno; | |
586 vf->dataoffsets[m+1]=dataoffset; | |
587 | |
588 vf->vi[m+1]=vi; | |
589 vf->vc[m+1]=vc; | |
590 | |
591 vf->pcmlengths[m*2+1]=searchgran; | |
592 vf->pcmlengths[m*2+2]=pcmoffset; | |
593 vf->pcmlengths[m*2+3]-=pcmoffset; | |
594 if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0; | |
595 } | |
596 return(0); | |
597 } | |
598 | |
599 static int _make_decode_ready(OggVorbis_File *vf){ | |
600 if(vf->ready_state>STREAMSET)return 0; | |
601 if(vf->ready_state<STREAMSET)return OV_EFAULT; | |
602 if(vf->seekable){ | |
603 if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link)) | |
604 return OV_EBADLINK; | |
605 }else{ | |
606 if(vorbis_synthesis_init(&vf->vd,vf->vi)) | |
607 return OV_EBADLINK; | |
608 } | |
609 vorbis_block_init(&vf->vd,&vf->vb); | |
610 vf->ready_state=INITSET; | |
611 vf->bittrack=0.f; | |
612 vf->samptrack=0.f; | |
613 return 0; | |
614 } | |
615 | |
616 static int _open_seekable2(OggVorbis_File *vf){ | |
617 ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1; | |
618 int endserial=vf->os.serialno; | |
619 int serialno=vf->os.serialno; | |
620 | |
621 /* we're partially open and have a first link header state in | |
622 storage in vf */ | |
623 | |
624 /* fetch initial PCM offset */ | |
625 ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi); | |
626 | |
627 /* we can seek, so set out learning all about this file */ | |
628 if(vf->callbacks.seek_func && vf->callbacks.tell_func){ | |
629 (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); | |
630 vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); | |
631 }else{ | |
632 vf->offset=vf->end=-1; | |
633 } | |
634 | |
635 /* If seek_func is implemented, tell_func must also be implemented */ | |
636 if(vf->end==-1) return(OV_EINVAL); | |
637 | |
638 /* Get the offset of the last page of the physical bitstream, or, if | |
639 we're lucky the last vorbis page of this link as most OggVorbis | |
640 files will contain a single logical bitstream */ | |
641 end=_get_prev_page_serial(vf,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran); | |
642 if(end<0)return(end); | |
643 | |
644 /* now determine bitstream structure recursively */ | |
645 if(_bisect_forward_serialno(vf,0,dataoffset,vf->offset,endgran,endserial, | |
646 vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD); | |
647 | |
648 vf->offsets[0]=0; | |
649 vf->serialnos[0]=serialno; | |
650 vf->dataoffsets[0]=dataoffset; | |
651 vf->pcmlengths[0]=pcmoffset; | |
652 vf->pcmlengths[1]-=pcmoffset; | |
653 if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0; | |
654 | |
655 return(ov_raw_seek(vf,dataoffset)); | |
656 } | |
657 | |
658 /* clear out the current logical bitstream decoder */ | |
659 static void _decode_clear(OggVorbis_File *vf){ | |
660 vorbis_dsp_clear(&vf->vd); | |
661 vorbis_block_clear(&vf->vb); | |
662 vf->ready_state=OPENED; | |
663 } | |
664 | |
665 /* fetch and process a packet. Handles the case where we're at a | |
666 bitstream boundary and dumps the decoding machine. If the decoding | |
667 machine is unloaded, it loads it. It also keeps pcm_offset up to | |
668 date (seek and read both use this. seek uses a special hack with | |
669 readp). | |
670 | |
671 return: <0) error, OV_HOLE (lost packet) or OV_EOF | |
672 0) need more data (only if readp==0) | |
673 1) got a packet | |
674 */ | |
675 | |
676 static int _fetch_and_process_packet(OggVorbis_File *vf, | |
677 ogg_packet *op_in, | |
678 int readp, | |
679 int spanp){ | |
680 ogg_page og; | |
681 | |
682 /* handle one packet. Try to fetch it from current stream state */ | |
683 /* extract packets from page */ | |
684 while(1){ | |
685 | |
686 if(vf->ready_state==STREAMSET){ | |
687 int ret=_make_decode_ready(vf); | |
688 if(ret<0)return ret; | |
689 } | |
690 | |
691 /* process a packet if we can. */ | |
692 | |
693 if(vf->ready_state==INITSET){ | |
694 int hs=vorbis_synthesis_halfrate_p(vf->vi); | |
695 | |
696 while(1) { | |
697 ogg_packet op; | |
698 ogg_packet *op_ptr=(op_in?op_in:&op); | |
699 int result=ogg_stream_packetout(&vf->os,op_ptr); | |
700 ogg_int64_t granulepos; | |
701 | |
702 op_in=NULL; | |
703 if(result==-1)return(OV_HOLE); /* hole in the data. */ | |
704 if(result>0){ | |
705 /* got a packet. process it */ | |
706 granulepos=op_ptr->granulepos; | |
707 if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy | |
708 header handling. The | |
709 header packets aren't | |
710 audio, so if/when we | |
711 submit them, | |
712 vorbis_synthesis will | |
713 reject them */ | |
714 | |
715 /* suck in the synthesis data and track bitrate */ | |
716 { | |
717 int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); | |
718 /* for proper use of libvorbis within libvorbisfile, | |
719 oldsamples will always be zero. */ | |
720 if(oldsamples)return(OV_EFAULT); | |
721 | |
722 vorbis_synthesis_blockin(&vf->vd,&vf->vb); | |
723 vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs); | |
724 vf->bittrack+=op_ptr->bytes*8; | |
725 } | |
726 | |
727 /* update the pcm offset. */ | |
728 if(granulepos!=-1 && !op_ptr->e_o_s){ | |
729 int link=(vf->seekable?vf->current_link:0); | |
730 int i,samples; | |
731 | |
732 /* this packet has a pcm_offset on it (the last packet | |
733 completed on a page carries the offset) After processing | |
734 (above), we know the pcm position of the *last* sample | |
735 ready to be returned. Find the offset of the *first* | |
736 | |
737 As an aside, this trick is inaccurate if we begin | |
738 reading anew right at the last page; the end-of-stream | |
739 granulepos declares the last frame in the stream, and the | |
740 last packet of the last page may be a partial frame. | |
741 So, we need a previous granulepos from an in-sequence page | |
742 to have a reference point. Thus the !op_ptr->e_o_s clause | |
743 above */ | |
744 | |
745 if(vf->seekable && link>0) | |
746 granulepos-=vf->pcmlengths[link*2]; | |
747 if(granulepos<0)granulepos=0; /* actually, this | |
748 shouldn't be possible | |
749 here unless the stream | |
750 is very broken */ | |
751 | |
752 samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs); | |
753 | |
754 granulepos-=samples; | |
755 for(i=0;i<link;i++) | |
756 granulepos+=vf->pcmlengths[i*2+1]; | |
757 vf->pcm_offset=granulepos; | |
758 } | |
759 return(1); | |
760 } | |
761 } | |
762 else | |
763 break; | |
764 } | |
765 } | |
766 | |
767 if(vf->ready_state>=OPENED){ | |
768 ogg_int64_t ret; | |
769 | |
770 while(1){ | |
771 /* the loop is not strictly necessary, but there's no sense in | |
772 doing the extra checks of the larger loop for the common | |
773 case in a multiplexed bistream where the page is simply | |
774 part of a different logical bitstream; keep reading until | |
775 we get one with the correct serialno */ | |
776 | |
777 if(!readp)return(0); | |
778 if((ret=_get_next_page(vf,&og,-1))<0){ | |
779 return(OV_EOF); /* eof. leave unitialized */ | |
780 } | |
781 | |
782 /* bitrate tracking; add the header's bytes here, the body bytes | |
783 are done by packet above */ | |
784 vf->bittrack+=og.header_len*8; | |
785 | |
786 if(vf->ready_state==INITSET){ | |
787 if(vf->current_serialno!=ogg_page_serialno(&og)){ | |
788 | |
789 /* two possibilities: | |
790 1) our decoding just traversed a bitstream boundary | |
791 2) another stream is multiplexed into this logical section */ | |
792 | |
793 if(ogg_page_bos(&og)){ | |
794 /* boundary case */ | |
795 if(!spanp) | |
796 return(OV_EOF); | |
797 | |
798 _decode_clear(vf); | |
799 | |
800 if(!vf->seekable){ | |
801 vorbis_info_clear(vf->vi); | |
802 vorbis_comment_clear(vf->vc); | |
803 } | |
804 break; | |
805 | |
806 }else | |
807 continue; /* possibility #2 */ | |
808 } | |
809 } | |
810 | |
811 break; | |
812 } | |
813 } | |
814 | |
815 /* Do we need to load a new machine before submitting the page? */ | |
816 /* This is different in the seekable and non-seekable cases. | |
817 | |
818 In the seekable case, we already have all the header | |
819 information loaded and cached; we just initialize the machine | |
820 with it and continue on our merry way. | |
821 | |
822 In the non-seekable (streaming) case, we'll only be at a | |
823 boundary if we just left the previous logical bitstream and | |
824 we're now nominally at the header of the next bitstream | |
825 */ | |
826 | |
827 if(vf->ready_state!=INITSET){ | |
828 int link; | |
829 | |
830 if(vf->ready_state<STREAMSET){ | |
831 if(vf->seekable){ | |
832 long serialno = ogg_page_serialno(&og); | |
833 | |
834 /* match the serialno to bitstream section. We use this rather than | |
835 offset positions to avoid problems near logical bitstream | |
836 boundaries */ | |
837 | |
838 for(link=0;link<vf->links;link++) | |
839 if(vf->serialnos[link]==serialno)break; | |
840 | |
841 if(link==vf->links) continue; /* not the desired Vorbis | |
842 bitstream section; keep | |
843 trying */ | |
844 | |
845 vf->current_serialno=serialno; | |
846 vf->current_link=link; | |
847 | |
848 ogg_stream_reset_serialno(&vf->os,vf->current_serialno); | |
849 vf->ready_state=STREAMSET; | |
850 | |
851 }else{ | |
852 /* we're streaming */ | |
853 /* fetch the three header packets, build the info struct */ | |
854 | |
855 int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og); | |
856 if(ret)return(ret); | |
857 vf->current_serialno=vf->os.serialno; | |
858 vf->current_link++; | |
859 link=0; | |
860 } | |
861 } | |
862 } | |
863 | |
864 /* the buffered page is the data we want, and we're ready for it; | |
865 add it to the stream state */ | |
866 ogg_stream_pagein(&vf->os,&og); | |
867 | |
868 } | |
869 } | |
870 | |
871 /* if, eg, 64 bit stdio is configured by default, this will build with | |
872 fseek64 */ | |
873 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ | |
874 if(f==NULL)return(-1); | |
875 return fseek(f,off,whence); | |
876 } | |
877 | |
878 static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, | |
879 long ibytes, ov_callbacks callbacks){ | |
880 int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); | |
881 long *serialno_list=NULL; | |
882 int serialno_list_size=0; | |
883 int ret; | |
884 | |
885 memset(vf,0,sizeof(*vf)); | |
886 vf->datasource=f; | |
887 vf->callbacks = callbacks; | |
888 | |
889 /* init the framing state */ | |
890 ogg_sync_init(&vf->oy); | |
891 | |
892 /* perhaps some data was previously read into a buffer for testing | |
893 against other stream types. Allow initialization from this | |
894 previously read data (especially as we may be reading from a | |
895 non-seekable stream) */ | |
896 if(initial){ | |
897 char *buffer=ogg_sync_buffer(&vf->oy,ibytes); | |
898 memcpy(buffer,initial,ibytes); | |
899 ogg_sync_wrote(&vf->oy,ibytes); | |
900 } | |
901 | |
902 /* can we seek? Stevens suggests the seek test was portable */ | |
903 if(offsettest!=-1)vf->seekable=1; | |
904 | |
905 /* No seeking yet; Set up a 'single' (current) logical bitstream | |
906 entry for partial open */ | |
907 vf->links=1; | |
908 vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); | |
909 vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); | |
910 ogg_stream_init(&vf->os,-1); /* fill in the serialno later */ | |
911 | |
912 /* Fetch all BOS pages, store the vorbis header and all seen serial | |
913 numbers, load subsequent vorbis setup headers */ | |
914 if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){ | |
915 vf->datasource=NULL; | |
916 ov_clear(vf); | |
917 }else{ | |
918 /* serial number list for first link needs to be held somewhere | |
919 for second stage of seekable stream open; this saves having to | |
920 seek/reread first link's serialnumber data then. */ | |
921 vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos)); | |
922 vf->serialnos[0]=vf->current_serialno=vf->os.serialno; | |
923 vf->serialnos[1]=serialno_list_size; | |
924 memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos)); | |
925 | |
926 vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets)); | |
927 vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets)); | |
928 vf->offsets[0]=0; | |
929 vf->dataoffsets[0]=vf->offset; | |
930 | |
931 vf->ready_state=PARTOPEN; | |
932 } | |
933 if(serialno_list)_ogg_free(serialno_list); | |
934 return(ret); | |
935 } | |
936 | |
937 static int _ov_open2(OggVorbis_File *vf){ | |
938 if(vf->ready_state != PARTOPEN) return OV_EINVAL; | |
939 vf->ready_state=OPENED; | |
940 if(vf->seekable){ | |
941 int ret=_open_seekable2(vf); | |
942 if(ret){ | |
943 vf->datasource=NULL; | |
944 ov_clear(vf); | |
945 } | |
946 return(ret); | |
947 }else | |
948 vf->ready_state=STREAMSET; | |
949 | |
950 return 0; | |
951 } | |
952 | |
953 | |
954 /* clear out the OggVorbis_File struct */ | |
955 int ov_clear(OggVorbis_File *vf){ | |
956 if(vf){ | |
957 vorbis_block_clear(&vf->vb); | |
958 vorbis_dsp_clear(&vf->vd); | |
959 ogg_stream_clear(&vf->os); | |
960 | |
961 if(vf->vi && vf->links){ | |
962 int i; | |
963 for(i=0;i<vf->links;i++){ | |
964 vorbis_info_clear(vf->vi+i); | |
965 vorbis_comment_clear(vf->vc+i); | |
966 } | |
967 _ogg_free(vf->vi); | |
968 _ogg_free(vf->vc); | |
969 } | |
970 if(vf->dataoffsets)_ogg_free(vf->dataoffsets); | |
971 if(vf->pcmlengths)_ogg_free(vf->pcmlengths); | |
972 if(vf->serialnos)_ogg_free(vf->serialnos); | |
973 if(vf->offsets)_ogg_free(vf->offsets); | |
974 ogg_sync_clear(&vf->oy); | |
975 if(vf->datasource && vf->callbacks.close_func) | |
976 (vf->callbacks.close_func)(vf->datasource); | |
977 memset(vf,0,sizeof(*vf)); | |
978 } | |
979 #ifdef DEBUG_LEAKS | |
980 _VDBG_dump(); | |
981 #endif | |
982 return(0); | |
983 } | |
984 | |
985 /* inspects the OggVorbis file and finds/documents all the logical | |
986 bitstreams contained in it. Tries to be tolerant of logical | |
987 bitstream sections that are truncated/woogie. | |
988 | |
989 return: -1) error | |
990 0) OK | |
991 */ | |
992 | |
993 int ov_open_callbacks(void *f,OggVorbis_File *vf, | |
994 const char *initial,long ibytes,ov_callbacks callbacks){ | |
995 int ret=_ov_open1(f,vf,initial,ibytes,callbacks); | |
996 if(ret)return ret; | |
997 return _ov_open2(vf); | |
998 } | |
999 | |
1000 int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ | |
1001 ov_callbacks callbacks = { | |
1002 (size_t (*)(void *, size_t, size_t, void *)) fread, | |
1003 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, | |
1004 (int (*)(void *)) fclose, | |
1005 (long (*)(void *)) ftell | |
1006 }; | |
1007 | |
1008 return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); | |
1009 } | |
1010 | |
1011 int ov_fopen(const char *path,OggVorbis_File *vf){ | |
1012 int ret; | |
1013 FILE *f = fopen(path,"rb"); | |
1014 if(!f) return -1; | |
1015 | |
1016 ret = ov_open(f,vf,NULL,0); | |
1017 if(ret) fclose(f); | |
1018 return ret; | |
1019 } | |
1020 | |
1021 | |
1022 /* cheap hack for game usage where downsampling is desirable; there's | |
1023 no need for SRC as we can just do it cheaply in libvorbis. */ | |
1024 | |
1025 int ov_halfrate(OggVorbis_File *vf,int flag){ | |
1026 int i; | |
1027 if(vf->vi==NULL)return OV_EINVAL; | |
1028 if(vf->ready_state>STREAMSET){ | |
1029 /* clear out stream state; dumping the decode machine is needed to | |
1030 reinit the MDCT lookups. */ | |
1031 vorbis_dsp_clear(&vf->vd); | |
1032 vorbis_block_clear(&vf->vb); | |
1033 vf->ready_state=STREAMSET; | |
1034 if(vf->pcm_offset>=0){ | |
1035 ogg_int64_t pos=vf->pcm_offset; | |
1036 vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */ | |
1037 ov_pcm_seek(vf,pos); | |
1038 } | |
1039 } | |
1040 | |
1041 for(i=0;i<vf->links;i++){ | |
1042 if(vorbis_synthesis_halfrate(vf->vi+i,flag)){ | |
1043 if(flag) ov_halfrate(vf,0); | |
1044 return OV_EINVAL; | |
1045 } | |
1046 } | |
1047 return 0; | |
1048 } | |
1049 | |
1050 int ov_halfrate_p(OggVorbis_File *vf){ | |
1051 if(vf->vi==NULL)return OV_EINVAL; | |
1052 return vorbis_synthesis_halfrate_p(vf->vi); | |
1053 } | |
1054 | |
1055 /* Only partially open the vorbis file; test for Vorbisness, and load | |
1056 the headers for the first chain. Do not seek (although test for | |
1057 seekability). Use ov_test_open to finish opening the file, else | |
1058 ov_clear to close/free it. Same return codes as open. */ | |
1059 | |
1060 int ov_test_callbacks(void *f,OggVorbis_File *vf, | |
1061 const char *initial,long ibytes,ov_callbacks callbacks) | |
1062 { | |
1063 return _ov_open1(f,vf,initial,ibytes,callbacks); | |
1064 } | |
1065 | |
1066 int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ | |
1067 ov_callbacks callbacks = { | |
1068 (size_t (*)(void *, size_t, size_t, void *)) fread, | |
1069 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, | |
1070 (int (*)(void *)) fclose, | |
1071 (long (*)(void *)) ftell | |
1072 }; | |
1073 | |
1074 return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); | |
1075 } | |
1076 | |
1077 int ov_test_open(OggVorbis_File *vf){ | |
1078 if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); | |
1079 return _ov_open2(vf); | |
1080 } | |
1081 | |
1082 /* How many logical bitstreams in this physical bitstream? */ | |
1083 long ov_streams(OggVorbis_File *vf){ | |
1084 return vf->links; | |
1085 } | |
1086 | |
1087 /* Is the FILE * associated with vf seekable? */ | |
1088 long ov_seekable(OggVorbis_File *vf){ | |
1089 return vf->seekable; | |
1090 } | |
1091 | |
1092 /* returns the bitrate for a given logical bitstream or the entire | |
1093 physical bitstream. If the file is open for random access, it will | |
1094 find the *actual* average bitrate. If the file is streaming, it | |
1095 returns the nominal bitrate (if set) else the average of the | |
1096 upper/lower bounds (if set) else -1 (unset). | |
1097 | |
1098 If you want the actual bitrate field settings, get them from the | |
1099 vorbis_info structs */ | |
1100 | |
1101 long ov_bitrate(OggVorbis_File *vf,int i){ | |
1102 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1103 if(i>=vf->links)return(OV_EINVAL); | |
1104 if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); | |
1105 if(i<0){ | |
1106 ogg_int64_t bits=0; | |
1107 int i; | |
1108 float br; | |
1109 for(i=0;i<vf->links;i++) | |
1110 bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; | |
1111 /* This once read: return(rint(bits/ov_time_total(vf,-1))); | |
1112 * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, | |
1113 * so this is slightly transformed to make it work. | |
1114 */ | |
1115 br = bits/ov_time_total(vf,-1); | |
1116 return(rint(br)); | |
1117 }else{ | |
1118 if(vf->seekable){ | |
1119 /* return the actual bitrate */ | |
1120 return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i))); | |
1121 }else{ | |
1122 /* return nominal if set */ | |
1123 if(vf->vi[i].bitrate_nominal>0){ | |
1124 return vf->vi[i].bitrate_nominal; | |
1125 }else{ | |
1126 if(vf->vi[i].bitrate_upper>0){ | |
1127 if(vf->vi[i].bitrate_lower>0){ | |
1128 return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; | |
1129 }else{ | |
1130 return vf->vi[i].bitrate_upper; | |
1131 } | |
1132 } | |
1133 return(OV_FALSE); | |
1134 } | |
1135 } | |
1136 } | |
1137 } | |
1138 | |
1139 /* returns the actual bitrate since last call. returns -1 if no | |
1140 additional data to offer since last call (or at beginning of stream), | |
1141 EINVAL if stream is only partially open | |
1142 */ | |
1143 long ov_bitrate_instant(OggVorbis_File *vf){ | |
1144 int link=(vf->seekable?vf->current_link:0); | |
1145 long ret; | |
1146 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1147 if(vf->samptrack==0)return(OV_FALSE); | |
1148 ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5; | |
1149 vf->bittrack=0.f; | |
1150 vf->samptrack=0.f; | |
1151 return(ret); | |
1152 } | |
1153 | |
1154 /* Guess */ | |
1155 long ov_serialnumber(OggVorbis_File *vf,int i){ | |
1156 if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); | |
1157 if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); | |
1158 if(i<0){ | |
1159 return(vf->current_serialno); | |
1160 }else{ | |
1161 return(vf->serialnos[i]); | |
1162 } | |
1163 } | |
1164 | |
1165 /* returns: total raw (compressed) length of content if i==-1 | |
1166 raw (compressed) length of that logical bitstream for i==0 to n | |
1167 OV_EINVAL if the stream is not seekable (we can't know the length) | |
1168 or if stream is only partially open | |
1169 */ | |
1170 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ | |
1171 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1172 if(!vf->seekable || i>=vf->links)return(OV_EINVAL); | |
1173 if(i<0){ | |
1174 ogg_int64_t acc=0; | |
1175 int i; | |
1176 for(i=0;i<vf->links;i++) | |
1177 acc+=ov_raw_total(vf,i); | |
1178 return(acc); | |
1179 }else{ | |
1180 return(vf->offsets[i+1]-vf->offsets[i]); | |
1181 } | |
1182 } | |
1183 | |
1184 /* returns: total PCM length (samples) of content if i==-1 PCM length | |
1185 (samples) of that logical bitstream for i==0 to n | |
1186 OV_EINVAL if the stream is not seekable (we can't know the | |
1187 length) or only partially open | |
1188 */ | |
1189 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ | |
1190 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1191 if(!vf->seekable || i>=vf->links)return(OV_EINVAL); | |
1192 if(i<0){ | |
1193 ogg_int64_t acc=0; | |
1194 int i; | |
1195 for(i=0;i<vf->links;i++) | |
1196 acc+=ov_pcm_total(vf,i); | |
1197 return(acc); | |
1198 }else{ | |
1199 return(vf->pcmlengths[i*2+1]); | |
1200 } | |
1201 } | |
1202 | |
1203 /* returns: total seconds of content if i==-1 | |
1204 seconds in that logical bitstream for i==0 to n | |
1205 OV_EINVAL if the stream is not seekable (we can't know the | |
1206 length) or only partially open | |
1207 */ | |
1208 double ov_time_total(OggVorbis_File *vf,int i){ | |
1209 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1210 if(!vf->seekable || i>=vf->links)return(OV_EINVAL); | |
1211 if(i<0){ | |
1212 double acc=0; | |
1213 int i; | |
1214 for(i=0;i<vf->links;i++) | |
1215 acc+=ov_time_total(vf,i); | |
1216 return(acc); | |
1217 }else{ | |
1218 return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate); | |
1219 } | |
1220 } | |
1221 | |
1222 /* seek to an offset relative to the *compressed* data. This also | |
1223 scans packets to update the PCM cursor. It will cross a logical | |
1224 bitstream boundary, but only if it can't get any packets out of the | |
1225 tail of the bitstream we seek to (so no surprises). | |
1226 | |
1227 returns zero on success, nonzero on failure */ | |
1228 | |
1229 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ | |
1230 ogg_stream_state work_os; | |
1231 int ret; | |
1232 | |
1233 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1234 if(!vf->seekable) | |
1235 return(OV_ENOSEEK); /* don't dump machine if we can't seek */ | |
1236 | |
1237 if(pos<0 || pos>vf->end)return(OV_EINVAL); | |
1238 | |
1239 /* is the seek position outside our current link [if any]? */ | |
1240 if(vf->ready_state>=STREAMSET){ | |
1241 if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1]) | |
1242 _decode_clear(vf); /* clear out stream state */ | |
1243 } | |
1244 | |
1245 /* don't yet clear out decoding machine (if it's initialized), in | |
1246 the case we're in the same link. Restart the decode lapping, and | |
1247 let _fetch_and_process_packet deal with a potential bitstream | |
1248 boundary */ | |
1249 vf->pcm_offset=-1; | |
1250 ogg_stream_reset_serialno(&vf->os, | |
1251 vf->current_serialno); /* must set serialno */ | |
1252 vorbis_synthesis_restart(&vf->vd); | |
1253 | |
1254 ret=_seek_helper(vf,pos); | |
1255 if(ret)goto seek_error; | |
1256 | |
1257 /* we need to make sure the pcm_offset is set, but we don't want to | |
1258 advance the raw cursor past good packets just to get to the first | |
1259 with a granulepos. That's not equivalent behavior to beginning | |
1260 decoding as immediately after the seek position as possible. | |
1261 | |
1262 So, a hack. We use two stream states; a local scratch state and | |
1263 the shared vf->os stream state. We use the local state to | |
1264 scan, and the shared state as a buffer for later decode. | |
1265 | |
1266 Unfortuantely, on the last page we still advance to last packet | |
1267 because the granulepos on the last page is not necessarily on a | |
1268 packet boundary, and we need to make sure the granpos is | |
1269 correct. | |
1270 */ | |
1271 | |
1272 { | |
1273 ogg_page og; | |
1274 ogg_packet op; | |
1275 int lastblock=0; | |
1276 int accblock=0; | |
1277 int thisblock=0; | |
1278 int lastflag=0; | |
1279 int firstflag=0; | |
1280 ogg_int64_t pagepos=-1; | |
1281 | |
1282 ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */ | |
1283 ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE | |
1284 return from not necessarily | |
1285 starting from the beginning */ | |
1286 | |
1287 while(1){ | |
1288 if(vf->ready_state>=STREAMSET){ | |
1289 /* snarf/scan a packet if we can */ | |
1290 int result=ogg_stream_packetout(&work_os,&op); | |
1291 | |
1292 if(result>0){ | |
1293 | |
1294 if(vf->vi[vf->current_link].codec_setup){ | |
1295 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); | |
1296 if(thisblock<0){ | |
1297 ogg_stream_packetout(&vf->os,NULL); | |
1298 thisblock=0; | |
1299 }else{ | |
1300 | |
1301 /* We can't get a guaranteed correct pcm position out of the | |
1302 last page in a stream because it might have a 'short' | |
1303 granpos, which can only be detected in the presence of a | |
1304 preceding page. However, if the last page is also the first | |
1305 page, the granpos rules of a first page take precedence. Not | |
1306 only that, but for first==last, the EOS page must be treated | |
1307 as if its a normal first page for the stream to open/play. */ | |
1308 if(lastflag && !firstflag) | |
1309 ogg_stream_packetout(&vf->os,NULL); | |
1310 else | |
1311 if(lastblock)accblock+=(lastblock+thisblock)>>2; | |
1312 } | |
1313 | |
1314 if(op.granulepos!=-1){ | |
1315 int i,link=vf->current_link; | |
1316 ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; | |
1317 if(granulepos<0)granulepos=0; | |
1318 | |
1319 for(i=0;i<link;i++) | |
1320 granulepos+=vf->pcmlengths[i*2+1]; | |
1321 vf->pcm_offset=granulepos-accblock; | |
1322 if(vf->pcm_offset<0)vf->pcm_offset=0; | |
1323 break; | |
1324 } | |
1325 lastblock=thisblock; | |
1326 continue; | |
1327 }else | |
1328 ogg_stream_packetout(&vf->os,NULL); | |
1329 } | |
1330 } | |
1331 | |
1332 if(!lastblock){ | |
1333 pagepos=_get_next_page(vf,&og,-1); | |
1334 if(pagepos<0){ | |
1335 vf->pcm_offset=ov_pcm_total(vf,-1); | |
1336 break; | |
1337 } | |
1338 }else{ | |
1339 /* huh? Bogus stream with packets but no granulepos */ | |
1340 vf->pcm_offset=-1; | |
1341 break; | |
1342 } | |
1343 | |
1344 /* has our decoding just traversed a bitstream boundary? */ | |
1345 if(vf->ready_state>=STREAMSET){ | |
1346 if(vf->current_serialno!=ogg_page_serialno(&og)){ | |
1347 | |
1348 /* two possibilities: | |
1349 1) our decoding just traversed a bitstream boundary | |
1350 2) another stream is multiplexed into this logical section? */ | |
1351 | |
1352 if(ogg_page_bos(&og)){ | |
1353 /* we traversed */ | |
1354 _decode_clear(vf); /* clear out stream state */ | |
1355 ogg_stream_clear(&work_os); | |
1356 } /* else, do nothing; next loop will scoop another page */ | |
1357 } | |
1358 } | |
1359 | |
1360 if(vf->ready_state<STREAMSET){ | |
1361 int link; | |
1362 long serialno = ogg_page_serialno(&og); | |
1363 | |
1364 for(link=0;link<vf->links;link++) | |
1365 if(vf->serialnos[link]==serialno)break; | |
1366 | |
1367 if(link==vf->links) continue; /* not the desired Vorbis | |
1368 bitstream section; keep | |
1369 trying */ | |
1370 vf->current_link=link; | |
1371 vf->current_serialno=serialno; | |
1372 ogg_stream_reset_serialno(&vf->os,serialno); | |
1373 ogg_stream_reset_serialno(&work_os,serialno); | |
1374 vf->ready_state=STREAMSET; | |
1375 firstflag=(pagepos<=vf->dataoffsets[link]); | |
1376 } | |
1377 | |
1378 ogg_stream_pagein(&vf->os,&og); | |
1379 ogg_stream_pagein(&work_os,&og); | |
1380 lastflag=ogg_page_eos(&og); | |
1381 | |
1382 } | |
1383 } | |
1384 | |
1385 ogg_stream_clear(&work_os); | |
1386 vf->bittrack=0.f; | |
1387 vf->samptrack=0.f; | |
1388 return(0); | |
1389 | |
1390 seek_error: | |
1391 /* dump the machine so we're in a known state */ | |
1392 vf->pcm_offset=-1; | |
1393 ogg_stream_clear(&work_os); | |
1394 _decode_clear(vf); | |
1395 return OV_EBADLINK; | |
1396 } | |
1397 | |
1398 /* Page granularity seek (faster than sample granularity because we | |
1399 don't do the last bit of decode to find a specific sample). | |
1400 | |
1401 Seek to the last [granule marked] page preceding the specified pos | |
1402 location, such that decoding past the returned point will quickly | |
1403 arrive at the requested position. */ | |
1404 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ | |
1405 int link=-1; | |
1406 ogg_int64_t result=0; | |
1407 ogg_int64_t total=ov_pcm_total(vf,-1); | |
1408 | |
1409 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1410 if(!vf->seekable)return(OV_ENOSEEK); | |
1411 | |
1412 if(pos<0 || pos>total)return(OV_EINVAL); | |
1413 | |
1414 /* which bitstream section does this pcm offset occur in? */ | |
1415 for(link=vf->links-1;link>=0;link--){ | |
1416 total-=vf->pcmlengths[link*2+1]; | |
1417 if(pos>=total)break; | |
1418 } | |
1419 | |
1420 /* search within the logical bitstream for the page with the highest | |
1421 pcm_pos preceding (or equal to) pos. There is a danger here; | |
1422 missing pages or incorrect frame number information in the | |
1423 bitstream could make our task impossible. Account for that (it | |
1424 would be an error condition) */ | |
1425 | |
1426 /* new search algorithm by HB (Nicholas Vinen) */ | |
1427 { | |
1428 ogg_int64_t end=vf->offsets[link+1]; | |
1429 ogg_int64_t begin=vf->offsets[link]; | |
1430 ogg_int64_t begintime = vf->pcmlengths[link*2]; | |
1431 ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; | |
1432 ogg_int64_t target=pos-total+begintime; | |
1433 ogg_int64_t best=begin; | |
1434 | |
1435 ogg_page og; | |
1436 while(begin<end){ | |
1437 ogg_int64_t bisect; | |
1438 | |
1439 if(end-begin<CHUNKSIZE){ | |
1440 bisect=begin; | |
1441 }else{ | |
1442 /* take a (pretty decent) guess. */ | |
1443 bisect=begin + | |
1444 (ogg_int64_t)((double)(target-begintime)*(end-begin)/(endtime-begintime)) | |
1445 - CHUNKSIZE; | |
1446 if(bisect<begin+CHUNKSIZE) | |
1447 bisect=begin; | |
1448 } | |
1449 | |
1450 if(bisect!=vf->offset){ | |
1451 result=_seek_helper(vf,bisect); | |
1452 if(result) goto seek_error; | |
1453 } | |
1454 | |
1455 while(begin<end){ | |
1456 result=_get_next_page(vf,&og,end-vf->offset); | |
1457 if(result==OV_EREAD) goto seek_error; | |
1458 if(result<0){ | |
1459 if(bisect<=begin+1) | |
1460 end=begin; /* found it */ | |
1461 else{ | |
1462 if(bisect==0) goto seek_error; | |
1463 bisect-=CHUNKSIZE; | |
1464 if(bisect<=begin)bisect=begin+1; | |
1465 result=_seek_helper(vf,bisect); | |
1466 if(result) goto seek_error; | |
1467 } | |
1468 }else{ | |
1469 ogg_int64_t granulepos; | |
1470 | |
1471 if(ogg_page_serialno(&og)!=vf->serialnos[link]) | |
1472 continue; | |
1473 | |
1474 granulepos=ogg_page_granulepos(&og); | |
1475 if(granulepos==-1)continue; | |
1476 | |
1477 if(granulepos<target){ | |
1478 best=result; /* raw offset of packet with granulepos */ | |
1479 begin=vf->offset; /* raw offset of next page */ | |
1480 begintime=granulepos; | |
1481 | |
1482 if(target-begintime>44100)break; | |
1483 bisect=begin; /* *not* begin + 1 */ | |
1484 }else{ | |
1485 if(bisect<=begin+1) | |
1486 end=begin; /* found it */ | |
1487 else{ | |
1488 if(end==vf->offset){ /* we're pretty close - we'd be stuck in */ | |
1489 end=result; | |
1490 bisect-=CHUNKSIZE; /* an endless loop otherwise. */ | |
1491 if(bisect<=begin)bisect=begin+1; | |
1492 result=_seek_helper(vf,bisect); | |
1493 if(result) goto seek_error; | |
1494 }else{ | |
1495 end=bisect; | |
1496 endtime=granulepos; | |
1497 break; | |
1498 } | |
1499 } | |
1500 } | |
1501 } | |
1502 } | |
1503 } | |
1504 | |
1505 /* found our page. seek to it, update pcm offset. Easier case than | |
1506 raw_seek, don't keep packets preceding granulepos. */ | |
1507 { | |
1508 ogg_page og; | |
1509 ogg_packet op; | |
1510 | |
1511 /* seek */ | |
1512 result=_seek_helper(vf,best); | |
1513 vf->pcm_offset=-1; | |
1514 if(result) goto seek_error; | |
1515 result=_get_next_page(vf,&og,-1); | |
1516 if(result<0) goto seek_error; | |
1517 | |
1518 if(link!=vf->current_link){ | |
1519 /* Different link; dump entire decode machine */ | |
1520 _decode_clear(vf); | |
1521 | |
1522 vf->current_link=link; | |
1523 vf->current_serialno=vf->serialnos[link]; | |
1524 vf->ready_state=STREAMSET; | |
1525 | |
1526 }else{ | |
1527 vorbis_synthesis_restart(&vf->vd); | |
1528 } | |
1529 | |
1530 ogg_stream_reset_serialno(&vf->os,vf->current_serialno); | |
1531 ogg_stream_pagein(&vf->os,&og); | |
1532 | |
1533 /* pull out all but last packet; the one with granulepos */ | |
1534 while(1){ | |
1535 result=ogg_stream_packetpeek(&vf->os,&op); | |
1536 if(result==0){ | |
1537 /* !!! the packet finishing this page originated on a | |
1538 preceding page. Keep fetching previous pages until we | |
1539 get one with a granulepos or without the 'continued' flag | |
1540 set. Then just use raw_seek for simplicity. */ | |
1541 | |
1542 result=_seek_helper(vf,best); | |
1543 if(result<0) goto seek_error; | |
1544 | |
1545 while(1){ | |
1546 result=_get_prev_page(vf,&og); | |
1547 if(result<0) goto seek_error; | |
1548 if(ogg_page_serialno(&og)==vf->current_serialno && | |
1549 (ogg_page_granulepos(&og)>-1 || | |
1550 !ogg_page_continued(&og))){ | |
1551 return ov_raw_seek(vf,result); | |
1552 } | |
1553 vf->offset=result; | |
1554 } | |
1555 } | |
1556 if(result<0){ | |
1557 result = OV_EBADPACKET; | |
1558 goto seek_error; | |
1559 } | |
1560 if(op.granulepos!=-1){ | |
1561 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; | |
1562 if(vf->pcm_offset<0)vf->pcm_offset=0; | |
1563 vf->pcm_offset+=total; | |
1564 break; | |
1565 }else | |
1566 result=ogg_stream_packetout(&vf->os,NULL); | |
1567 } | |
1568 } | |
1569 } | |
1570 | |
1571 /* verify result */ | |
1572 if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ | |
1573 result=OV_EFAULT; | |
1574 goto seek_error; | |
1575 } | |
1576 vf->bittrack=0.f; | |
1577 vf->samptrack=0.f; | |
1578 return(0); | |
1579 | |
1580 seek_error: | |
1581 /* dump machine so we're in a known state */ | |
1582 vf->pcm_offset=-1; | |
1583 _decode_clear(vf); | |
1584 return (int)result; | |
1585 } | |
1586 | |
1587 /* seek to a sample offset relative to the decompressed pcm stream | |
1588 returns zero on success, nonzero on failure */ | |
1589 | |
1590 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ | |
1591 int thisblock,lastblock=0; | |
1592 int ret=ov_pcm_seek_page(vf,pos); | |
1593 if(ret<0)return(ret); | |
1594 if((ret=_make_decode_ready(vf)))return ret; | |
1595 | |
1596 /* discard leading packets we don't need for the lapping of the | |
1597 position we want; don't decode them */ | |
1598 | |
1599 while(1){ | |
1600 ogg_packet op; | |
1601 ogg_page og; | |
1602 | |
1603 int ret=ogg_stream_packetpeek(&vf->os,&op); | |
1604 if(ret>0){ | |
1605 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); | |
1606 if(thisblock<0){ | |
1607 ogg_stream_packetout(&vf->os,NULL); | |
1608 continue; /* non audio packet */ | |
1609 } | |
1610 if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2; | |
1611 | |
1612 if(vf->pcm_offset+((thisblock+ | |
1613 vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break; | |
1614 | |
1615 /* remove the packet from packet queue and track its granulepos */ | |
1616 ogg_stream_packetout(&vf->os,NULL); | |
1617 vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with | |
1618 only tracking, no | |
1619 pcm_decode */ | |
1620 vorbis_synthesis_blockin(&vf->vd,&vf->vb); | |
1621 | |
1622 /* end of logical stream case is hard, especially with exact | |
1623 length positioning. */ | |
1624 | |
1625 if(op.granulepos>-1){ | |
1626 int i; | |
1627 /* always believe the stream markers */ | |
1628 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; | |
1629 if(vf->pcm_offset<0)vf->pcm_offset=0; | |
1630 for(i=0;i<vf->current_link;i++) | |
1631 vf->pcm_offset+=vf->pcmlengths[i*2+1]; | |
1632 } | |
1633 | |
1634 lastblock=thisblock; | |
1635 | |
1636 }else{ | |
1637 if(ret<0 && ret!=OV_HOLE)break; | |
1638 | |
1639 /* suck in a new page */ | |
1640 if(_get_next_page(vf,&og,-1)<0)break; | |
1641 if(ogg_page_bos(&og))_decode_clear(vf); | |
1642 | |
1643 if(vf->ready_state<STREAMSET){ | |
1644 long serialno=ogg_page_serialno(&og); | |
1645 int link; | |
1646 | |
1647 for(link=0;link<vf->links;link++) | |
1648 if(vf->serialnos[link]==serialno)break; | |
1649 if(link==vf->links) continue; | |
1650 vf->current_link=link; | |
1651 | |
1652 vf->ready_state=STREAMSET; | |
1653 vf->current_serialno=ogg_page_serialno(&og); | |
1654 ogg_stream_reset_serialno(&vf->os,serialno); | |
1655 ret=_make_decode_ready(vf); | |
1656 if(ret)return ret; | |
1657 lastblock=0; | |
1658 } | |
1659 | |
1660 ogg_stream_pagein(&vf->os,&og); | |
1661 } | |
1662 } | |
1663 | |
1664 vf->bittrack=0.f; | |
1665 vf->samptrack=0.f; | |
1666 /* discard samples until we reach the desired position. Crossing a | |
1667 logical bitstream boundary with abandon is OK. */ | |
1668 { | |
1669 /* note that halfrate could be set differently in each link, but | |
1670 vorbisfile encoforces all links are set or unset */ | |
1671 int hs=vorbis_synthesis_halfrate_p(vf->vi); | |
1672 while(vf->pcm_offset<((pos>>hs)<<hs)){ | |
1673 ogg_int64_t target=(pos-vf->pcm_offset)>>hs; | |
1674 long samples=vorbis_synthesis_pcmout(&vf->vd,NULL); | |
1675 | |
1676 if(samples>target)samples=target; | |
1677 vorbis_synthesis_read(&vf->vd,samples); | |
1678 vf->pcm_offset+=samples<<hs; | |
1679 | |
1680 if(samples<target) | |
1681 if(_fetch_and_process_packet(vf,NULL,1,1)<=0) | |
1682 vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */ | |
1683 } | |
1684 } | |
1685 return 0; | |
1686 } | |
1687 | |
1688 /* seek to a playback time relative to the decompressed pcm stream | |
1689 returns zero on success, nonzero on failure */ | |
1690 int ov_time_seek(OggVorbis_File *vf,double seconds){ | |
1691 /* translate time to PCM position and call ov_pcm_seek */ | |
1692 | |
1693 int link=-1; | |
1694 ogg_int64_t pcm_total=0; | |
1695 double time_total=0.; | |
1696 | |
1697 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1698 if(!vf->seekable)return(OV_ENOSEEK); | |
1699 if(seconds<0)return(OV_EINVAL); | |
1700 | |
1701 /* which bitstream section does this time offset occur in? */ | |
1702 for(link=0;link<vf->links;link++){ | |
1703 double addsec = ov_time_total(vf,link); | |
1704 if(seconds<time_total+addsec)break; | |
1705 time_total+=addsec; | |
1706 pcm_total+=vf->pcmlengths[link*2+1]; | |
1707 } | |
1708 | |
1709 if(link==vf->links)return(OV_EINVAL); | |
1710 | |
1711 /* enough information to convert time offset to pcm offset */ | |
1712 { | |
1713 ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; | |
1714 return(ov_pcm_seek(vf,target)); | |
1715 } | |
1716 } | |
1717 | |
1718 /* page-granularity version of ov_time_seek | |
1719 returns zero on success, nonzero on failure */ | |
1720 int ov_time_seek_page(OggVorbis_File *vf,double seconds){ | |
1721 /* translate time to PCM position and call ov_pcm_seek */ | |
1722 | |
1723 int link=-1; | |
1724 ogg_int64_t pcm_total=0; | |
1725 double time_total=0.; | |
1726 | |
1727 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1728 if(!vf->seekable)return(OV_ENOSEEK); | |
1729 if(seconds<0)return(OV_EINVAL); | |
1730 | |
1731 /* which bitstream section does this time offset occur in? */ | |
1732 for(link=0;link<vf->links;link++){ | |
1733 double addsec = ov_time_total(vf,link); | |
1734 if(seconds<time_total+addsec)break; | |
1735 time_total+=addsec; | |
1736 pcm_total+=vf->pcmlengths[link*2+1]; | |
1737 } | |
1738 | |
1739 if(link==vf->links)return(OV_EINVAL); | |
1740 | |
1741 /* enough information to convert time offset to pcm offset */ | |
1742 { | |
1743 ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; | |
1744 return(ov_pcm_seek_page(vf,target)); | |
1745 } | |
1746 } | |
1747 | |
1748 /* tell the current stream offset cursor. Note that seek followed by | |
1749 tell will likely not give the set offset due to caching */ | |
1750 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ | |
1751 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1752 return(vf->offset); | |
1753 } | |
1754 | |
1755 /* return PCM offset (sample) of next PCM sample to be read */ | |
1756 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ | |
1757 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1758 return(vf->pcm_offset); | |
1759 } | |
1760 | |
1761 /* return time offset (seconds) of next PCM sample to be read */ | |
1762 double ov_time_tell(OggVorbis_File *vf){ | |
1763 int link=0; | |
1764 ogg_int64_t pcm_total=0; | |
1765 double time_total=0.f; | |
1766 | |
1767 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1768 if(vf->seekable){ | |
1769 pcm_total=ov_pcm_total(vf,-1); | |
1770 time_total=ov_time_total(vf,-1); | |
1771 | |
1772 /* which bitstream section does this time offset occur in? */ | |
1773 for(link=vf->links-1;link>=0;link--){ | |
1774 pcm_total-=vf->pcmlengths[link*2+1]; | |
1775 time_total-=ov_time_total(vf,link); | |
1776 if(vf->pcm_offset>=pcm_total)break; | |
1777 } | |
1778 } | |
1779 | |
1780 return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate); | |
1781 } | |
1782 | |
1783 /* link: -1) return the vorbis_info struct for the bitstream section | |
1784 currently being decoded | |
1785 0-n) to request information for a specific bitstream section | |
1786 | |
1787 In the case of a non-seekable bitstream, any call returns the | |
1788 current bitstream. NULL in the case that the machine is not | |
1789 initialized */ | |
1790 | |
1791 vorbis_info *ov_info(OggVorbis_File *vf,int link){ | |
1792 if(vf->seekable){ | |
1793 if(link<0) | |
1794 if(vf->ready_state>=STREAMSET) | |
1795 return vf->vi+vf->current_link; | |
1796 else | |
1797 return vf->vi; | |
1798 else | |
1799 if(link>=vf->links) | |
1800 return NULL; | |
1801 else | |
1802 return vf->vi+link; | |
1803 }else{ | |
1804 return vf->vi; | |
1805 } | |
1806 } | |
1807 | |
1808 /* grr, strong typing, grr, no templates/inheritence, grr */ | |
1809 vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ | |
1810 if(vf->seekable){ | |
1811 if(link<0) | |
1812 if(vf->ready_state>=STREAMSET) | |
1813 return vf->vc+vf->current_link; | |
1814 else | |
1815 return vf->vc; | |
1816 else | |
1817 if(link>=vf->links) | |
1818 return NULL; | |
1819 else | |
1820 return vf->vc+link; | |
1821 }else{ | |
1822 return vf->vc; | |
1823 } | |
1824 } | |
1825 | |
1826 static int host_is_big_endian() { | |
1827 ogg_int32_t pattern = 0xfeedface; /* deadbeef */ | |
1828 unsigned char *bytewise = (unsigned char *)&pattern; | |
1829 if (bytewise[0] == 0xfe) return 1; | |
1830 return 0; | |
1831 } | |
1832 | |
1833 /* up to this point, everything could more or less hide the multiple | |
1834 logical bitstream nature of chaining from the toplevel application | |
1835 if the toplevel application didn't particularly care. However, at | |
1836 the point that we actually read audio back, the multiple-section | |
1837 nature must surface: Multiple bitstream sections do not necessarily | |
1838 have to have the same number of channels or sampling rate. | |
1839 | |
1840 ov_read returns the sequential logical bitstream number currently | |
1841 being decoded along with the PCM data in order that the toplevel | |
1842 application can take action on channel/sample rate changes. This | |
1843 number will be incremented even for streamed (non-seekable) streams | |
1844 (for seekable streams, it represents the actual logical bitstream | |
1845 index within the physical bitstream. Note that the accessor | |
1846 functions above are aware of this dichotomy). | |
1847 | |
1848 ov_read_filter is exactly the same as ov_read except that it processes | |
1849 the decoded audio data through a filter before packing it into the | |
1850 requested format. This gives greater accuracy than applying a filter | |
1851 after the audio has been converted into integral PCM. | |
1852 | |
1853 input values: buffer) a buffer to hold packed PCM data for return | |
1854 length) the byte length requested to be placed into buffer | |
1855 bigendianp) should the data be packed LSB first (0) or | |
1856 MSB first (1) | |
1857 word) word size for output. currently 1 (byte) or | |
1858 2 (16 bit short) | |
1859 | |
1860 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) | |
1861 0) EOF | |
1862 n) number of bytes of PCM actually returned. The | |
1863 below works on a packet-by-packet basis, so the | |
1864 return length is not related to the 'length' passed | |
1865 in, just guaranteed to fit. | |
1866 | |
1867 *section) set to the logical bitstream number */ | |
1868 | |
1869 long ov_read_filter(OggVorbis_File *vf,char *buffer,int length, | |
1870 int bigendianp,int word,int sgned,int *bitstream, | |
1871 void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){ | |
1872 int i,j; | |
1873 int host_endian = host_is_big_endian(); | |
1874 int hs; | |
1875 | |
1876 float **pcm; | |
1877 long samples; | |
1878 | |
1879 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
1880 | |
1881 while(1){ | |
1882 if(vf->ready_state==INITSET){ | |
1883 samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); | |
1884 if(samples)break; | |
1885 } | |
1886 | |
1887 /* suck in another packet */ | |
1888 { | |
1889 int ret=_fetch_and_process_packet(vf,NULL,1,1); | |
1890 if(ret==OV_EOF) | |
1891 return(0); | |
1892 if(ret<=0) | |
1893 return(ret); | |
1894 } | |
1895 | |
1896 } | |
1897 | |
1898 if(samples>0){ | |
1899 | |
1900 /* yay! proceed to pack data into the byte buffer */ | |
1901 | |
1902 long channels=ov_info(vf,-1)->channels; | |
1903 long bytespersample=word * channels; | |
1904 vorbis_fpu_control fpu; | |
1905 if(samples>length/bytespersample)samples=length/bytespersample; | |
1906 | |
1907 if(samples <= 0) | |
1908 return OV_EINVAL; | |
1909 | |
1910 /* Here. */ | |
1911 if(filter) | |
1912 filter(pcm,channels,samples,filter_param); | |
1913 | |
1914 /* a tight loop to pack each size */ | |
1915 { | |
1916 int val; | |
1917 if(word==1){ | |
1918 int off=(sgned?0:128); | |
1919 vorbis_fpu_setround(&fpu); | |
1920 for(j=0;j<samples;j++) | |
1921 for(i=0;i<channels;i++){ | |
1922 val=vorbis_ftoi(pcm[i][j]*128.f); | |
1923 if(val>127)val=127; | |
1924 else if(val<-128)val=-128; | |
1925 *buffer++=val+off; | |
1926 } | |
1927 vorbis_fpu_restore(fpu); | |
1928 }else{ | |
1929 int off=(sgned?0:32768); | |
1930 | |
1931 if(host_endian==bigendianp){ | |
1932 if(sgned){ | |
1933 | |
1934 vorbis_fpu_setround(&fpu); | |
1935 for(i=0;i<channels;i++) { /* It's faster in this order */ | |
1936 float *src=pcm[i]; | |
1937 short *dest=((short *)buffer)+i; | |
1938 for(j=0;j<samples;j++) { | |
1939 val=vorbis_ftoi(src[j]*32768.f); | |
1940 if(val>32767)val=32767; | |
1941 else if(val<-32768)val=-32768; | |
1942 *dest=val; | |
1943 dest+=channels; | |
1944 } | |
1945 } | |
1946 vorbis_fpu_restore(fpu); | |
1947 | |
1948 }else{ | |
1949 | |
1950 vorbis_fpu_setround(&fpu); | |
1951 for(i=0;i<channels;i++) { | |
1952 float *src=pcm[i]; | |
1953 short *dest=((short *)buffer)+i; | |
1954 for(j=0;j<samples;j++) { | |
1955 val=vorbis_ftoi(src[j]*32768.f); | |
1956 if(val>32767)val=32767; | |
1957 else if(val<-32768)val=-32768; | |
1958 *dest=val+off; | |
1959 dest+=channels; | |
1960 } | |
1961 } | |
1962 vorbis_fpu_restore(fpu); | |
1963 | |
1964 } | |
1965 }else if(bigendianp){ | |
1966 | |
1967 vorbis_fpu_setround(&fpu); | |
1968 for(j=0;j<samples;j++) | |
1969 for(i=0;i<channels;i++){ | |
1970 val=vorbis_ftoi(pcm[i][j]*32768.f); | |
1971 if(val>32767)val=32767; | |
1972 else if(val<-32768)val=-32768; | |
1973 val+=off; | |
1974 *buffer++=(val>>8); | |
1975 *buffer++=(val&0xff); | |
1976 } | |
1977 vorbis_fpu_restore(fpu); | |
1978 | |
1979 }else{ | |
1980 int val; | |
1981 vorbis_fpu_setround(&fpu); | |
1982 for(j=0;j<samples;j++) | |
1983 for(i=0;i<channels;i++){ | |
1984 val=vorbis_ftoi(pcm[i][j]*32768.f); | |
1985 if(val>32767)val=32767; | |
1986 else if(val<-32768)val=-32768; | |
1987 val+=off; | |
1988 *buffer++=(val&0xff); | |
1989 *buffer++=(val>>8); | |
1990 } | |
1991 vorbis_fpu_restore(fpu); | |
1992 | |
1993 } | |
1994 } | |
1995 } | |
1996 | |
1997 vorbis_synthesis_read(&vf->vd,samples); | |
1998 hs=vorbis_synthesis_halfrate_p(vf->vi); | |
1999 vf->pcm_offset+=(samples<<hs); | |
2000 if(bitstream)*bitstream=vf->current_link; | |
2001 return(samples*bytespersample); | |
2002 }else{ | |
2003 return(samples); | |
2004 } | |
2005 } | |
2006 | |
2007 long ov_read(OggVorbis_File *vf,char *buffer,int length, | |
2008 int bigendianp,int word,int sgned,int *bitstream){ | |
2009 return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL); | |
2010 } | |
2011 | |
2012 /* input values: pcm_channels) a float vector per channel of output | |
2013 length) the sample length being read by the app | |
2014 | |
2015 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) | |
2016 0) EOF | |
2017 n) number of samples of PCM actually returned. The | |
2018 below works on a packet-by-packet basis, so the | |
2019 return length is not related to the 'length' passed | |
2020 in, just guaranteed to fit. | |
2021 | |
2022 *section) set to the logical bitstream number */ | |
2023 | |
2024 | |
2025 | |
2026 long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length, | |
2027 int *bitstream){ | |
2028 | |
2029 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
2030 | |
2031 while(1){ | |
2032 if(vf->ready_state==INITSET){ | |
2033 float **pcm; | |
2034 long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); | |
2035 if(samples){ | |
2036 int hs=vorbis_synthesis_halfrate_p(vf->vi); | |
2037 if(pcm_channels)*pcm_channels=pcm; | |
2038 if(samples>length)samples=length; | |
2039 vorbis_synthesis_read(&vf->vd,samples); | |
2040 vf->pcm_offset+=samples<<hs; | |
2041 if(bitstream)*bitstream=vf->current_link; | |
2042 return samples; | |
2043 | |
2044 } | |
2045 } | |
2046 | |
2047 /* suck in another packet */ | |
2048 { | |
2049 int ret=_fetch_and_process_packet(vf,NULL,1,1); | |
2050 if(ret==OV_EOF)return(0); | |
2051 if(ret<=0)return(ret); | |
2052 } | |
2053 | |
2054 } | |
2055 } | |
2056 | |
2057 extern float *vorbis_window(vorbis_dsp_state *v,int W); | |
2058 | |
2059 static void _ov_splice(float **pcm,float **lappcm, | |
2060 int n1, int n2, | |
2061 int ch1, int ch2, | |
2062 float *w1, float *w2){ | |
2063 int i,j; | |
2064 float *w=w1; | |
2065 int n=n1; | |
2066 | |
2067 if(n1>n2){ | |
2068 n=n2; | |
2069 w=w2; | |
2070 } | |
2071 | |
2072 /* splice */ | |
2073 for(j=0;j<ch1 && j<ch2;j++){ | |
2074 float *s=lappcm[j]; | |
2075 float *d=pcm[j]; | |
2076 | |
2077 for(i=0;i<n;i++){ | |
2078 float wd=w[i]*w[i]; | |
2079 float ws=1.-wd; | |
2080 d[i]=d[i]*wd + s[i]*ws; | |
2081 } | |
2082 } | |
2083 /* window from zero */ | |
2084 for(;j<ch2;j++){ | |
2085 float *d=pcm[j]; | |
2086 for(i=0;i<n;i++){ | |
2087 float wd=w[i]*w[i]; | |
2088 d[i]=d[i]*wd; | |
2089 } | |
2090 } | |
2091 | |
2092 } | |
2093 | |
2094 /* make sure vf is INITSET */ | |
2095 static int _ov_initset(OggVorbis_File *vf){ | |
2096 while(1){ | |
2097 if(vf->ready_state==INITSET)break; | |
2098 /* suck in another packet */ | |
2099 { | |
2100 int ret=_fetch_and_process_packet(vf,NULL,1,0); | |
2101 if(ret<0 && ret!=OV_HOLE)return(ret); | |
2102 } | |
2103 } | |
2104 return 0; | |
2105 } | |
2106 | |
2107 /* make sure vf is INITSET and that we have a primed buffer; if | |
2108 we're crosslapping at a stream section boundary, this also makes | |
2109 sure we're sanity checking against the right stream information */ | |
2110 static int _ov_initprime(OggVorbis_File *vf){ | |
2111 vorbis_dsp_state *vd=&vf->vd; | |
2112 while(1){ | |
2113 if(vf->ready_state==INITSET) | |
2114 if(vorbis_synthesis_pcmout(vd,NULL))break; | |
2115 | |
2116 /* suck in another packet */ | |
2117 { | |
2118 int ret=_fetch_and_process_packet(vf,NULL,1,0); | |
2119 if(ret<0 && ret!=OV_HOLE)return(ret); | |
2120 } | |
2121 } | |
2122 return 0; | |
2123 } | |
2124 | |
2125 /* grab enough data for lapping from vf; this may be in the form of | |
2126 unreturned, already-decoded pcm, remaining PCM we will need to | |
2127 decode, or synthetic postextrapolation from last packets. */ | |
2128 static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd, | |
2129 float **lappcm,int lapsize){ | |
2130 int lapcount=0,i; | |
2131 float **pcm; | |
2132 | |
2133 /* try first to decode the lapping data */ | |
2134 while(lapcount<lapsize){ | |
2135 int samples=vorbis_synthesis_pcmout(vd,&pcm); | |
2136 if(samples){ | |
2137 if(samples>lapsize-lapcount)samples=lapsize-lapcount; | |
2138 for(i=0;i<vi->channels;i++) | |
2139 memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples); | |
2140 lapcount+=samples; | |
2141 vorbis_synthesis_read(vd,samples); | |
2142 }else{ | |
2143 /* suck in another packet */ | |
2144 int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */ | |
2145 if(ret==OV_EOF)break; | |
2146 } | |
2147 } | |
2148 if(lapcount<lapsize){ | |
2149 /* failed to get lapping data from normal decode; pry it from the | |
2150 postextrapolation buffering, or the second half of the MDCT | |
2151 from the last packet */ | |
2152 int samples=vorbis_synthesis_lapout(&vf->vd,&pcm); | |
2153 if(samples==0){ | |
2154 for(i=0;i<vi->channels;i++) | |
2155 memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount); | |
2156 lapcount=lapsize; | |
2157 }else{ | |
2158 if(samples>lapsize-lapcount)samples=lapsize-lapcount; | |
2159 for(i=0;i<vi->channels;i++) | |
2160 memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples); | |
2161 lapcount+=samples; | |
2162 } | |
2163 } | |
2164 } | |
2165 | |
2166 /* this sets up crosslapping of a sample by using trailing data from | |
2167 sample 1 and lapping it into the windowing buffer of sample 2 */ | |
2168 int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){ | |
2169 vorbis_info *vi1,*vi2; | |
2170 float **lappcm; | |
2171 float **pcm; | |
2172 float *w1,*w2; | |
2173 int n1,n2,i,ret,hs1,hs2; | |
2174 | |
2175 if(vf1==vf2)return(0); /* degenerate case */ | |
2176 if(vf1->ready_state<OPENED)return(OV_EINVAL); | |
2177 if(vf2->ready_state<OPENED)return(OV_EINVAL); | |
2178 | |
2179 /* the relevant overlap buffers must be pre-checked and pre-primed | |
2180 before looking at settings in the event that priming would cross | |
2181 a bitstream boundary. So, do it now */ | |
2182 | |
2183 ret=_ov_initset(vf1); | |
2184 if(ret)return(ret); | |
2185 ret=_ov_initprime(vf2); | |
2186 if(ret)return(ret); | |
2187 | |
2188 vi1=ov_info(vf1,-1); | |
2189 vi2=ov_info(vf2,-1); | |
2190 hs1=ov_halfrate_p(vf1); | |
2191 hs2=ov_halfrate_p(vf2); | |
2192 | |
2193 lappcm=alloca(sizeof(*lappcm)*vi1->channels); | |
2194 n1=vorbis_info_blocksize(vi1,0)>>(1+hs1); | |
2195 n2=vorbis_info_blocksize(vi2,0)>>(1+hs2); | |
2196 w1=vorbis_window(&vf1->vd,0); | |
2197 w2=vorbis_window(&vf2->vd,0); | |
2198 | |
2199 for(i=0;i<vi1->channels;i++) | |
2200 lappcm[i]=alloca(sizeof(**lappcm)*n1); | |
2201 | |
2202 _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1); | |
2203 | |
2204 /* have a lapping buffer from vf1; now to splice it into the lapping | |
2205 buffer of vf2 */ | |
2206 /* consolidate and expose the buffer. */ | |
2207 vorbis_synthesis_lapout(&vf2->vd,&pcm); | |
2208 | |
2209 #if 0 | |
2210 _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0); | |
2211 _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0); | |
2212 #endif | |
2213 | |
2214 /* splice */ | |
2215 _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2); | |
2216 | |
2217 /* done */ | |
2218 return(0); | |
2219 } | |
2220 | |
2221 static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos, | |
2222 int (*localseek)(OggVorbis_File *,ogg_int64_t)){ | |
2223 vorbis_info *vi; | |
2224 float **lappcm; | |
2225 float **pcm; | |
2226 float *w1,*w2; | |
2227 int n1,n2,ch1,ch2,hs; | |
2228 int i,ret; | |
2229 | |
2230 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
2231 ret=_ov_initset(vf); | |
2232 if(ret)return(ret); | |
2233 vi=ov_info(vf,-1); | |
2234 hs=ov_halfrate_p(vf); | |
2235 | |
2236 ch1=vi->channels; | |
2237 n1=vorbis_info_blocksize(vi,0)>>(1+hs); | |
2238 w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are | |
2239 persistent; even if the decode state | |
2240 from this link gets dumped, this | |
2241 window array continues to exist */ | |
2242 | |
2243 lappcm=alloca(sizeof(*lappcm)*ch1); | |
2244 for(i=0;i<ch1;i++) | |
2245 lappcm[i]=alloca(sizeof(**lappcm)*n1); | |
2246 _ov_getlap(vf,vi,&vf->vd,lappcm,n1); | |
2247 | |
2248 /* have lapping data; seek and prime the buffer */ | |
2249 ret=localseek(vf,pos); | |
2250 if(ret)return ret; | |
2251 ret=_ov_initprime(vf); | |
2252 if(ret)return(ret); | |
2253 | |
2254 /* Guard against cross-link changes; they're perfectly legal */ | |
2255 vi=ov_info(vf,-1); | |
2256 ch2=vi->channels; | |
2257 n2=vorbis_info_blocksize(vi,0)>>(1+hs); | |
2258 w2=vorbis_window(&vf->vd,0); | |
2259 | |
2260 /* consolidate and expose the buffer. */ | |
2261 vorbis_synthesis_lapout(&vf->vd,&pcm); | |
2262 | |
2263 /* splice */ | |
2264 _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2); | |
2265 | |
2266 /* done */ | |
2267 return(0); | |
2268 } | |
2269 | |
2270 int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){ | |
2271 return _ov_64_seek_lap(vf,pos,ov_raw_seek); | |
2272 } | |
2273 | |
2274 int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){ | |
2275 return _ov_64_seek_lap(vf,pos,ov_pcm_seek); | |
2276 } | |
2277 | |
2278 int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){ | |
2279 return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page); | |
2280 } | |
2281 | |
2282 static int _ov_d_seek_lap(OggVorbis_File *vf,double pos, | |
2283 int (*localseek)(OggVorbis_File *,double)){ | |
2284 vorbis_info *vi; | |
2285 float **lappcm; | |
2286 float **pcm; | |
2287 float *w1,*w2; | |
2288 int n1,n2,ch1,ch2,hs; | |
2289 int i,ret; | |
2290 | |
2291 if(vf->ready_state<OPENED)return(OV_EINVAL); | |
2292 ret=_ov_initset(vf); | |
2293 if(ret)return(ret); | |
2294 vi=ov_info(vf,-1); | |
2295 hs=ov_halfrate_p(vf); | |
2296 | |
2297 ch1=vi->channels; | |
2298 n1=vorbis_info_blocksize(vi,0)>>(1+hs); | |
2299 w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are | |
2300 persistent; even if the decode state | |
2301 from this link gets dumped, this | |
2302 window array continues to exist */ | |
2303 | |
2304 lappcm=alloca(sizeof(*lappcm)*ch1); | |
2305 for(i=0;i<ch1;i++) | |
2306 lappcm[i]=alloca(sizeof(**lappcm)*n1); | |
2307 _ov_getlap(vf,vi,&vf->vd,lappcm,n1); | |
2308 | |
2309 /* have lapping data; seek and prime the buffer */ | |
2310 ret=localseek(vf,pos); | |
2311 if(ret)return ret; | |
2312 ret=_ov_initprime(vf); | |
2313 if(ret)return(ret); | |
2314 | |
2315 /* Guard against cross-link changes; they're perfectly legal */ | |
2316 vi=ov_info(vf,-1); | |
2317 ch2=vi->channels; | |
2318 n2=vorbis_info_blocksize(vi,0)>>(1+hs); | |
2319 w2=vorbis_window(&vf->vd,0); | |
2320 | |
2321 /* consolidate and expose the buffer. */ | |
2322 vorbis_synthesis_lapout(&vf->vd,&pcm); | |
2323 | |
2324 /* splice */ | |
2325 _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2); | |
2326 | |
2327 /* done */ | |
2328 return(0); | |
2329 } | |
2330 | |
2331 int ov_time_seek_lap(OggVorbis_File *vf,double pos){ | |
2332 return _ov_d_seek_lap(vf,pos,ov_time_seek); | |
2333 } | |
2334 | |
2335 int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){ | |
2336 return _ov_d_seek_lap(vf,pos,ov_time_seek_page); | |
2337 } |