Line | Count | Source (jump to first uncovered line) |
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-2014 * |
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$ |
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 "os.h" |
29 | | #include "misc.h" |
30 | | |
31 | | /* A 'chained bitstream' is a Vorbis bitstream that contains more than |
32 | | one logical bitstream arranged end to end (the only form of Ogg |
33 | | multiplexing allowed in a Vorbis bitstream; grouping [parallel |
34 | | multiplexing] is not allowed in Vorbis) */ |
35 | | |
36 | | /* A Vorbis file can be played beginning to end (streamed) without |
37 | | worrying ahead of time about chaining (see decoder_example.c). If |
38 | | we have the whole file, however, and want random access |
39 | | (seeking/scrubbing) or desire to know the total length/time of a |
40 | | file, we need to account for the possibility of chaining. */ |
41 | | |
42 | | /* We can handle things a number of ways; we can determine the entire |
43 | | bitstream structure right off the bat, or find pieces on demand. |
44 | | This example determines and caches structure for the entire |
45 | | bitstream, but builds a virtual decoder on the fly when moving |
46 | | between links in the chain. */ |
47 | | |
48 | | /* There are also different ways to implement seeking. Enough |
49 | | information exists in an Ogg bitstream to seek to |
50 | | sample-granularity positions in the output. Or, one can seek by |
51 | | picking some portion of the stream roughly in the desired area if |
52 | | we only want coarse navigation through the stream. */ |
53 | | |
54 | | /************************************************************************* |
55 | | * Many, many internal helpers. The intention is not to be confusing; |
56 | | * rampant duplication and monolithic function implementation would be |
57 | | * harder to understand anyway. The high level functions are last. Begin |
58 | | * grokking near the end of the file */ |
59 | | |
60 | | |
61 | | /* read a little more data from the file/pipe into the ogg_sync framer */ |
62 | 9.74k | static long _get_data(OggVorbis_File *vf){ |
63 | 9.74k | errno=0; |
64 | 9.74k | if(!(vf->callbacks.read_func))return(-1); |
65 | 9.74k | if(vf->datasource){ |
66 | 9.74k | char *buffer=ogg_sync_buffer(&vf->oy,READSIZE); |
67 | 9.74k | long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource); |
68 | 9.74k | if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); |
69 | 9.74k | if(bytes==0 && errno)return(-1); |
70 | 9.74k | return(bytes); |
71 | 9.74k | }else |
72 | 0 | return(0); |
73 | 9.74k | } |
74 | | |
75 | | /* save a tiny smidge of verbosity to make the code more readable */ |
76 | 0 | static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ |
77 | 0 | if(vf->datasource){ |
78 | | /* only seek if the file position isn't already there */ |
79 | 0 | if(vf->offset != offset){ |
80 | 0 | if(!(vf->callbacks.seek_func)|| |
81 | 0 | (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) |
82 | 0 | return OV_EREAD; |
83 | 0 | vf->offset=offset; |
84 | 0 | ogg_sync_reset(&vf->oy); |
85 | 0 | } |
86 | 0 | }else{ |
87 | | /* shouldn't happen unless someone writes a broken callback */ |
88 | 0 | return OV_EFAULT; |
89 | 0 | } |
90 | 0 | return 0; |
91 | 0 | } |
92 | | |
93 | | /* The read/seek functions track absolute position within the stream */ |
94 | | |
95 | | /* from the head of the stream, get the next page. boundary specifies |
96 | | if the function is allowed to fetch more data from the stream (and |
97 | | how much) or only use internally buffered data. |
98 | | |
99 | | boundary: -1) unbounded search |
100 | | 0) read no additional data; use cached only |
101 | | n) search for a new page beginning for n bytes |
102 | | |
103 | | return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) |
104 | | n) found a page at absolute offset n */ |
105 | | |
106 | | static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, |
107 | 36.4k | ogg_int64_t boundary){ |
108 | 36.4k | if(boundary>0)boundary+=vf->offset; |
109 | 54.6k | while(1){ |
110 | 54.6k | long more; |
111 | | |
112 | 54.6k | if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); |
113 | 54.6k | more=ogg_sync_pageseek(&vf->oy,og); |
114 | | |
115 | 54.6k | if(more<0){ |
116 | | /* skipped n bytes */ |
117 | 11.1k | vf->offset-=more; |
118 | 43.4k | }else{ |
119 | 43.4k | if(more==0){ |
120 | | /* send more paramedics */ |
121 | 9.74k | if(!boundary)return(OV_FALSE); |
122 | 9.74k | { |
123 | 9.74k | long ret=_get_data(vf); |
124 | 9.74k | if(ret==0)return(OV_EOF); |
125 | 7.04k | if(ret<0)return(OV_EREAD); |
126 | 7.04k | } |
127 | 33.6k | }else{ |
128 | | /* got a page. Return the offset at the page beginning, |
129 | | advance the internal offset past the page end */ |
130 | 33.6k | ogg_int64_t ret=vf->offset; |
131 | 33.6k | vf->offset+=more; |
132 | 33.6k | return(ret); |
133 | | |
134 | 33.6k | } |
135 | 43.4k | } |
136 | 54.6k | } |
137 | 36.4k | } |
138 | | |
139 | | /* find the latest page beginning before the passed in position. Much |
140 | | dirtier than the above as Ogg doesn't have any backward search |
141 | | linkage. no 'readp' as it will certainly have to read. */ |
142 | | /* returns offset or OV_EREAD, OV_FAULT */ |
143 | 0 | static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){ |
144 | 0 | ogg_int64_t end = begin; |
145 | 0 | ogg_int64_t ret; |
146 | 0 | ogg_int64_t offset=-1; |
147 | |
|
148 | 0 | while(offset==-1){ |
149 | 0 | begin-=CHUNKSIZE; |
150 | 0 | if(begin<0) |
151 | 0 | begin=0; |
152 | |
|
153 | 0 | ret=_seek_helper(vf,begin); |
154 | 0 | if(ret)return(ret); |
155 | | |
156 | 0 | while(vf->offset<end){ |
157 | 0 | memset(og,0,sizeof(*og)); |
158 | 0 | ret=_get_next_page(vf,og,end-vf->offset); |
159 | 0 | if(ret==OV_EREAD)return(OV_EREAD); |
160 | 0 | if(ret<0){ |
161 | 0 | break; |
162 | 0 | }else{ |
163 | 0 | offset=ret; |
164 | 0 | } |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | | /* In a fully compliant, non-multiplexed stream, we'll still be |
169 | | holding the last page. In multiplexed (or noncompliant streams), |
170 | | we will probably have to re-read the last page we saw */ |
171 | 0 | if(og->header_len==0){ |
172 | 0 | ret=_seek_helper(vf,offset); |
173 | 0 | if(ret)return(ret); |
174 | | |
175 | 0 | ret=_get_next_page(vf,og,CHUNKSIZE); |
176 | 0 | if(ret<0) |
177 | | /* this shouldn't be possible */ |
178 | 0 | return(OV_EFAULT); |
179 | 0 | } |
180 | | |
181 | 0 | return(offset); |
182 | 0 | } |
183 | | |
184 | 5.39k | static void _add_serialno(ogg_page *og,ogg_uint32_t **serialno_list, int *n){ |
185 | 5.39k | ogg_uint32_t s = ogg_page_serialno(og); |
186 | 5.39k | (*n)++; |
187 | | |
188 | 5.39k | if(*serialno_list){ |
189 | 1.12k | *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n)); |
190 | 4.27k | }else{ |
191 | 4.27k | *serialno_list = _ogg_malloc(sizeof(**serialno_list)); |
192 | 4.27k | } |
193 | | |
194 | 5.39k | (*serialno_list)[(*n)-1] = s; |
195 | 5.39k | } |
196 | | |
197 | | /* returns nonzero if found */ |
198 | 5.40k | static int _lookup_serialno(ogg_uint32_t s, ogg_uint32_t *serialno_list, int n){ |
199 | 5.40k | if(serialno_list){ |
200 | 15.4k | while(n--){ |
201 | 14.2k | if(*serialno_list == s) return 1; |
202 | 14.2k | serialno_list++; |
203 | 14.2k | } |
204 | 1.12k | } |
205 | 5.39k | return 0; |
206 | 5.40k | } |
207 | | |
208 | 5.40k | static int _lookup_page_serialno(ogg_page *og, ogg_uint32_t *serialno_list, int n){ |
209 | 5.40k | ogg_uint32_t s = ogg_page_serialno(og); |
210 | 5.40k | return _lookup_serialno(s,serialno_list,n); |
211 | 5.40k | } |
212 | | |
213 | | /* performs the same search as _get_prev_page, but prefers pages of |
214 | | the specified serial number. If a page of the specified serialno is |
215 | | spotted during the seek-back-and-read-forward, it will return the |
216 | | info of last page of the matching serial number instead of the very |
217 | | last page. If no page of the specified serialno is seen, it will |
218 | | return the info of last page and alter *serialno. */ |
219 | | static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin, |
220 | | ogg_uint32_t *serial_list, int serial_n, |
221 | 0 | int *serialno, ogg_int64_t *granpos){ |
222 | 0 | ogg_page og; |
223 | 0 | ogg_int64_t end=begin; |
224 | 0 | ogg_int64_t ret; |
225 | |
|
226 | 0 | ogg_int64_t prefoffset=-1; |
227 | 0 | ogg_int64_t offset=-1; |
228 | 0 | ogg_int64_t ret_serialno=-1; |
229 | 0 | ogg_int64_t ret_gran=-1; |
230 | |
|
231 | 0 | while(offset==-1){ |
232 | 0 | begin-=CHUNKSIZE; |
233 | 0 | if(begin<0) |
234 | 0 | begin=0; |
235 | |
|
236 | 0 | ret=_seek_helper(vf,begin); |
237 | 0 | if(ret)return(ret); |
238 | | |
239 | 0 | while(vf->offset<end){ |
240 | 0 | ret=_get_next_page(vf,&og,end-vf->offset); |
241 | 0 | if(ret==OV_EREAD)return(OV_EREAD); |
242 | 0 | if(ret<0){ |
243 | 0 | break; |
244 | 0 | }else{ |
245 | 0 | ret_serialno=ogg_page_serialno(&og); |
246 | 0 | ret_gran=ogg_page_granulepos(&og); |
247 | 0 | offset=ret; |
248 | |
|
249 | 0 | if((ogg_uint32_t)ret_serialno == *serialno){ |
250 | 0 | prefoffset=ret; |
251 | 0 | *granpos=ret_gran; |
252 | 0 | } |
253 | |
|
254 | 0 | if(!_lookup_serialno((ogg_uint32_t)ret_serialno,serial_list,serial_n)){ |
255 | | /* we fell off the end of the link, which means we seeked |
256 | | back too far and shouldn't have been looking in that link |
257 | | to begin with. If we found the preferred serial number, |
258 | | forget that we saw it. */ |
259 | 0 | prefoffset=-1; |
260 | 0 | } |
261 | 0 | } |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | | /* we're not interested in the page... just the serialno and granpos. */ |
266 | 0 | if(prefoffset>=0)return(prefoffset); |
267 | | |
268 | 0 | *serialno = ret_serialno; |
269 | 0 | *granpos = ret_gran; |
270 | 0 | return(offset); |
271 | |
|
272 | 0 | } |
273 | | |
274 | | /* uses the local ogg_stream storage in vf; this is important for |
275 | | non-streaming input sources */ |
276 | | static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, |
277 | | ogg_uint32_t **serialno_list, int *serialno_n, |
278 | 8.50k | ogg_page *og_ptr){ |
279 | 8.50k | ogg_page og; |
280 | 8.50k | ogg_packet op; |
281 | 8.50k | int i,ret; |
282 | 8.50k | int allbos=0; |
283 | | |
284 | 8.50k | if(!og_ptr){ |
285 | 4.35k | ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); |
286 | 4.35k | if(llret==OV_EREAD)return(OV_EREAD); |
287 | 4.35k | if(llret<0)return(OV_ENOTVORBIS); |
288 | 4.28k | og_ptr=&og; |
289 | 4.28k | } |
290 | | |
291 | 8.42k | vorbis_info_init(vi); |
292 | 8.42k | vorbis_comment_init(vc); |
293 | 8.42k | vf->ready_state=OPENED; |
294 | | |
295 | | /* extract the serialnos of all BOS pages + the first set of vorbis |
296 | | headers we see in the link */ |
297 | | |
298 | 15.0k | while(ogg_page_bos(og_ptr)){ |
299 | 14.6k | if(serialno_list){ |
300 | 5.40k | if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){ |
301 | | /* a dupe serialnumber in an initial header packet set == invalid stream */ |
302 | 4 | if(*serialno_list)_ogg_free(*serialno_list); |
303 | 4 | *serialno_list=0; |
304 | 4 | *serialno_n=0; |
305 | 4 | ret=OV_EBADHEADER; |
306 | 4 | goto bail_header; |
307 | 4 | } |
308 | | |
309 | 5.39k | _add_serialno(og_ptr,serialno_list,serialno_n); |
310 | 5.39k | } |
311 | | |
312 | 14.6k | if(vf->ready_state<STREAMSET){ |
313 | | /* we don't have a vorbis stream in this link yet, so begin |
314 | | prospective stream setup. We need a stream to get packets */ |
315 | 14.3k | ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr)); |
316 | 14.3k | ogg_stream_pagein(&vf->os,og_ptr); |
317 | | |
318 | 14.3k | if(ogg_stream_packetout(&vf->os,&op) > 0 && |
319 | 14.3k | vorbis_synthesis_idheader(&op)){ |
320 | | /* vorbis header; continue setup */ |
321 | 8.05k | vf->ready_state=STREAMSET; |
322 | 8.05k | if((ret=vorbis_synthesis_headerin(vi,vc,&op))){ |
323 | 109 | ret=OV_EBADHEADER; |
324 | 109 | goto bail_header; |
325 | 109 | } |
326 | 8.05k | } |
327 | 14.3k | } |
328 | | |
329 | | /* get next page */ |
330 | 14.5k | { |
331 | 14.5k | ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE); |
332 | 14.5k | if(llret==OV_EREAD){ |
333 | 0 | ret=OV_EREAD; |
334 | 0 | goto bail_header; |
335 | 0 | } |
336 | 14.5k | if(llret<0){ |
337 | 406 | ret=OV_ENOTVORBIS; |
338 | 406 | goto bail_header; |
339 | 406 | } |
340 | | |
341 | | /* if this page also belongs to our vorbis stream, submit it and break */ |
342 | 14.1k | if(vf->ready_state==STREAMSET && |
343 | 14.1k | vf->os.serialno == ogg_page_serialno(og_ptr)){ |
344 | 7.52k | ogg_stream_pagein(&vf->os,og_ptr); |
345 | 7.52k | break; |
346 | 7.52k | } |
347 | 14.1k | } |
348 | 14.1k | } |
349 | | |
350 | 7.91k | if(vf->ready_state!=STREAMSET){ |
351 | 15 | ret = OV_ENOTVORBIS; |
352 | 15 | goto bail_header; |
353 | 15 | } |
354 | | |
355 | 7.89k | while(1){ |
356 | | |
357 | 7.89k | i=0; |
358 | 16.2k | while(i<2){ /* get a page loop */ |
359 | | |
360 | 23.6k | while(i<2){ /* get a packet loop */ |
361 | | |
362 | 17.2k | int result=ogg_stream_packetout(&vf->os,&op); |
363 | 17.2k | if(result==0)break; |
364 | 15.0k | if(result==-1){ |
365 | 51 | ret=OV_EBADHEADER; |
366 | 51 | goto bail_header; |
367 | 51 | } |
368 | | |
369 | 15.0k | if((ret=vorbis_synthesis_headerin(vi,vc,&op))) |
370 | 1.36k | goto bail_header; |
371 | | |
372 | 13.6k | i++; |
373 | 13.6k | } |
374 | | |
375 | 9.89k | while(i<2){ |
376 | 3.57k | if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ |
377 | 154 | ret=OV_EBADHEADER; |
378 | 154 | goto bail_header; |
379 | 154 | } |
380 | | |
381 | | /* if this page belongs to the correct stream, go parse it */ |
382 | 3.41k | if(vf->os.serialno == ogg_page_serialno(og_ptr)){ |
383 | 2.07k | ogg_stream_pagein(&vf->os,og_ptr); |
384 | 2.07k | break; |
385 | 2.07k | } |
386 | | |
387 | | /* if we never see the final vorbis headers before the link |
388 | | ends, abort */ |
389 | 1.34k | if(ogg_page_bos(og_ptr)){ |
390 | 131 | if(allbos){ |
391 | 3 | ret = OV_EBADHEADER; |
392 | 3 | goto bail_header; |
393 | 3 | }else |
394 | 128 | allbos=1; |
395 | 131 | } |
396 | | |
397 | | /* otherwise, keep looking */ |
398 | 1.34k | } |
399 | 8.55k | } |
400 | | |
401 | 6.32k | return 0; |
402 | 7.89k | } |
403 | | |
404 | 2.10k | bail_header: |
405 | 2.10k | vorbis_info_clear(vi); |
406 | 2.10k | vorbis_comment_clear(vc); |
407 | 2.10k | vf->ready_state=OPENED; |
408 | | |
409 | 2.10k | return ret; |
410 | 7.89k | } |
411 | | |
412 | | /* Starting from current cursor position, get initial PCM offset of |
413 | | next page. Consumes the page in the process without decoding |
414 | | audio, however this is only called during stream parsing upon |
415 | | seekable open. */ |
416 | 0 | static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ |
417 | 0 | ogg_page og; |
418 | 0 | ogg_int64_t accumulated=0; |
419 | 0 | long lastblock=-1; |
420 | 0 | int result; |
421 | 0 | int serialno = vf->os.serialno; |
422 | |
|
423 | 0 | while(1){ |
424 | 0 | ogg_packet op; |
425 | 0 | if(_get_next_page(vf,&og,-1)<0) |
426 | 0 | break; /* should not be possible unless the file is truncated/mangled */ |
427 | | |
428 | 0 | if(ogg_page_bos(&og)) break; |
429 | 0 | if(ogg_page_serialno(&og)!=serialno) continue; |
430 | | |
431 | | /* count blocksizes of all frames in the page */ |
432 | 0 | ogg_stream_pagein(&vf->os,&og); |
433 | 0 | while((result=ogg_stream_packetout(&vf->os,&op))){ |
434 | 0 | if(result>0){ /* ignore holes */ |
435 | 0 | long thisblock=vorbis_packet_blocksize(vi,&op); |
436 | 0 | if(lastblock!=-1) |
437 | 0 | accumulated+=(lastblock+thisblock)>>2; |
438 | 0 | lastblock=thisblock; |
439 | 0 | } |
440 | 0 | } |
441 | |
|
442 | 0 | if(ogg_page_granulepos(&og)!=-1){ |
443 | | /* pcm offset of last packet on the first audio page */ |
444 | 0 | accumulated= ogg_page_granulepos(&og)-accumulated; |
445 | 0 | break; |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | | /* less than zero? This is a stream with samples trimmed off |
450 | | the beginning, a normal occurrence; set the offset to zero */ |
451 | 0 | if(accumulated<0)accumulated=0; |
452 | |
|
453 | 0 | return accumulated; |
454 | 0 | } |
455 | | |
456 | | /* finds each bitstream link one at a time using a bisection search |
457 | | (has to begin by knowing the offset of the lb's initial page). |
458 | | Recurses for each link so it can alloc the link storage after |
459 | | finding them all, then unroll and fill the cache at the same time */ |
460 | | static int _bisect_forward_serialno(OggVorbis_File *vf, |
461 | | ogg_int64_t begin, |
462 | | ogg_int64_t searched, |
463 | | ogg_int64_t end, |
464 | | ogg_int64_t endgran, |
465 | | int endserial, |
466 | | ogg_uint32_t *currentno_list, |
467 | | int currentnos, |
468 | 0 | long m){ |
469 | 0 | ogg_int64_t pcmoffset; |
470 | 0 | ogg_int64_t dataoffset=searched; |
471 | 0 | ogg_int64_t endsearched=end; |
472 | 0 | ogg_int64_t next=end; |
473 | 0 | ogg_int64_t searchgran=-1; |
474 | 0 | ogg_page og; |
475 | 0 | ogg_int64_t ret,last; |
476 | 0 | int serialno = vf->os.serialno; |
477 | | |
478 | | /* invariants: |
479 | | we have the headers and serialnos for the link beginning at 'begin' |
480 | | we have the offset and granpos of the last page in the file (potentially |
481 | | not a page we care about) |
482 | | */ |
483 | | |
484 | | /* Is the last page in our list of current serialnumbers? */ |
485 | 0 | if(_lookup_serialno(endserial,currentno_list,currentnos)){ |
486 | | |
487 | | /* last page is in the starting serialno list, so we've bisected |
488 | | down to (or just started with) a single link. Now we need to |
489 | | find the last vorbis page belonging to the first vorbis stream |
490 | | for this link. */ |
491 | 0 | searched = end; |
492 | 0 | while(endserial != serialno){ |
493 | 0 | endserial = serialno; |
494 | 0 | searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran); |
495 | 0 | } |
496 | |
|
497 | 0 | vf->links=m+1; |
498 | 0 | if(vf->offsets)_ogg_free(vf->offsets); |
499 | 0 | if(vf->serialnos)_ogg_free(vf->serialnos); |
500 | 0 | if(vf->dataoffsets)_ogg_free(vf->dataoffsets); |
501 | |
|
502 | 0 | vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets)); |
503 | 0 | vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi)); |
504 | 0 | vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc)); |
505 | 0 | vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos)); |
506 | 0 | vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); |
507 | 0 | vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); |
508 | |
|
509 | 0 | vf->offsets[m+1]=end; |
510 | 0 | vf->offsets[m]=begin; |
511 | 0 | vf->pcmlengths[m*2+1]=(endgran<0?0:endgran); |
512 | |
|
513 | 0 | }else{ |
514 | | |
515 | | /* last page is not in the starting stream's serial number list, |
516 | | so we have multiple links. Find where the stream that begins |
517 | | our bisection ends. */ |
518 | |
|
519 | 0 | ogg_uint32_t *next_serialno_list=NULL; |
520 | 0 | int next_serialnos=0; |
521 | 0 | vorbis_info vi; |
522 | 0 | vorbis_comment vc; |
523 | 0 | int testserial = serialno+1; |
524 | | |
525 | | /* the below guards against garbage seperating the last and |
526 | | first pages of two links. */ |
527 | 0 | while(searched<endsearched){ |
528 | 0 | ogg_int64_t bisect; |
529 | |
|
530 | 0 | if(endsearched-searched<CHUNKSIZE){ |
531 | 0 | bisect=searched; |
532 | 0 | }else{ |
533 | 0 | bisect=(searched+endsearched)/2; |
534 | 0 | } |
535 | |
|
536 | 0 | ret=_seek_helper(vf,bisect); |
537 | 0 | if(ret)return(ret); |
538 | | |
539 | 0 | last=_get_next_page(vf,&og,-1); |
540 | 0 | if(last==OV_EREAD)return(OV_EREAD); |
541 | 0 | if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){ |
542 | 0 | endsearched=bisect; |
543 | 0 | if(last>=0)next=last; |
544 | 0 | }else{ |
545 | 0 | searched=vf->offset; |
546 | 0 | } |
547 | 0 | } |
548 | | |
549 | | /* Bisection point found */ |
550 | | /* for the time being, fetch end PCM offset the simple way */ |
551 | 0 | searched = next; |
552 | 0 | while(testserial != serialno){ |
553 | 0 | testserial = serialno; |
554 | 0 | searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran); |
555 | 0 | } |
556 | |
|
557 | 0 | ret=_seek_helper(vf,next); |
558 | 0 | if(ret)return(ret); |
559 | | |
560 | 0 | ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL); |
561 | 0 | if(ret)return(ret); |
562 | 0 | serialno = vf->os.serialno; |
563 | 0 | dataoffset = vf->offset; |
564 | | |
565 | | /* this will consume a page, however the next bisection always |
566 | | starts with a raw seek */ |
567 | 0 | pcmoffset = _initial_pcmoffset(vf,&vi); |
568 | |
|
569 | 0 | ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial, |
570 | 0 | next_serialno_list,next_serialnos,m+1); |
571 | 0 | if(ret)return(ret); |
572 | | |
573 | 0 | if(next_serialno_list)_ogg_free(next_serialno_list); |
574 | |
|
575 | 0 | vf->offsets[m+1]=next; |
576 | 0 | vf->serialnos[m+1]=serialno; |
577 | 0 | vf->dataoffsets[m+1]=dataoffset; |
578 | |
|
579 | 0 | vf->vi[m+1]=vi; |
580 | 0 | vf->vc[m+1]=vc; |
581 | |
|
582 | 0 | vf->pcmlengths[m*2+1]=searchgran; |
583 | 0 | vf->pcmlengths[m*2+2]=pcmoffset; |
584 | 0 | vf->pcmlengths[m*2+3]-=pcmoffset; |
585 | 0 | if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0; |
586 | |
|
587 | 0 | } |
588 | 0 | return(0); |
589 | 0 | } |
590 | | |
591 | 6.32k | static int _make_decode_ready(OggVorbis_File *vf){ |
592 | 6.32k | if(vf->ready_state>STREAMSET)return 0; |
593 | 6.32k | if(vf->ready_state<STREAMSET)return OV_EFAULT; |
594 | 6.32k | if(vf->seekable){ |
595 | 0 | if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link)) |
596 | 0 | return OV_EBADLINK; |
597 | 6.32k | }else{ |
598 | 6.32k | if(vorbis_synthesis_init(&vf->vd,vf->vi)) |
599 | 111 | return OV_EBADLINK; |
600 | 6.32k | } |
601 | 6.21k | vorbis_block_init(&vf->vd,&vf->vb); |
602 | 6.21k | vf->ready_state=INITSET; |
603 | 6.21k | vf->bittrack=0; |
604 | 6.21k | vf->samptrack=0; |
605 | 6.21k | return 0; |
606 | 6.32k | } |
607 | | |
608 | 0 | static int _open_seekable2(OggVorbis_File *vf){ |
609 | 0 | ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1; |
610 | 0 | int endserial=vf->os.serialno; |
611 | 0 | int serialno=vf->os.serialno; |
612 | | |
613 | | /* we're partially open and have a first link header state in |
614 | | storage in vf */ |
615 | | |
616 | | /* fetch initial PCM offset */ |
617 | 0 | ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi); |
618 | | |
619 | | /* we can seek, so set out learning all about this file */ |
620 | 0 | if(vf->callbacks.seek_func && vf->callbacks.tell_func){ |
621 | 0 | (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); |
622 | 0 | vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); |
623 | 0 | }else{ |
624 | 0 | vf->offset=vf->end=-1; |
625 | 0 | } |
626 | | |
627 | | /* If seek_func is implemented, tell_func must also be implemented */ |
628 | 0 | if(vf->end==-1) return(OV_EINVAL); |
629 | | |
630 | | /* Get the offset of the last page of the physical bitstream, or, if |
631 | | we're lucky the last vorbis page of this link as most OggVorbis |
632 | | files will contain a single logical bitstream */ |
633 | 0 | end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran); |
634 | 0 | if(end<0)return(end); |
635 | | |
636 | | /* now determine bitstream structure recursively */ |
637 | 0 | if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial, |
638 | 0 | vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD); |
639 | | |
640 | 0 | vf->offsets[0]=0; |
641 | 0 | vf->serialnos[0]=serialno; |
642 | 0 | vf->dataoffsets[0]=dataoffset; |
643 | 0 | vf->pcmlengths[0]=pcmoffset; |
644 | 0 | vf->pcmlengths[1]-=pcmoffset; |
645 | 0 | if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0; |
646 | |
|
647 | 0 | return(ov_raw_seek(vf,dataoffset)); |
648 | 0 | } |
649 | | |
650 | | /* clear out the current logical bitstream decoder */ |
651 | 4.14k | static void _decode_clear(OggVorbis_File *vf){ |
652 | 4.14k | vorbis_dsp_clear(&vf->vd); |
653 | 4.14k | vorbis_block_clear(&vf->vb); |
654 | 4.14k | vf->ready_state=OPENED; |
655 | 4.14k | } |
656 | | |
657 | | /* fetch and process a packet. Handles the case where we're at a |
658 | | bitstream boundary and dumps the decoding machine. If the decoding |
659 | | machine is unloaded, it loads it. It also keeps pcm_offset up to |
660 | | date (seek and read both use this. seek uses a special hack with |
661 | | readp). |
662 | | |
663 | | return: <0) error, OV_HOLE (lost packet) or OV_EOF |
664 | | 0) need more data (only if readp==0) |
665 | | 1) got a packet |
666 | | */ |
667 | | |
668 | | static int _fetch_and_process_packet(OggVorbis_File *vf, |
669 | | ogg_packet *op_in, |
670 | | int readp, |
671 | 43.3k | int spanp){ |
672 | 43.3k | ogg_page og; |
673 | | |
674 | | /* handle one packet. Try to fetch it from current stream state */ |
675 | | /* extract packets from page */ |
676 | 54.3k | while(1){ |
677 | | |
678 | 54.3k | if(vf->ready_state==STREAMSET){ |
679 | 6.32k | int ret=_make_decode_ready(vf); |
680 | 6.32k | if(ret<0)return ret; |
681 | 6.32k | } |
682 | | |
683 | | /* process a packet if we can. If the machine isn't loaded, |
684 | | neither is a page */ |
685 | 54.2k | if(vf->ready_state==INITSET){ |
686 | 118k | while(1) { |
687 | 118k | ogg_packet op; |
688 | 118k | ogg_packet *op_ptr=(op_in?op_in:&op); |
689 | 118k | int result=ogg_stream_packetout(&vf->os,op_ptr); |
690 | 118k | ogg_int64_t granulepos; |
691 | | |
692 | 118k | op_in=NULL; |
693 | 118k | if(result==-1)return(OV_HOLE); /* hole in the data. */ |
694 | 109k | if(result>0){ |
695 | | /* got a packet. process it */ |
696 | 96.2k | granulepos=op_ptr->granulepos; |
697 | 96.2k | if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy |
698 | | header handling. The |
699 | | header packets aren't |
700 | | audio, so if/when we |
701 | | submit them, |
702 | | vorbis_synthesis will |
703 | | reject them */ |
704 | | |
705 | | /* suck in the synthesis data and track bitrate */ |
706 | 32.4k | { |
707 | 32.4k | int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); |
708 | | /* for proper use of libvorbis within libvorbisfile, |
709 | | oldsamples will always be zero. */ |
710 | 32.4k | if(oldsamples)return(OV_EFAULT); |
711 | | |
712 | 32.4k | vorbis_synthesis_blockin(&vf->vd,&vf->vb); |
713 | 32.4k | vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL); |
714 | 32.4k | vf->bittrack+=op_ptr->bytes*8; |
715 | 32.4k | } |
716 | | |
717 | | /* update the pcm offset. */ |
718 | 32.4k | if(granulepos!=-1 && !op_ptr->e_o_s){ |
719 | 5.07k | int link=(vf->seekable?vf->current_link:0); |
720 | 5.07k | int i,samples; |
721 | | |
722 | | /* this packet has a pcm_offset on it (the last packet |
723 | | completed on a page carries the offset) After processing |
724 | | (above), we know the pcm position of the *last* sample |
725 | | ready to be returned. Find the offset of the *first* |
726 | | |
727 | | As an aside, this trick is inaccurate if we begin |
728 | | reading anew right at the last page; the end-of-stream |
729 | | granulepos declares the last frame in the stream, and the |
730 | | last packet of the last page may be a partial frame. |
731 | | So, we need a previous granulepos from an in-sequence page |
732 | | to have a reference point. Thus the !op_ptr->e_o_s clause |
733 | | above */ |
734 | | |
735 | 5.07k | if(vf->seekable && link>0) |
736 | 0 | granulepos-=vf->pcmlengths[link*2]; |
737 | 5.07k | if(granulepos<0)granulepos=0; /* actually, this |
738 | | shouldn't be possible |
739 | | here unless the stream |
740 | | is very broken */ |
741 | | |
742 | 5.07k | samples=vorbis_synthesis_pcmout(&vf->vd,NULL); |
743 | | |
744 | 5.07k | granulepos-=samples; |
745 | 5.07k | for(i=0;i<link;i++) |
746 | 0 | granulepos+=vf->pcmlengths[i*2+1]; |
747 | 5.07k | vf->pcm_offset=granulepos; |
748 | 5.07k | } |
749 | 32.4k | return(1); |
750 | 32.4k | } |
751 | 96.2k | } |
752 | 13.3k | else |
753 | 13.3k | break; |
754 | 109k | } |
755 | 54.2k | } |
756 | | |
757 | 13.3k | if(vf->ready_state>=OPENED){ |
758 | 13.3k | ogg_int64_t ret; |
759 | | |
760 | 13.9k | while(1){ |
761 | | /* the loop is not strictly necessary, but there's no sense in |
762 | | doing the extra checks of the larger loop for the common |
763 | | case in a multiplexed bistream where the page is simply |
764 | | part of a different logical bitstream; keep reading until |
765 | | we get one with the correct serialno */ |
766 | | |
767 | 13.9k | if(!readp)return(0); |
768 | 13.9k | if((ret=_get_next_page(vf,&og,-1))<0){ |
769 | 2.06k | return(OV_EOF); /* eof. leave unitialized */ |
770 | 2.06k | } |
771 | | |
772 | | /* bitrate tracking; add the header's bytes here, the body bytes |
773 | | are done by packet above */ |
774 | 11.8k | vf->bittrack+=og.header_len*8; |
775 | | |
776 | 11.8k | if(vf->ready_state==INITSET){ |
777 | 11.8k | if(vf->current_serialno!=ogg_page_serialno(&og)){ |
778 | | |
779 | | /* two possibilities: |
780 | | 1) our decoding just traversed a bitstream boundary |
781 | | 2) another stream is multiplexed into this logical section */ |
782 | | |
783 | 4.72k | if(ogg_page_bos(&og)){ |
784 | | /* boundary case */ |
785 | 4.14k | if(!spanp) |
786 | 0 | return(OV_EOF); |
787 | | |
788 | 4.14k | _decode_clear(vf); |
789 | | |
790 | 4.14k | if(!vf->seekable){ |
791 | 4.14k | vorbis_info_clear(vf->vi); |
792 | 4.14k | vorbis_comment_clear(vf->vc); |
793 | 4.14k | } |
794 | 4.14k | break; |
795 | | |
796 | 4.14k | }else |
797 | 571 | continue; /* possibility #2 */ |
798 | 4.72k | } |
799 | 11.8k | } |
800 | | |
801 | 7.12k | break; |
802 | 11.8k | } |
803 | 13.3k | } |
804 | | |
805 | | /* Do we need to load a new machine before submitting the page? */ |
806 | | /* This is different in the seekable and non-seekable cases. |
807 | | |
808 | | In the seekable case, we already have all the header |
809 | | information loaded and cached; we just initialize the machine |
810 | | with it and continue on our merry way. |
811 | | |
812 | | In the non-seekable (streaming) case, we'll only be at a |
813 | | boundary if we just left the previous logical bitstream and |
814 | | we're now nominally at the header of the next bitstream |
815 | | */ |
816 | | |
817 | 11.2k | if(vf->ready_state!=INITSET){ |
818 | 4.14k | int link; |
819 | | |
820 | 4.14k | if(vf->ready_state<STREAMSET){ |
821 | 4.14k | if(vf->seekable){ |
822 | 0 | ogg_uint32_t serialno = ogg_page_serialno(&og); |
823 | | |
824 | | /* match the serialno to bitstream section. We use this rather than |
825 | | offset positions to avoid problems near logical bitstream |
826 | | boundaries */ |
827 | |
|
828 | 0 | for(link=0;link<vf->links;link++) |
829 | 0 | if(vf->serialnos[link]==serialno)break; |
830 | |
|
831 | 0 | if(link==vf->links) continue; /* not the desired Vorbis |
832 | | bitstream section; keep |
833 | | trying */ |
834 | | |
835 | 0 | vf->current_serialno=serialno; |
836 | 0 | vf->current_link=link; |
837 | |
|
838 | 0 | ogg_stream_reset_serialno(&vf->os,vf->current_serialno); |
839 | 0 | vf->ready_state=STREAMSET; |
840 | |
|
841 | 4.14k | }else{ |
842 | | /* we're streaming */ |
843 | | /* fetch the three header packets, build the info struct */ |
844 | | |
845 | 4.14k | int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og); |
846 | 4.14k | if(ret)return(ret); |
847 | 3.91k | vf->current_serialno=vf->os.serialno; |
848 | 3.91k | vf->current_link++; |
849 | 3.91k | link=0; |
850 | 3.91k | } |
851 | 4.14k | } |
852 | 4.14k | } |
853 | | |
854 | | /* the buffered page is the data we want, and we're ready for it; |
855 | | add it to the stream state */ |
856 | 11.0k | ogg_stream_pagein(&vf->os,&og); |
857 | | |
858 | 11.0k | } |
859 | 43.3k | } |
860 | | |
861 | | /* if, eg, 64 bit stdio is configured by default, this will build with |
862 | | fseek64 */ |
863 | 0 | static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ |
864 | 0 | if(f==NULL)return(-1); |
865 | 0 | return fseek(f,off,whence); |
866 | 0 | } |
867 | | |
868 | | static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, |
869 | 4.35k | long ibytes, ov_callbacks callbacks){ |
870 | 4.35k | int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); |
871 | 4.35k | ogg_uint32_t *serialno_list=NULL; |
872 | 4.35k | int serialno_list_size=0; |
873 | 4.35k | int ret; |
874 | | |
875 | 4.35k | memset(vf,0,sizeof(*vf)); |
876 | 4.35k | vf->datasource=f; |
877 | 4.35k | vf->callbacks = callbacks; |
878 | | |
879 | | /* init the framing state */ |
880 | 4.35k | ogg_sync_init(&vf->oy); |
881 | | |
882 | | /* perhaps some data was previously read into a buffer for testing |
883 | | against other stream types. Allow initialization from this |
884 | | previously read data (especially as we may be reading from a |
885 | | non-seekable stream) */ |
886 | 4.35k | if(initial){ |
887 | 0 | char *buffer=ogg_sync_buffer(&vf->oy,ibytes); |
888 | 0 | memcpy(buffer,initial,ibytes); |
889 | 0 | ogg_sync_wrote(&vf->oy,ibytes); |
890 | 0 | } |
891 | | |
892 | | /* can we seek? Stevens suggests the seek test was portable */ |
893 | 4.35k | if(offsettest!=-1)vf->seekable=1; |
894 | | |
895 | | /* No seeking yet; Set up a 'single' (current) logical bitstream |
896 | | entry for partial open */ |
897 | 4.35k | vf->links=1; |
898 | 4.35k | vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); |
899 | 4.35k | vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); |
900 | 4.35k | ogg_stream_init(&vf->os,-1); /* fill in the serialno later */ |
901 | | |
902 | | /* Fetch all BOS pages, store the vorbis header and all seen serial |
903 | | numbers, load subsequent vorbis setup headers */ |
904 | 4.35k | if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){ |
905 | 1.94k | vf->datasource=NULL; |
906 | 1.94k | ov_clear(vf); |
907 | 2.40k | }else{ |
908 | | /* serial number list for first link needs to be held somewhere |
909 | | for second stage of seekable stream open; this saves having to |
910 | | seek/reread first link's serialnumber data then. */ |
911 | 2.40k | vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos)); |
912 | 2.40k | vf->serialnos[0]=vf->current_serialno=vf->os.serialno; |
913 | 2.40k | vf->serialnos[1]=serialno_list_size; |
914 | 2.40k | memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos)); |
915 | | |
916 | 2.40k | vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets)); |
917 | 2.40k | vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets)); |
918 | 2.40k | vf->offsets[0]=0; |
919 | 2.40k | vf->dataoffsets[0]=vf->offset; |
920 | | |
921 | 2.40k | vf->ready_state=PARTOPEN; |
922 | 2.40k | } |
923 | 4.35k | if(serialno_list)_ogg_free(serialno_list); |
924 | 4.35k | return(ret); |
925 | 4.35k | } |
926 | | |
927 | 2.40k | static int _ov_open2(OggVorbis_File *vf){ |
928 | 2.40k | if(vf->ready_state != PARTOPEN) return OV_EINVAL; |
929 | 2.40k | vf->ready_state=OPENED; |
930 | 2.40k | if(vf->seekable){ |
931 | 0 | int ret=_open_seekable2(vf); |
932 | 0 | if(ret){ |
933 | 0 | vf->datasource=NULL; |
934 | 0 | ov_clear(vf); |
935 | 0 | } |
936 | 0 | return(ret); |
937 | 0 | }else |
938 | 2.40k | vf->ready_state=STREAMSET; |
939 | | |
940 | 2.40k | return 0; |
941 | 2.40k | } |
942 | | |
943 | | |
944 | | /* clear out the OggVorbis_File struct */ |
945 | 4.35k | int ov_clear(OggVorbis_File *vf){ |
946 | 4.35k | if(vf){ |
947 | 4.35k | vorbis_block_clear(&vf->vb); |
948 | 4.35k | vorbis_dsp_clear(&vf->vd); |
949 | 4.35k | ogg_stream_clear(&vf->os); |
950 | | |
951 | 4.35k | if(vf->vi && vf->links){ |
952 | 4.35k | int i; |
953 | 8.71k | for(i=0;i<vf->links;i++){ |
954 | 4.35k | vorbis_info_clear(vf->vi+i); |
955 | 4.35k | vorbis_comment_clear(vf->vc+i); |
956 | 4.35k | } |
957 | 4.35k | _ogg_free(vf->vi); |
958 | 4.35k | _ogg_free(vf->vc); |
959 | 4.35k | } |
960 | 4.35k | if(vf->dataoffsets)_ogg_free(vf->dataoffsets); |
961 | 4.35k | if(vf->pcmlengths)_ogg_free(vf->pcmlengths); |
962 | 4.35k | if(vf->serialnos)_ogg_free(vf->serialnos); |
963 | 4.35k | if(vf->offsets)_ogg_free(vf->offsets); |
964 | 4.35k | ogg_sync_clear(&vf->oy); |
965 | 4.35k | if(vf->datasource && vf->callbacks.close_func) |
966 | 0 | (vf->callbacks.close_func)(vf->datasource); |
967 | 4.35k | memset(vf,0,sizeof(*vf)); |
968 | 4.35k | } |
969 | | #ifdef DEBUG_LEAKS |
970 | | _VDBG_dump(); |
971 | | #endif |
972 | 4.35k | return(0); |
973 | 4.35k | } |
974 | | |
975 | | /* inspects the OggVorbis file and finds/documents all the logical |
976 | | bitstreams contained in it. Tries to be tolerant of logical |
977 | | bitstream sections that are truncated/woogie. |
978 | | |
979 | | return: -1) error |
980 | | 0) OK |
981 | | */ |
982 | | |
983 | | int ov_open_callbacks(void *f,OggVorbis_File *vf, |
984 | 4.35k | const char *initial,long ibytes,ov_callbacks callbacks){ |
985 | 4.35k | int ret=_ov_open1(f,vf,initial,ibytes,callbacks); |
986 | 4.35k | if(ret)return ret; |
987 | 2.40k | return _ov_open2(vf); |
988 | 4.35k | } |
989 | | |
990 | 0 | int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ |
991 | 0 | ov_callbacks callbacks = { |
992 | 0 | (size_t (*)(void *, size_t, size_t, void *)) fread, |
993 | 0 | (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, |
994 | 0 | (int (*)(void *)) fclose, |
995 | 0 | (long (*)(void *)) ftell |
996 | 0 | }; |
997 | |
|
998 | 0 | return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); |
999 | 0 | } |
1000 | | |
1001 | 0 | int ov_fopen(const char *path,OggVorbis_File *vf){ |
1002 | 0 | int ret; |
1003 | 0 | FILE *f = fopen(path,"rb"); |
1004 | 0 | if(!f) return -1; |
1005 | | |
1006 | 0 | ret = ov_open(f,vf,NULL,0); |
1007 | 0 | if(ret) fclose(f); |
1008 | 0 | return ret; |
1009 | 0 | } |
1010 | | |
1011 | | |
1012 | | /* Only partially open the vorbis file; test for Vorbisness, and load |
1013 | | the headers for the first chain. Do not seek (although test for |
1014 | | seekability). Use ov_test_open to finish opening the file, else |
1015 | | ov_clear to close/free it. Same return codes as open. */ |
1016 | | |
1017 | | int ov_test_callbacks(void *f,OggVorbis_File *vf, |
1018 | | const char *initial,long ibytes,ov_callbacks callbacks) |
1019 | 0 | { |
1020 | 0 | return _ov_open1(f,vf,initial,ibytes,callbacks); |
1021 | 0 | } |
1022 | | |
1023 | 0 | int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ |
1024 | 0 | ov_callbacks callbacks = { |
1025 | 0 | (size_t (*)(void *, size_t, size_t, void *)) fread, |
1026 | 0 | (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, |
1027 | 0 | (int (*)(void *)) fclose, |
1028 | 0 | (long (*)(void *)) ftell |
1029 | 0 | }; |
1030 | |
|
1031 | 0 | return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); |
1032 | 0 | } |
1033 | | |
1034 | 0 | int ov_test_open(OggVorbis_File *vf){ |
1035 | 0 | if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); |
1036 | 0 | return _ov_open2(vf); |
1037 | 0 | } |
1038 | | |
1039 | | /* How many logical bitstreams in this physical bitstream? */ |
1040 | 0 | long ov_streams(OggVorbis_File *vf){ |
1041 | 0 | return vf->links; |
1042 | 0 | } |
1043 | | |
1044 | | /* Is the FILE * associated with vf seekable? */ |
1045 | 0 | long ov_seekable(OggVorbis_File *vf){ |
1046 | 0 | return vf->seekable; |
1047 | 0 | } |
1048 | | |
1049 | | /* returns the bitrate for a given logical bitstream or the entire |
1050 | | physical bitstream. If the file is open for random access, it will |
1051 | | find the *actual* average bitrate. If the file is streaming, it |
1052 | | returns the nominal bitrate (if set) else the average of the |
1053 | | upper/lower bounds (if set) else -1 (unset). |
1054 | | |
1055 | | If you want the actual bitrate field settings, get them from the |
1056 | | vorbis_info structs */ |
1057 | | |
1058 | 0 | long ov_bitrate(OggVorbis_File *vf,int i){ |
1059 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1060 | 0 | if(i>=vf->links)return(OV_EINVAL); |
1061 | 0 | if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); |
1062 | 0 | if(i<0){ |
1063 | 0 | ogg_int64_t bits=0; |
1064 | 0 | int i; |
1065 | 0 | for(i=0;i<vf->links;i++) |
1066 | 0 | bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; |
1067 | | /* This once read: return(rint(bits/ov_time_total(vf,-1))); |
1068 | | * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, |
1069 | | * so this is slightly transformed to make it work. |
1070 | | */ |
1071 | 0 | return(bits*1000/ov_time_total(vf,-1)); |
1072 | 0 | }else{ |
1073 | 0 | if(vf->seekable){ |
1074 | | /* return the actual bitrate */ |
1075 | 0 | return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i)); |
1076 | 0 | }else{ |
1077 | | /* return nominal if set */ |
1078 | 0 | if(vf->vi[i].bitrate_nominal>0){ |
1079 | 0 | return vf->vi[i].bitrate_nominal; |
1080 | 0 | }else{ |
1081 | 0 | if(vf->vi[i].bitrate_upper>0){ |
1082 | 0 | if(vf->vi[i].bitrate_lower>0){ |
1083 | 0 | return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; |
1084 | 0 | }else{ |
1085 | 0 | return vf->vi[i].bitrate_upper; |
1086 | 0 | } |
1087 | 0 | } |
1088 | 0 | return(OV_FALSE); |
1089 | 0 | } |
1090 | 0 | } |
1091 | 0 | } |
1092 | 0 | } |
1093 | | |
1094 | | /* returns the actual bitrate since last call. returns -1 if no |
1095 | | additional data to offer since last call (or at beginning of stream), |
1096 | | EINVAL if stream is only partially open |
1097 | | */ |
1098 | 0 | long ov_bitrate_instant(OggVorbis_File *vf){ |
1099 | 0 | int link=(vf->seekable?vf->current_link:0); |
1100 | 0 | long ret; |
1101 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1102 | 0 | if(vf->samptrack==0)return(OV_FALSE); |
1103 | 0 | ret=vf->bittrack/vf->samptrack*vf->vi[link].rate; |
1104 | 0 | vf->bittrack=0; |
1105 | 0 | vf->samptrack=0; |
1106 | 0 | return(ret); |
1107 | 0 | } |
1108 | | |
1109 | | /* Guess */ |
1110 | 0 | long ov_serialnumber(OggVorbis_File *vf,int i){ |
1111 | 0 | if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); |
1112 | 0 | if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); |
1113 | 0 | if(i<0){ |
1114 | 0 | return(vf->current_serialno); |
1115 | 0 | }else{ |
1116 | 0 | return(vf->serialnos[i]); |
1117 | 0 | } |
1118 | 0 | } |
1119 | | |
1120 | | /* returns: total raw (compressed) length of content if i==-1 |
1121 | | raw (compressed) length of that logical bitstream for i==0 to n |
1122 | | OV_EINVAL if the stream is not seekable (we can't know the length) |
1123 | | or if stream is only partially open |
1124 | | */ |
1125 | 0 | ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ |
1126 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1127 | 0 | if(!vf->seekable || i>=vf->links)return(OV_EINVAL); |
1128 | 0 | if(i<0){ |
1129 | 0 | ogg_int64_t acc=0; |
1130 | 0 | int i; |
1131 | 0 | for(i=0;i<vf->links;i++) |
1132 | 0 | acc+=ov_raw_total(vf,i); |
1133 | 0 | return(acc); |
1134 | 0 | }else{ |
1135 | 0 | return(vf->offsets[i+1]-vf->offsets[i]); |
1136 | 0 | } |
1137 | 0 | } |
1138 | | |
1139 | | /* returns: total PCM length (samples) of content if i==-1 PCM length |
1140 | | (samples) of that logical bitstream for i==0 to n |
1141 | | OV_EINVAL if the stream is not seekable (we can't know the |
1142 | | length) or only partially open |
1143 | | */ |
1144 | 0 | ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ |
1145 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1146 | 0 | if(!vf->seekable || i>=vf->links)return(OV_EINVAL); |
1147 | 0 | if(i<0){ |
1148 | 0 | ogg_int64_t acc=0; |
1149 | 0 | int i; |
1150 | 0 | for(i=0;i<vf->links;i++) |
1151 | 0 | acc+=ov_pcm_total(vf,i); |
1152 | 0 | return(acc); |
1153 | 0 | }else{ |
1154 | 0 | return(vf->pcmlengths[i*2+1]); |
1155 | 0 | } |
1156 | 0 | } |
1157 | | |
1158 | | /* returns: total milliseconds of content if i==-1 |
1159 | | milliseconds in that logical bitstream for i==0 to n |
1160 | | OV_EINVAL if the stream is not seekable (we can't know the |
1161 | | length) or only partially open |
1162 | | */ |
1163 | 0 | ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){ |
1164 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1165 | 0 | if(!vf->seekable || i>=vf->links)return(OV_EINVAL); |
1166 | 0 | if(i<0){ |
1167 | 0 | ogg_int64_t acc=0; |
1168 | 0 | int i; |
1169 | 0 | for(i=0;i<vf->links;i++) |
1170 | 0 | acc+=ov_time_total(vf,i); |
1171 | 0 | return(acc); |
1172 | 0 | }else{ |
1173 | 0 | return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate); |
1174 | 0 | } |
1175 | 0 | } |
1176 | | |
1177 | | /* seek to an offset relative to the *compressed* data. This also |
1178 | | scans packets to update the PCM cursor. It will cross a logical |
1179 | | bitstream boundary, but only if it can't get any packets out of the |
1180 | | tail of the bitstream we seek to (so no surprises). |
1181 | | |
1182 | | returns zero on success, nonzero on failure */ |
1183 | | |
1184 | 0 | int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ |
1185 | 0 | ogg_stream_state work_os; |
1186 | 0 | int ret; |
1187 | |
|
1188 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1189 | 0 | if(!vf->seekable) |
1190 | 0 | return(OV_ENOSEEK); /* don't dump machine if we can't seek */ |
1191 | | |
1192 | 0 | if(pos<0 || pos>vf->end)return(OV_EINVAL); |
1193 | | |
1194 | | /* is the seek position outside our current link [if any]? */ |
1195 | 0 | if(vf->ready_state>=STREAMSET){ |
1196 | 0 | if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1]) |
1197 | 0 | _decode_clear(vf); /* clear out stream state */ |
1198 | 0 | } |
1199 | | |
1200 | | /* don't yet clear out decoding machine (if it's initialized), in |
1201 | | the case we're in the same link. Restart the decode lapping, and |
1202 | | let _fetch_and_process_packet deal with a potential bitstream |
1203 | | boundary */ |
1204 | 0 | vf->pcm_offset=-1; |
1205 | 0 | ogg_stream_reset_serialno(&vf->os, |
1206 | 0 | vf->current_serialno); /* must set serialno */ |
1207 | 0 | vorbis_synthesis_restart(&vf->vd); |
1208 | |
|
1209 | 0 | ret=_seek_helper(vf,pos); |
1210 | 0 | if(ret)goto seek_error; |
1211 | | |
1212 | | /* we need to make sure the pcm_offset is set, but we don't want to |
1213 | | advance the raw cursor past good packets just to get to the first |
1214 | | with a granulepos. That's not equivalent behavior to beginning |
1215 | | decoding as immediately after the seek position as possible. |
1216 | | |
1217 | | So, a hack. We use two stream states; a local scratch state and |
1218 | | the shared vf->os stream state. We use the local state to |
1219 | | scan, and the shared state as a buffer for later decode. |
1220 | | |
1221 | | Unfortuantely, on the last page we still advance to last packet |
1222 | | because the granulepos on the last page is not necessarily on a |
1223 | | packet boundary, and we need to make sure the granpos is |
1224 | | correct. |
1225 | | */ |
1226 | | |
1227 | 0 | { |
1228 | 0 | ogg_page og; |
1229 | 0 | ogg_packet op; |
1230 | 0 | int lastblock=0; |
1231 | 0 | int accblock=0; |
1232 | 0 | int thisblock=0; |
1233 | 0 | int lastflag=0; |
1234 | 0 | int firstflag=0; |
1235 | 0 | ogg_int64_t pagepos=-1; |
1236 | |
|
1237 | 0 | ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */ |
1238 | 0 | ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE |
1239 | | return from not necessarily |
1240 | | starting from the beginning */ |
1241 | |
|
1242 | 0 | while(1){ |
1243 | 0 | if(vf->ready_state>=STREAMSET){ |
1244 | | /* snarf/scan a packet if we can */ |
1245 | 0 | int result=ogg_stream_packetout(&work_os,&op); |
1246 | |
|
1247 | 0 | if(result>0){ |
1248 | |
|
1249 | 0 | if(vf->vi[vf->current_link].codec_setup){ |
1250 | 0 | thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); |
1251 | 0 | if(thisblock<0){ |
1252 | 0 | ogg_stream_packetout(&vf->os,NULL); |
1253 | 0 | thisblock=0; |
1254 | 0 | }else{ |
1255 | | |
1256 | | /* We can't get a guaranteed correct pcm position out of the |
1257 | | last page in a stream because it might have a 'short' |
1258 | | granpos, which can only be detected in the presence of a |
1259 | | preceding page. However, if the last page is also the first |
1260 | | page, the granpos rules of a first page take precedence. Not |
1261 | | only that, but for first==last, the EOS page must be treated |
1262 | | as if its a normal first page for the stream to open/play. */ |
1263 | 0 | if(lastflag && !firstflag) |
1264 | 0 | ogg_stream_packetout(&vf->os,NULL); |
1265 | 0 | else |
1266 | 0 | if(lastblock)accblock+=(lastblock+thisblock)>>2; |
1267 | 0 | } |
1268 | |
|
1269 | 0 | if(op.granulepos!=-1){ |
1270 | 0 | int i,link=vf->current_link; |
1271 | 0 | ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; |
1272 | 0 | if(granulepos<0)granulepos=0; |
1273 | |
|
1274 | 0 | for(i=0;i<link;i++) |
1275 | 0 | granulepos+=vf->pcmlengths[i*2+1]; |
1276 | 0 | vf->pcm_offset=granulepos-accblock; |
1277 | 0 | if(vf->pcm_offset<0)vf->pcm_offset=0; |
1278 | 0 | break; |
1279 | 0 | } |
1280 | 0 | lastblock=thisblock; |
1281 | 0 | continue; |
1282 | 0 | }else |
1283 | 0 | ogg_stream_packetout(&vf->os,NULL); |
1284 | 0 | } |
1285 | 0 | } |
1286 | | |
1287 | 0 | if(!lastblock){ |
1288 | 0 | pagepos=_get_next_page(vf,&og,-1); |
1289 | 0 | if(pagepos<0){ |
1290 | 0 | vf->pcm_offset=ov_pcm_total(vf,-1); |
1291 | 0 | break; |
1292 | 0 | } |
1293 | 0 | }else{ |
1294 | | /* huh? Bogus stream with packets but no granulepos */ |
1295 | 0 | vf->pcm_offset=-1; |
1296 | 0 | break; |
1297 | 0 | } |
1298 | | |
1299 | | /* has our decoding just traversed a bitstream boundary? */ |
1300 | 0 | if(vf->ready_state>=STREAMSET){ |
1301 | 0 | if(vf->current_serialno!=ogg_page_serialno(&og)){ |
1302 | | |
1303 | | /* two possibilities: |
1304 | | 1) our decoding just traversed a bitstream boundary |
1305 | | 2) another stream is multiplexed into this logical section? */ |
1306 | |
|
1307 | 0 | if(ogg_page_bos(&og)){ |
1308 | | /* we traversed */ |
1309 | 0 | _decode_clear(vf); /* clear out stream state */ |
1310 | 0 | ogg_stream_clear(&work_os); |
1311 | 0 | } /* else, do nothing; next loop will scoop another page */ |
1312 | 0 | } |
1313 | 0 | } |
1314 | |
|
1315 | 0 | if(vf->ready_state<STREAMSET){ |
1316 | 0 | int link; |
1317 | 0 | ogg_uint32_t serialno = ogg_page_serialno(&og); |
1318 | |
|
1319 | 0 | for(link=0;link<vf->links;link++) |
1320 | 0 | if(vf->serialnos[link]==serialno)break; |
1321 | |
|
1322 | 0 | if(link==vf->links) continue; /* not the desired Vorbis |
1323 | | bitstream section; keep |
1324 | | trying */ |
1325 | 0 | vf->current_link=link; |
1326 | 0 | vf->current_serialno=serialno; |
1327 | 0 | ogg_stream_reset_serialno(&vf->os,serialno); |
1328 | 0 | ogg_stream_reset_serialno(&work_os,serialno); |
1329 | 0 | vf->ready_state=STREAMSET; |
1330 | 0 | firstflag=(pagepos<=vf->dataoffsets[link]); |
1331 | 0 | } |
1332 | | |
1333 | 0 | ogg_stream_pagein(&vf->os,&og); |
1334 | 0 | ogg_stream_pagein(&work_os,&og); |
1335 | 0 | lastflag=ogg_page_eos(&og); |
1336 | |
|
1337 | 0 | } |
1338 | 0 | } |
1339 | |
|
1340 | 0 | ogg_stream_clear(&work_os); |
1341 | 0 | vf->bittrack=0; |
1342 | 0 | vf->samptrack=0; |
1343 | 0 | return(0); |
1344 | | |
1345 | 0 | seek_error: |
1346 | | /* dump the machine so we're in a known state */ |
1347 | 0 | vf->pcm_offset=-1; |
1348 | 0 | ogg_stream_clear(&work_os); |
1349 | 0 | _decode_clear(vf); |
1350 | 0 | return OV_EBADLINK; |
1351 | 0 | } |
1352 | | |
1353 | | /* rescales the number x from the range of [0,from] to [0,to] |
1354 | | x is in the range [0,from] |
1355 | | from, to are in the range [1, 1<<62-1] */ |
1356 | 0 | ogg_int64_t rescale64(ogg_int64_t x, ogg_int64_t from, ogg_int64_t to){ |
1357 | 0 | ogg_int64_t frac=0; |
1358 | 0 | ogg_int64_t ret=0; |
1359 | 0 | int i; |
1360 | 0 | if(x >= from) return to; |
1361 | 0 | if(x <= 0) return 0; |
1362 | | |
1363 | 0 | for(i=0;i<64;i++){ |
1364 | 0 | if(x>=from){ |
1365 | 0 | frac|=1; |
1366 | 0 | x-=from; |
1367 | 0 | } |
1368 | 0 | x<<=1; |
1369 | 0 | frac<<=1; |
1370 | 0 | } |
1371 | |
|
1372 | 0 | for(i=0;i<64;i++){ |
1373 | 0 | if(frac & 1){ |
1374 | 0 | ret+=to; |
1375 | 0 | } |
1376 | 0 | frac>>=1; |
1377 | 0 | ret>>=1; |
1378 | 0 | } |
1379 | |
|
1380 | 0 | return ret; |
1381 | 0 | } |
1382 | | |
1383 | | /* Page granularity seek (faster than sample granularity because we |
1384 | | don't do the last bit of decode to find a specific sample). |
1385 | | |
1386 | | Seek to the last [granule marked] page preceding the specified pos |
1387 | | location, such that decoding past the returned point will quickly |
1388 | | arrive at the requested position. */ |
1389 | 0 | int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ |
1390 | 0 | int link=-1; |
1391 | 0 | ogg_int64_t result=0; |
1392 | 0 | ogg_int64_t total=ov_pcm_total(vf,-1); |
1393 | |
|
1394 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1395 | 0 | if(!vf->seekable)return(OV_ENOSEEK); |
1396 | | |
1397 | 0 | if(pos<0 || pos>total)return(OV_EINVAL); |
1398 | | |
1399 | | /* which bitstream section does this pcm offset occur in? */ |
1400 | 0 | for(link=vf->links-1;link>=0;link--){ |
1401 | 0 | total-=vf->pcmlengths[link*2+1]; |
1402 | 0 | if(pos>=total)break; |
1403 | 0 | } |
1404 | | |
1405 | | /* Search within the logical bitstream for the page with the highest |
1406 | | pcm_pos preceding pos. If we're looking for a position on the |
1407 | | first page, bisection will halt without finding our position as |
1408 | | it's before the first explicit granulepos fencepost. That case is |
1409 | | handled separately below. |
1410 | | |
1411 | | There is a danger here; missing pages or incorrect frame number |
1412 | | information in the bitstream could make our task impossible. |
1413 | | Account for that (it would be an error condition) */ |
1414 | | |
1415 | | /* new search algorithm originally by HB (Nicholas Vinen) */ |
1416 | |
|
1417 | 0 | { |
1418 | 0 | ogg_int64_t end=vf->offsets[link+1]; |
1419 | 0 | ogg_int64_t begin=vf->dataoffsets[link]; |
1420 | 0 | ogg_int64_t begintime = vf->pcmlengths[link*2]; |
1421 | 0 | ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; |
1422 | 0 | ogg_int64_t target=pos-total+begintime; |
1423 | 0 | ogg_int64_t best=-1; |
1424 | 0 | int got_page=0; |
1425 | |
|
1426 | 0 | ogg_page og; |
1427 | | |
1428 | | /* if we have only one page, there will be no bisection. Grab the page here */ |
1429 | 0 | if(begin==end){ |
1430 | 0 | result=_seek_helper(vf,begin); |
1431 | 0 | if(result) goto seek_error; |
1432 | | |
1433 | 0 | result=_get_next_page(vf,&og,1); |
1434 | 0 | if(result<0) goto seek_error; |
1435 | | |
1436 | 0 | got_page=1; |
1437 | 0 | } |
1438 | | |
1439 | | /* bisection loop */ |
1440 | 0 | while(begin<end){ |
1441 | 0 | ogg_int64_t bisect; |
1442 | |
|
1443 | 0 | if(end-begin<CHUNKSIZE){ |
1444 | 0 | bisect=begin; |
1445 | 0 | }else{ |
1446 | | /* take a (pretty decent) guess. */ |
1447 | 0 | bisect=begin + rescale64(target-begintime, |
1448 | 0 | endtime-begintime, |
1449 | 0 | end-begin) - CHUNKSIZE; |
1450 | 0 | if(bisect<begin+CHUNKSIZE) |
1451 | 0 | bisect=begin; |
1452 | 0 | } |
1453 | |
|
1454 | 0 | result=_seek_helper(vf,bisect); |
1455 | 0 | if(result) goto seek_error; |
1456 | | |
1457 | | /* read loop within the bisection loop */ |
1458 | 0 | while(begin<end){ |
1459 | 0 | result=_get_next_page(vf,&og,end-vf->offset); |
1460 | 0 | if(result==OV_EREAD) goto seek_error; |
1461 | 0 | if(result<0){ |
1462 | | /* there is no next page! */ |
1463 | 0 | if(bisect<=begin+1) |
1464 | | /* No bisection left to perform. We've either found the |
1465 | | best candidate already or failed. Exit loop. */ |
1466 | 0 | end=begin; |
1467 | 0 | else{ |
1468 | | /* We tried to load a fraction of the last page; back up a |
1469 | | bit and try to get the whole last page */ |
1470 | 0 | if(bisect==0) goto seek_error; |
1471 | 0 | bisect-=CHUNKSIZE; |
1472 | | |
1473 | | /* don't repeat/loop on a read we've already performed */ |
1474 | 0 | if(bisect<=begin)bisect=begin+1; |
1475 | | |
1476 | | /* seek and continue bisection */ |
1477 | 0 | result=_seek_helper(vf,bisect); |
1478 | 0 | if(result) goto seek_error; |
1479 | 0 | } |
1480 | 0 | }else{ |
1481 | 0 | ogg_int64_t granulepos; |
1482 | 0 | got_page=1; |
1483 | | |
1484 | | /* got a page. analyze it */ |
1485 | | /* only consider pages from primary vorbis stream */ |
1486 | 0 | if(ogg_page_serialno(&og)!=vf->serialnos[link]) |
1487 | 0 | continue; |
1488 | | |
1489 | | /* only consider pages with the granulepos set */ |
1490 | 0 | granulepos=ogg_page_granulepos(&og); |
1491 | 0 | if(granulepos==-1)continue; |
1492 | | |
1493 | 0 | if(granulepos<target){ |
1494 | | /* this page is a successful candidate! Set state */ |
1495 | |
|
1496 | 0 | best=result; /* raw offset of packet with granulepos */ |
1497 | 0 | begin=vf->offset; /* raw offset of next page */ |
1498 | 0 | begintime=granulepos; |
1499 | | |
1500 | | /* if we're before our target but within a short distance, |
1501 | | don't bisect; read forward */ |
1502 | 0 | if(target-begintime>44100)break; |
1503 | | |
1504 | 0 | bisect=begin; /* *not* begin + 1 as above */ |
1505 | 0 | }else{ |
1506 | | |
1507 | | /* This is one of our pages, but the granpos is |
1508 | | post-target; it is not a bisection return |
1509 | | candidate. (The only way we'd use it is if it's the |
1510 | | first page in the stream; we handle that case later |
1511 | | outside the bisection) */ |
1512 | 0 | if(bisect<=begin+1){ |
1513 | | /* No bisection left to perform. We've either found the |
1514 | | best candidate already or failed. Exit loop. */ |
1515 | 0 | end=begin; |
1516 | 0 | }else{ |
1517 | 0 | if(end==vf->offset){ |
1518 | | /* bisection read to the end; use the known page |
1519 | | boundary (result) to update bisection, back up a |
1520 | | little bit, and try again */ |
1521 | 0 | end=result; |
1522 | 0 | bisect-=CHUNKSIZE; |
1523 | 0 | if(bisect<=begin)bisect=begin+1; |
1524 | 0 | result=_seek_helper(vf,bisect); |
1525 | 0 | if(result) goto seek_error; |
1526 | 0 | }else{ |
1527 | | /* Normal bisection */ |
1528 | 0 | end=bisect; |
1529 | 0 | endtime=granulepos; |
1530 | 0 | break; |
1531 | 0 | } |
1532 | 0 | } |
1533 | 0 | } |
1534 | 0 | } |
1535 | 0 | } |
1536 | 0 | } |
1537 | | |
1538 | | /* Out of bisection: did it 'fail?' */ |
1539 | 0 | if(best == -1){ |
1540 | | |
1541 | | /* Check the 'looking for data in first page' special case; |
1542 | | bisection would 'fail' because our search target was before the |
1543 | | first PCM granule position fencepost. */ |
1544 | |
|
1545 | 0 | if(got_page && |
1546 | 0 | begin == vf->dataoffsets[link] && |
1547 | 0 | ogg_page_serialno(&og)==vf->serialnos[link]){ |
1548 | | |
1549 | | /* Yes, this is the beginning-of-stream case. We already have |
1550 | | our page, right at the beginning of PCM data. Set state |
1551 | | and return. */ |
1552 | |
|
1553 | 0 | vf->pcm_offset=total; |
1554 | |
|
1555 | 0 | if(link!=vf->current_link){ |
1556 | | /* Different link; dump entire decode machine */ |
1557 | 0 | _decode_clear(vf); |
1558 | |
|
1559 | 0 | vf->current_link=link; |
1560 | 0 | vf->current_serialno=vf->serialnos[link]; |
1561 | 0 | vf->ready_state=STREAMSET; |
1562 | |
|
1563 | 0 | }else{ |
1564 | 0 | vorbis_synthesis_restart(&vf->vd); |
1565 | 0 | } |
1566 | |
|
1567 | 0 | ogg_stream_reset_serialno(&vf->os,vf->current_serialno); |
1568 | 0 | ogg_stream_pagein(&vf->os,&og); |
1569 | |
|
1570 | 0 | }else |
1571 | 0 | goto seek_error; |
1572 | |
|
1573 | 0 | }else{ |
1574 | | |
1575 | | /* Bisection found our page. seek to it, update pcm offset. Easier case than |
1576 | | raw_seek, don't keep packets preceding granulepos. */ |
1577 | |
|
1578 | 0 | ogg_page og; |
1579 | 0 | ogg_packet op; |
1580 | | |
1581 | | /* seek */ |
1582 | 0 | result=_seek_helper(vf,best); |
1583 | 0 | vf->pcm_offset=-1; |
1584 | 0 | if(result) goto seek_error; |
1585 | 0 | result=_get_next_page(vf,&og,-1); |
1586 | 0 | if(result<0) goto seek_error; |
1587 | | |
1588 | 0 | if(link!=vf->current_link){ |
1589 | | /* Different link; dump entire decode machine */ |
1590 | 0 | _decode_clear(vf); |
1591 | |
|
1592 | 0 | vf->current_link=link; |
1593 | 0 | vf->current_serialno=vf->serialnos[link]; |
1594 | 0 | vf->ready_state=STREAMSET; |
1595 | |
|
1596 | 0 | }else{ |
1597 | 0 | vorbis_synthesis_restart(&vf->vd); |
1598 | 0 | } |
1599 | |
|
1600 | 0 | ogg_stream_reset_serialno(&vf->os,vf->current_serialno); |
1601 | 0 | ogg_stream_pagein(&vf->os,&og); |
1602 | | |
1603 | | /* pull out all but last packet; the one with granulepos */ |
1604 | 0 | while(1){ |
1605 | 0 | result=ogg_stream_packetpeek(&vf->os,&op); |
1606 | 0 | if(result==0){ |
1607 | | /* No packet returned; we exited the bisection with 'best' |
1608 | | pointing to a page with a granule position, so the packet |
1609 | | finishing this page ('best') originated on a preceding |
1610 | | page. Keep fetching previous pages until we get one with |
1611 | | a granulepos or without the 'continued' flag set. Then |
1612 | | just use raw_seek for simplicity. */ |
1613 | | /* Do not rewind past the beginning of link data; if we do, |
1614 | | it's either a bug or a broken stream */ |
1615 | 0 | result=best; |
1616 | 0 | while(result>vf->dataoffsets[link]){ |
1617 | 0 | result=_get_prev_page(vf,result,&og); |
1618 | 0 | if(result<0) goto seek_error; |
1619 | 0 | if(ogg_page_serialno(&og)==vf->current_serialno && |
1620 | 0 | (ogg_page_granulepos(&og)>-1 || |
1621 | 0 | !ogg_page_continued(&og))){ |
1622 | 0 | return ov_raw_seek(vf,result); |
1623 | 0 | } |
1624 | 0 | } |
1625 | 0 | } |
1626 | 0 | if(result<0){ |
1627 | 0 | result = OV_EBADPACKET; |
1628 | 0 | goto seek_error; |
1629 | 0 | } |
1630 | 0 | if(op.granulepos!=-1){ |
1631 | 0 | vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; |
1632 | 0 | if(vf->pcm_offset<0)vf->pcm_offset=0; |
1633 | 0 | vf->pcm_offset+=total; |
1634 | 0 | break; |
1635 | 0 | }else |
1636 | 0 | result=ogg_stream_packetout(&vf->os,NULL); |
1637 | 0 | } |
1638 | 0 | } |
1639 | 0 | } |
1640 | | |
1641 | | /* verify result */ |
1642 | 0 | if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ |
1643 | 0 | result=OV_EFAULT; |
1644 | 0 | goto seek_error; |
1645 | 0 | } |
1646 | 0 | vf->bittrack=0; |
1647 | 0 | vf->samptrack=0; |
1648 | 0 | return(0); |
1649 | | |
1650 | 0 | seek_error: |
1651 | | /* dump machine so we're in a known state */ |
1652 | 0 | vf->pcm_offset=-1; |
1653 | 0 | _decode_clear(vf); |
1654 | 0 | return (int)result; |
1655 | 0 | } |
1656 | | |
1657 | | /* seek to a sample offset relative to the decompressed pcm stream |
1658 | | returns zero on success, nonzero on failure */ |
1659 | | |
1660 | 0 | int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ |
1661 | 0 | int thisblock,lastblock=0; |
1662 | 0 | int ret=ov_pcm_seek_page(vf,pos); |
1663 | 0 | if(ret<0)return(ret); |
1664 | 0 | if((ret=_make_decode_ready(vf)))return ret; |
1665 | | |
1666 | | /* discard leading packets we don't need for the lapping of the |
1667 | | position we want; don't decode them */ |
1668 | | |
1669 | 0 | while(1){ |
1670 | 0 | ogg_packet op; |
1671 | 0 | ogg_page og; |
1672 | |
|
1673 | 0 | int ret=ogg_stream_packetpeek(&vf->os,&op); |
1674 | 0 | if(ret>0){ |
1675 | 0 | thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); |
1676 | 0 | if(thisblock<0){ |
1677 | 0 | ogg_stream_packetout(&vf->os,NULL); |
1678 | 0 | continue; /* non audio packet */ |
1679 | 0 | } |
1680 | 0 | if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2; |
1681 | |
|
1682 | 0 | if(vf->pcm_offset+((thisblock+ |
1683 | 0 | vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break; |
1684 | | |
1685 | | /* remove the packet from packet queue and track its granulepos */ |
1686 | 0 | ogg_stream_packetout(&vf->os,NULL); |
1687 | 0 | vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with |
1688 | | only tracking, no |
1689 | | pcm_decode */ |
1690 | 0 | vorbis_synthesis_blockin(&vf->vd,&vf->vb); |
1691 | | |
1692 | | /* end of logical stream case is hard, especially with exact |
1693 | | length positioning. */ |
1694 | |
|
1695 | 0 | if(op.granulepos>-1){ |
1696 | 0 | int i; |
1697 | | /* always believe the stream markers */ |
1698 | 0 | vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; |
1699 | 0 | if(vf->pcm_offset<0)vf->pcm_offset=0; |
1700 | 0 | for(i=0;i<vf->current_link;i++) |
1701 | 0 | vf->pcm_offset+=vf->pcmlengths[i*2+1]; |
1702 | 0 | } |
1703 | |
|
1704 | 0 | lastblock=thisblock; |
1705 | |
|
1706 | 0 | }else{ |
1707 | 0 | if(ret<0 && ret!=OV_HOLE)break; |
1708 | | |
1709 | | /* suck in a new page */ |
1710 | 0 | if(_get_next_page(vf,&og,-1)<0)break; |
1711 | 0 | if(ogg_page_bos(&og))_decode_clear(vf); |
1712 | |
|
1713 | 0 | if(vf->ready_state<STREAMSET){ |
1714 | 0 | ogg_uint32_t serialno=ogg_page_serialno(&og); |
1715 | 0 | int link; |
1716 | |
|
1717 | 0 | for(link=0;link<vf->links;link++) |
1718 | 0 | if(vf->serialnos[link]==serialno)break; |
1719 | 0 | if(link==vf->links) continue; |
1720 | 0 | vf->current_link=link; |
1721 | |
|
1722 | 0 | vf->ready_state=STREAMSET; |
1723 | 0 | vf->current_serialno=ogg_page_serialno(&og); |
1724 | 0 | ogg_stream_reset_serialno(&vf->os,serialno); |
1725 | 0 | ret=_make_decode_ready(vf); |
1726 | 0 | if(ret)return ret; |
1727 | 0 | lastblock=0; |
1728 | 0 | } |
1729 | | |
1730 | 0 | ogg_stream_pagein(&vf->os,&og); |
1731 | 0 | } |
1732 | 0 | } |
1733 | | |
1734 | 0 | vf->bittrack=0; |
1735 | 0 | vf->samptrack=0; |
1736 | | /* discard samples until we reach the desired position. Crossing a |
1737 | | logical bitstream boundary with abandon is OK. */ |
1738 | 0 | while(vf->pcm_offset<pos){ |
1739 | 0 | ogg_int64_t target=pos-vf->pcm_offset; |
1740 | 0 | long samples=vorbis_synthesis_pcmout(&vf->vd,NULL); |
1741 | |
|
1742 | 0 | if(samples>target)samples=target; |
1743 | 0 | vorbis_synthesis_read(&vf->vd,samples); |
1744 | 0 | vf->pcm_offset+=samples; |
1745 | |
|
1746 | 0 | if(samples<target) |
1747 | 0 | if(_fetch_and_process_packet(vf,NULL,1,1)<=0) |
1748 | 0 | vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */ |
1749 | 0 | } |
1750 | 0 | return 0; |
1751 | 0 | } |
1752 | | |
1753 | | /* seek to a playback time relative to the decompressed pcm stream |
1754 | | returns zero on success, nonzero on failure */ |
1755 | 0 | int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){ |
1756 | | /* translate time to PCM position and call ov_pcm_seek */ |
1757 | |
|
1758 | 0 | int link=-1; |
1759 | 0 | ogg_int64_t pcm_total=0; |
1760 | 0 | ogg_int64_t time_total=0; |
1761 | |
|
1762 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1763 | 0 | if(!vf->seekable)return(OV_ENOSEEK); |
1764 | 0 | if(milliseconds<0)return(OV_EINVAL); |
1765 | | |
1766 | | /* which bitstream section does this time offset occur in? */ |
1767 | 0 | for(link=0;link<vf->links;link++){ |
1768 | 0 | ogg_int64_t addsec = ov_time_total(vf,link); |
1769 | 0 | if(milliseconds<time_total+addsec)break; |
1770 | 0 | time_total+=addsec; |
1771 | 0 | pcm_total+=vf->pcmlengths[link*2+1]; |
1772 | 0 | } |
1773 | |
|
1774 | 0 | if(link==vf->links)return(OV_EINVAL); |
1775 | | |
1776 | | /* enough information to convert time offset to pcm offset */ |
1777 | 0 | { |
1778 | 0 | ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; |
1779 | 0 | return(ov_pcm_seek(vf,target)); |
1780 | 0 | } |
1781 | 0 | } |
1782 | | |
1783 | | /* page-granularity version of ov_time_seek |
1784 | | returns zero on success, nonzero on failure */ |
1785 | 0 | int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){ |
1786 | | /* translate time to PCM position and call ov_pcm_seek */ |
1787 | |
|
1788 | 0 | int link=-1; |
1789 | 0 | ogg_int64_t pcm_total=0; |
1790 | 0 | ogg_int64_t time_total=0; |
1791 | |
|
1792 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1793 | 0 | if(!vf->seekable)return(OV_ENOSEEK); |
1794 | 0 | if(milliseconds<0)return(OV_EINVAL); |
1795 | | |
1796 | | /* which bitstream section does this time offset occur in? */ |
1797 | 0 | for(link=0;link<vf->links;link++){ |
1798 | 0 | ogg_int64_t addsec = ov_time_total(vf,link); |
1799 | 0 | if(milliseconds<time_total+addsec)break; |
1800 | 0 | time_total+=addsec; |
1801 | 0 | pcm_total+=vf->pcmlengths[link*2+1]; |
1802 | 0 | } |
1803 | |
|
1804 | 0 | if(link==vf->links)return(OV_EINVAL); |
1805 | | |
1806 | | /* enough information to convert time offset to pcm offset */ |
1807 | 0 | { |
1808 | 0 | ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; |
1809 | 0 | return(ov_pcm_seek_page(vf,target)); |
1810 | 0 | } |
1811 | 0 | } |
1812 | | |
1813 | | /* tell the current stream offset cursor. Note that seek followed by |
1814 | | tell will likely not give the set offset due to caching */ |
1815 | 0 | ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ |
1816 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1817 | 0 | return(vf->offset); |
1818 | 0 | } |
1819 | | |
1820 | | /* return PCM offset (sample) of next PCM sample to be read */ |
1821 | 0 | ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ |
1822 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1823 | 0 | return(vf->pcm_offset); |
1824 | 0 | } |
1825 | | |
1826 | | /* return time offset (milliseconds) of next PCM sample to be read */ |
1827 | 0 | ogg_int64_t ov_time_tell(OggVorbis_File *vf){ |
1828 | 0 | int link=0; |
1829 | 0 | ogg_int64_t pcm_total=0; |
1830 | 0 | ogg_int64_t time_total=0; |
1831 | |
|
1832 | 0 | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1833 | 0 | if(vf->seekable){ |
1834 | 0 | pcm_total=ov_pcm_total(vf,-1); |
1835 | 0 | time_total=ov_time_total(vf,-1); |
1836 | | |
1837 | | /* which bitstream section does this time offset occur in? */ |
1838 | 0 | for(link=vf->links-1;link>=0;link--){ |
1839 | 0 | pcm_total-=vf->pcmlengths[link*2+1]; |
1840 | 0 | time_total-=ov_time_total(vf,link); |
1841 | 0 | if(vf->pcm_offset>=pcm_total)break; |
1842 | 0 | } |
1843 | 0 | } |
1844 | |
|
1845 | 0 | return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate); |
1846 | 0 | } |
1847 | | |
1848 | | /* link: -1) return the vorbis_info struct for the bitstream section |
1849 | | currently being decoded |
1850 | | 0-n) to request information for a specific bitstream section |
1851 | | |
1852 | | In the case of a non-seekable bitstream, any call returns the |
1853 | | current bitstream. NULL in the case that the machine is not |
1854 | | initialized */ |
1855 | | |
1856 | 1.41M | vorbis_info *ov_info(OggVorbis_File *vf,int link){ |
1857 | 1.41M | if(vf->seekable){ |
1858 | 0 | if(link<0) |
1859 | 0 | if(vf->ready_state>=STREAMSET) |
1860 | 0 | return vf->vi+vf->current_link; |
1861 | 0 | else |
1862 | 0 | return vf->vi; |
1863 | 0 | else |
1864 | 0 | if(link>=vf->links) |
1865 | 0 | return NULL; |
1866 | 0 | else |
1867 | 0 | return vf->vi+link; |
1868 | 1.41M | }else{ |
1869 | 1.41M | return vf->vi; |
1870 | 1.41M | } |
1871 | 1.41M | } |
1872 | | |
1873 | | /* grr, strong typing, grr, no templates/inheritence, grr */ |
1874 | 0 | vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ |
1875 | 0 | if(vf->seekable){ |
1876 | 0 | if(link<0) |
1877 | 0 | if(vf->ready_state>=STREAMSET) |
1878 | 0 | return vf->vc+vf->current_link; |
1879 | 0 | else |
1880 | 0 | return vf->vc; |
1881 | 0 | else |
1882 | 0 | if(link>=vf->links) |
1883 | 0 | return NULL; |
1884 | 0 | else |
1885 | 0 | return vf->vc+link; |
1886 | 0 | }else{ |
1887 | 0 | return vf->vc; |
1888 | 0 | } |
1889 | 0 | } |
1890 | | |
1891 | | /* up to this point, everything could more or less hide the multiple |
1892 | | logical bitstream nature of chaining from the toplevel application |
1893 | | if the toplevel application didn't particularly care. However, at |
1894 | | the point that we actually read audio back, the multiple-section |
1895 | | nature must surface: Multiple bitstream sections do not necessarily |
1896 | | have to have the same number of channels or sampling rate. |
1897 | | |
1898 | | ov_read returns the sequential logical bitstream number currently |
1899 | | being decoded along with the PCM data in order that the toplevel |
1900 | | application can take action on channel/sample rate changes. This |
1901 | | number will be incremented even for streamed (non-seekable) streams |
1902 | | (for seekable streams, it represents the actual logical bitstream |
1903 | | index within the physical bitstream. Note that the accessor |
1904 | | functions above are aware of this dichotomy). |
1905 | | |
1906 | | input values: buffer) a buffer to hold packed PCM data for return |
1907 | | bytes_req) the byte length requested to be placed into buffer |
1908 | | |
1909 | | return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) |
1910 | | 0) EOF |
1911 | | n) number of bytes of PCM actually returned. The |
1912 | | below works on a packet-by-packet basis, so the |
1913 | | return length is not related to the 'length' passed |
1914 | | in, just guaranteed to fit. |
1915 | | |
1916 | | *section) set to the logical bitstream number */ |
1917 | | |
1918 | 1.42M | long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ |
1919 | 1.42M | int i,j; |
1920 | | |
1921 | 1.42M | ogg_int32_t **pcm; |
1922 | 1.42M | long samples; |
1923 | | |
1924 | 1.42M | if(vf->ready_state<OPENED)return(OV_EINVAL); |
1925 | | |
1926 | 1.45M | while(1){ |
1927 | 1.45M | if(vf->ready_state==INITSET){ |
1928 | 1.45M | samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); |
1929 | 1.45M | if(samples)break; |
1930 | 1.45M | } |
1931 | | |
1932 | | /* suck in another packet */ |
1933 | 43.3k | { |
1934 | 43.3k | int ret=_fetch_and_process_packet(vf,NULL,1,1); |
1935 | 43.3k | if(ret==OV_EOF) |
1936 | 2.06k | return(0); |
1937 | 41.2k | if(ret<=0) |
1938 | 8.81k | return(ret); |
1939 | 41.2k | } |
1940 | | |
1941 | 41.2k | } |
1942 | | |
1943 | 1.41M | if(samples>0){ |
1944 | | |
1945 | | /* yay! proceed to pack data into the byte buffer */ |
1946 | | |
1947 | 1.41M | long channels=ov_info(vf,-1)->channels; |
1948 | | |
1949 | 1.41M | if(samples>(bytes_req/(2*channels))) |
1950 | 1.38M | samples=bytes_req/(2*channels); |
1951 | | |
1952 | 313M | for(i=0;i<channels;i++) { /* It's faster in this order */ |
1953 | 312M | ogg_int32_t *src=pcm[i]; |
1954 | 312M | short *dest=((short *)buffer)+i; |
1955 | 3.07G | for(j=0;j<samples;j++) { |
1956 | 2.76G | *dest=CLIP_TO_15(src[j]>>9); |
1957 | 2.76G | dest+=channels; |
1958 | 2.76G | } |
1959 | 312M | } |
1960 | | |
1961 | 1.41M | vorbis_synthesis_read(&vf->vd,samples); |
1962 | 1.41M | vf->pcm_offset+=samples; |
1963 | 1.41M | if(bitstream)*bitstream=vf->current_link; |
1964 | 1.41M | return(samples*2*channels); |
1965 | 1.41M | }else{ |
1966 | 0 | return(samples); |
1967 | 0 | } |
1968 | 1.41M | } |