summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libtremor/vorbisfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libtremor/vorbisfile.c')
-rw-r--r--lib/rbcodec/codecs/libtremor/vorbisfile.c1671
1 files changed, 1671 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libtremor/vorbisfile.c b/lib/rbcodec/codecs/libtremor/vorbisfile.c
new file mode 100644
index 0000000000..271e5a09e3
--- /dev/null
+++ b/lib/rbcodec/codecs/libtremor/vorbisfile.c
@@ -0,0 +1,1671 @@
1/********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
4 * *
5 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
6 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
11 * *
12 ********************************************************************
13
14 function: stdio-based convenience library for opening/seeking/decoding
15 last mod: $Id$
16
17 ********************************************************************/
18
19#include "config-tremor.h"
20#include <stdio.h>
21#include <errno.h>
22#include <string.h>
23#include <math.h>
24#include "system.h"
25
26#include "ivorbiscodec.h"
27#include "ivorbisfile.h"
28
29#include "os.h"
30#include "misc.h"
31
32/* A 'chained bitstream' is a Vorbis bitstream that contains more than
33 one logical bitstream arranged end to end (the only form of Ogg
34 multiplexing allowed in a Vorbis bitstream; grouping [parallel
35 multiplexing] is not allowed in Vorbis) */
36
37/* A Vorbis file can be played beginning to end (streamed) without
38 worrying ahead of time about chaining (see decoder_example.c). If
39 we have the whole file, however, and want random access
40 (seeking/scrubbing) or desire to know the total length/time of a
41 file, we need to account for the possibility of chaining. */
42
43/* We can handle things a number of ways; we can determine the entire
44 bitstream structure right off the bat, or find pieces on demand.
45 This example determines and caches structure for the entire
46 bitstream, but builds a virtual decoder on the fly when moving
47 between links in the chain. */
48
49/* There are also different ways to implement seeking. Enough
50 information exists in an Ogg bitstream to seek to
51 sample-granularity positions in the output. Or, one can seek by
52 picking some portion of the stream roughly in the desired area if
53 we only want coarse navigation through the stream. */
54
55/*************************************************************************
56 * Many, many internal helpers. The intention is not to be confusing;
57 * rampant duplication and monolithic function implementation would be
58 * harder to understand anyway. The high level functions are last. Begin
59 * grokking near the end of the file */
60
61
62/* read a little more data from the file/pipe into the ogg_sync framer */
63static long _get_data(OggVorbis_File *vf){
64 if(!(vf->callbacks.read_func))return(-1);
65 if(vf->datasource){
66 char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
67 long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
68 if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
69 return(bytes);
70 }else
71 return(0);
72}
73
74/* save a tiny smidge of verbosity to make the code more readable */
75static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
76 if(vf->datasource){
77 if(!(vf->callbacks.seek_func)||
78 (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
79 return OV_EREAD;
80 vf->offset=offset;
81 ogg_sync_reset(&vf->oy);
82 }else{
83 /* shouldn't happen unless someone writes a broken callback */
84 return OV_EFAULT;
85 }
86 return 0;
87}
88
89/* The read/seek functions track absolute position within the stream */
90
91/* from the head of the stream, get the next page. boundary specifies
92 if the function is allowed to fetch more data from the stream (and
93 how much) or only use internally buffered data.
94
95 boundary: -1) unbounded search
96 0) read no additional data; use cached only
97 n) search for a new page beginning for n bytes
98
99 return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
100 n) found a page at absolute offset n */
101
102static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
103 ogg_int64_t boundary){
104 if(boundary>0)boundary+=vf->offset;
105 while(1){
106 long more;
107
108 if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
109 more=ogg_sync_pageseek(&vf->oy,og);
110
111 if(more<0){
112 /* skipped n bytes */
113 vf->offset-=more;
114 }else{
115 if(more==0){
116 /* send more paramedics */
117 if(!boundary)return(OV_FALSE);
118 {
119 long ret=_get_data(vf);
120 if(ret==0)return(OV_EOF);
121 if(ret<0)return(OV_EREAD);
122 }
123 }else{
124 /* got a page. Return the offset at the page beginning,
125 advance the internal offset past the page end */
126 ogg_int64_t ret=vf->offset;
127 vf->offset+=more;
128 return(ret);
129
130 }
131 }
132 }
133}
134
135/* This is a nasty hack to work around the huge allocations we get from
136 huge comment packets, usually due to embedded album art */
137static int ogg_stream_discard_packet(OggVorbis_File *vf,ogg_page *og,
138 ogg_int64_t boundary){
139 int ret;
140 while((ret = ogg_stream_packetout(&vf->os, NULL)) == 0) {
141 if(_get_next_page(vf, og, boundary)<0)
142 break;
143 ogg_stream_pagein(&vf->os,og,false);
144 }
145 if (ret < 0)
146 return -1;
147 /* We might be pretending to have filled in more of the buffer than there is
148 actual space, in this case the body storage must be expanded before we
149 start writing to it */
150 if (vf->os.body_fill < og->body_len || vf->os.body_storage < vf->os.body_fill)
151 if(_os_body_expand(&vf->os, vf->os.body_fill - vf->os.body_storage + og->body_len))
152 return -1;
153 memcpy(vf->os.body_data+vf->os.body_fill-og->body_len, og->body, og->body_len);
154 return 1;
155}
156
157/* find the latest page beginning before the current stream cursor
158 position. Much dirtier than the above as Ogg doesn't have any
159 backward search linkage. no 'readp' as it will certainly have to
160 read. */
161/* returns offset or OV_EREAD, OV_FAULT */
162static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
163 ogg_int64_t begin=vf->offset;
164 ogg_int64_t end=begin;
165 ogg_int64_t ret;
166 ogg_int64_t offset=-1;
167
168 while(offset==-1){
169 begin-=CHUNKSIZE;
170 if(begin<0)
171 begin=0;
172
173 ret=_seek_helper(vf,begin);
174 if(ret)return(ret);
175
176 while(vf->offset<end){
177 memset(og,0,sizeof(*og));
178 ret=_get_next_page(vf,og,end-vf->offset);
179 if(ret==OV_EREAD)return(OV_EREAD);
180 if(ret<0){
181 break;
182 }else{
183 offset=ret;
184 }
185 }
186 }
187
188 /* In a fully compliant, non-multiplexed stream, we'll still be
189 holding the last page. In multiplexed (or noncompliant streams),
190 we will probably have to re-read the last page we saw */
191 if(og->header_len==0){
192 ret=_seek_helper(vf,offset);
193 if(ret)return(ret);
194
195 ret=_get_next_page(vf,og,CHUNKSIZE);
196 if(ret<0)
197 /* this shouldn't be possible */
198 return(OV_EFAULT);
199 }
200
201 return(offset);
202}
203
204static void _add_serialno(ogg_page *og,ogg_uint32_t **serialno_list, int *n){
205 long s = ogg_page_serialno(og);
206 (*n)++;
207
208 if(*serialno_list){
209 *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
210 }else{
211 *serialno_list = _ogg_malloc(sizeof(**serialno_list));
212 }
213
214 (*serialno_list)[(*n)-1] = s;
215}
216
217/* returns nonzero if found */
218static int _lookup_serialno(ogg_uint32_t s, ogg_uint32_t *serialno_list, int n){
219 if(serialno_list){
220 while(n--){
221 if(*serialno_list == (ogg_uint32_t) s) return 1;
222 serialno_list++;
223 }
224 }
225 return 0;
226}
227
228static int _lookup_page_serialno(ogg_page *og, ogg_uint32_t *serialno_list, int n){
229 ogg_uint32_t s = ogg_page_serialno(og);
230 return _lookup_serialno(s,serialno_list,n);
231}
232
233/* performs the same search as _get_prev_page, but prefers pages of
234 the specified serial number. If a page of the specified serialno is
235 spotted during the seek-back-and-read-forward, it will return the
236 info of last page of the matching serial number instead of the very
237 last page. If no page of the specified serialno is seen, it will
238 return the info of last page and alter *serialno. */
239static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf,
240 ogg_uint32_t *serial_list, int serial_n,
241 int *serialno, ogg_int64_t *granpos){
242 ogg_page og;
243 ogg_int64_t begin=vf->offset;
244 ogg_int64_t end=begin;
245 ogg_int64_t ret;
246
247 ogg_int64_t prefoffset=-1;
248 ogg_int64_t offset=-1;
249 ogg_int64_t ret_serialno=-1;
250 ogg_int64_t ret_gran=-1;
251
252 while(offset==-1){
253 begin-=CHUNKSIZE;
254 if(begin<0)
255 begin=0;
256
257 ret=_seek_helper(vf,begin);
258 if(ret)return(ret);
259
260 while(vf->offset<end){
261 ret=_get_next_page(vf,&og,end-vf->offset);
262 if(ret==OV_EREAD)return(OV_EREAD);
263 if(ret<0){
264 break;
265 }else{
266 ret_serialno=ogg_page_serialno(&og);
267 ret_gran=ogg_page_granulepos(&og);
268 offset=ret;
269
270 if((ogg_uint32_t)ret_serialno == (ogg_uint32_t)*serialno){
271 prefoffset=ret;
272 *granpos=ret_gran;
273 }
274
275 if(!_lookup_serialno((ogg_uint32_t)ret_serialno,serial_list,serial_n)){
276 /* we fell off the end of the link, which means we seeked
277 back too far and shouldn't have been looking in that link
278 to begin with. If we found the preferred serial number,
279 forget that we saw it. */
280 prefoffset=-1;
281 }
282 }
283 }
284 }
285
286 /* we're not interested in the page... just the serialno and granpos. */
287 if(prefoffset>=0)return(prefoffset);
288
289 *serialno = ret_serialno;
290 *granpos = ret_gran;
291 return(offset);
292
293}
294
295/* uses the local ogg_stream storage in vf; this is important for
296 non-streaming input sources */
297static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,
298 ogg_uint32_t **serialno_list, int *serialno_n,
299 ogg_page *og_ptr){
300 ogg_page og;
301 ogg_packet op;
302 int i,ret;
303 int allbos=0;
304
305 if(!og_ptr){
306 ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
307 if(llret==OV_EREAD)return(OV_EREAD);
308 if(llret<0)return(OV_ENOTVORBIS);
309 og_ptr=&og;
310 }
311
312 vorbis_info_init(vi);
313/* vorbis_comment_init(vc); */
314 vf->ready_state=OPENED;
315
316 /* extract the serialnos of all BOS pages + the first set of vorbis
317 headers we see in the link */
318
319 while(ogg_page_bos(og_ptr)){
320 if(serialno_list){
321 if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
322 /* a dupe serialnumber in an initial header packet set == invalid stream */
323 if(*serialno_list)_ogg_free(*serialno_list);
324 *serialno_list=0;
325 *serialno_n=0;
326 ret=OV_EBADHEADER;
327 goto bail_header;
328 }
329
330 _add_serialno(og_ptr,serialno_list,serialno_n);
331 }
332
333 if(vf->ready_state<STREAMSET){
334 /* we don't have a vorbis stream in this link yet, so begin
335 prospective stream setup. We need a stream to get packets */
336 ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
337 ogg_stream_pagein(&vf->os,og_ptr,true);
338
339 if(ogg_stream_packetout(&vf->os,&op) > 0 &&
340 vorbis_synthesis_idheader(&op)){
341 /* vorbis header; continue setup */
342 vf->ready_state=STREAMSET;
343 if((ret=vorbis_synthesis_headerin(vi,&op))){
344 ret=OV_EBADHEADER;
345 goto bail_header;
346 }
347 }
348 }
349
350 /* get next page */
351 {
352 ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
353 if(llret==OV_EREAD){
354 ret=OV_EREAD;
355 goto bail_header;
356 }
357 if(llret<0){
358 ret=OV_ENOTVORBIS;
359 goto bail_header;
360 }
361
362 /* if this page also belongs to our vorbis stream, submit it and break */
363 if(vf->ready_state==STREAMSET &&
364 vf->os.serialno == ogg_page_serialno(og_ptr)){
365 ogg_stream_pagein(&vf->os,og_ptr,true);
366 break;
367 }
368 }
369 }
370
371 if(vf->ready_state!=STREAMSET){
372 ret = OV_ENOTVORBIS;
373 goto bail_header;
374 }
375
376 while(1){
377
378 i=0;
379 /* discard comment packet */
380 if(ogg_stream_discard_packet(vf,og_ptr,CHUNKSIZE) < 0){
381 ret=OV_EBADHEADER;
382 goto bail_header;
383 }
384 i++;
385
386 while(i<2){ /* get a page loop */
387
388 while(i<2){ /* get a packet loop */
389 int result=ogg_stream_packetout(&vf->os,&op);
390 if(result==0)break;
391 if(result==-1){
392 ret=OV_EBADHEADER;
393 goto bail_header;
394 }
395
396 if((ret=vorbis_synthesis_headerin(vi,&op)))
397 goto bail_header;
398
399 i++;
400 }
401
402 while(i<2){
403 if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
404 ret=OV_EBADHEADER;
405 goto bail_header;
406 }
407
408 /* if this page belongs to the correct stream, go parse it */
409 if(vf->os.serialno == ogg_page_serialno(og_ptr)){
410 ogg_stream_pagein(&vf->os,og_ptr,true);
411 break;
412 }
413
414 /* if we never see the final vorbis headers before the link
415 ends, abort */
416 if(ogg_page_bos(og_ptr)){
417 if(allbos){
418 ret = OV_EBADHEADER;
419 goto bail_header;
420 }else
421 allbos=1;
422 }
423
424 /* otherwise, keep looking */
425 }
426 }
427
428 return 0;
429 }
430
431 bail_header:
432 vorbis_info_clear(vi);
433/* vorbis_comment_clear(vc); */
434 vf->ready_state=OPENED;
435
436 return ret;
437}
438
439/* Starting from current cursor position, get initial PCM offset of
440 next page. Consumes the page in the process without decoding
441 audio, however this is only called during stream parsing upon
442 seekable open. */
443static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
444 ogg_page og;
445 ogg_int64_t accumulated=0;
446 long lastblock=-1;
447 int result;
448 ogg_uint32_t serialno = vf->os.serialno;
449
450 while(1){
451 ogg_packet op;
452 if(_get_next_page(vf,&og,-1)<0)
453 break; /* should not be possible unless the file is truncated/mangled */
454
455 if(ogg_page_bos(&og)) break;
456 if(ogg_page_serialno(&og)!= serialno) continue;
457
458 /* count blocksizes of all frames in the page */
459 ogg_stream_pagein(&vf->os,&og,true);
460 while((result=ogg_stream_packetout(&vf->os,&op))){
461 if(result>0){ /* ignore holes */
462 long thisblock=vorbis_packet_blocksize(vi,&op);
463 if(lastblock!=-1)
464 accumulated+=(lastblock+thisblock)>>2;
465 lastblock=thisblock;
466 }
467 }
468
469 if(ogg_page_granulepos(&og)!=-1){
470 /* pcm offset of last packet on the first audio page */
471 accumulated= ogg_page_granulepos(&og)-accumulated;
472 break;
473 }
474 }
475
476 /* less than zero? This is a stream with samples trimmed off
477 the beginning, a normal occurrence; set the offset to zero */
478 if(accumulated<0)accumulated=0;
479
480 return accumulated;
481}
482
483/* finds each bitstream link one at a time using a bisection search
484 (has to begin by knowing the offset of the lb's initial page).
485 Recurses for each link so it can alloc the link storage after
486 finding them all, then unroll and fill the cache at the same time */
487static int _bisect_forward_serialno(OggVorbis_File *vf,
488 ogg_int64_t begin,
489 ogg_int64_t searched,
490 ogg_int64_t end,
491 ogg_int64_t endgran,
492 int endserial,
493 ogg_uint32_t *currentno_list,
494 int currentnos,
495 long m){
496 ogg_int64_t pcmoffset;
497 ogg_int64_t dataoffset=searched;
498 ogg_int64_t endsearched=end;
499 ogg_int64_t next=end;
500 ogg_int64_t searchgran=-1;
501 ogg_page og;
502 ogg_int64_t ret,last;
503 int serialno = vf->os.serialno;
504
505 /* invariants:
506 we have the headers and serialnos for the link beginning at 'begin'
507 we have the offset and granpos of the last page in the file (potentially
508 not a page we care about)
509 */
510
511 /* Is the last page in our list of current serialnumbers? */
512 if(_lookup_serialno(endserial,currentno_list,currentnos)){
513
514 /* last page is in the starting serialno list, so we've bisected
515 down to (or just started with) a single link. Now we need to
516 find the last vorbis page belonging to the first vorbis stream
517 for this link. */
518
519 while(endserial != serialno){
520 endserial = serialno;
521 vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&endserial,&endgran);
522 }
523
524 vf->links=m+1;
525 if(vf->offsets)_ogg_free(vf->offsets);
526 if(vf->serialnos)_ogg_free(vf->serialnos);
527 if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
528
529 vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
530 vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
531/* vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));*/
532 vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
533 vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
534 vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
535
536 vf->offsets[m+1]=end;
537 vf->offsets[m]=begin;
538 vf->pcmlengths[m*2+1]=endgran;
539
540 }else{
541
542 ogg_uint32_t *next_serialno_list=NULL;
543 int next_serialnos=0;
544 vorbis_info vi;
545/* vorbis_comment vc; */
546
547 /* the below guards against garbage seperating the last and
548 first pages of two links. */
549 while(searched<endsearched){
550 ogg_int64_t bisect;
551
552 if(endsearched-searched<CHUNKSIZE){
553 bisect=searched;
554 }else{
555 bisect=(searched+endsearched)/2;
556 }
557
558 if(bisect != vf->offset){
559 ret=_seek_helper(vf,bisect);
560 if(ret)return(ret);
561 }
562
563 last=_get_next_page(vf,&og,-1);
564 if(last==OV_EREAD)return(OV_EREAD);
565 if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
566 endsearched=bisect;
567 if(last>=0)next=last;
568 }else{
569 searched=vf->offset;
570 }
571 }
572
573 /* Bisection point found */
574
575 /* for the time being, fetch end PCM offset the simple way */
576 {
577 int testserial = serialno+1;
578 vf->offset = next;
579 while(testserial != serialno){
580 testserial = serialno;
581 vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&testserial,&searchgran);
582 }
583 }
584
585 if(vf->offset!=next){
586 ret=_seek_helper(vf,next);
587 if(ret)return(ret);
588 }
589
590 ret=_fetch_headers(vf,&vi,&next_serialno_list,&next_serialnos,NULL);
591 if(ret)return(ret);
592 serialno = vf->os.serialno;
593 dataoffset = vf->offset;
594
595 /* this will consume a page, however the next bistection always
596 starts with a raw seek */
597 pcmoffset = _initial_pcmoffset(vf,&vi);
598
599 ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
600 next_serialno_list,next_serialnos,m+1);
601 if(ret)return(ret);
602
603 if(next_serialno_list)_ogg_free(next_serialno_list);
604
605 vf->offsets[m+1]=next;
606 vf->serialnos[m+1]=serialno;
607 vf->dataoffsets[m+1]=dataoffset;
608
609 vf->vi[m+1]=vi;
610/* vf->vc[m+1]=vc; */
611
612 vf->pcmlengths[m*2+1]=searchgran;
613 vf->pcmlengths[m*2+2]=pcmoffset;
614 vf->pcmlengths[m*2+3]-=pcmoffset;
615
616 }
617 return(0);
618}
619
620static int _make_decode_ready(OggVorbis_File *vf){
621 if(vf->ready_state>STREAMSET)return 0;
622 if(vf->ready_state<STREAMSET)return OV_EFAULT;
623 if(vf->seekable){
624 if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
625 return OV_EBADLINK;
626 }else{
627 if(vorbis_synthesis_init(&vf->vd,vf->vi))
628 return OV_EBADLINK;
629 }
630 vorbis_block_init(&vf->vd,&vf->vb);
631 vf->ready_state=INITSET;
632 vf->bittrack=0;
633 vf->samptrack=0;
634 return 0;
635}
636
637static int _open_seekable2(OggVorbis_File *vf){
638 ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1;
639 int endserial=vf->os.serialno;
640 int serialno=vf->os.serialno;
641
642 /* we're partially open and have a first link header state in
643 storage in vf */
644
645 /* fetch initial PCM offset */
646 ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
647
648 /* we can seek, so set out learning all about this file */
649 if(vf->callbacks.seek_func && vf->callbacks.tell_func){
650 (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
651 vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
652 }else{
653 vf->offset=vf->end=-1;
654 }
655
656 /* If seek_func is implemented, tell_func must also be implemented */
657 if(vf->end==-1) return(OV_EINVAL);
658
659 /* Get the offset of the last page of the physical bitstream, or, if
660 we're lucky the last vorbis page of this link as most OggVorbis
661 files will contain a single logical bitstream */
662 end=_get_prev_page_serial(vf,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
663 if(end<0)return(end);
664
665 /* now determine bitstream structure recursively */
666 if(_bisect_forward_serialno(vf,0,dataoffset,vf->offset,endgran,endserial,
667 vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
668
669 vf->offsets[0]=0;
670 vf->serialnos[0]=serialno;
671 vf->dataoffsets[0]=dataoffset;
672 vf->pcmlengths[0]=pcmoffset;
673 vf->pcmlengths[1]-=pcmoffset;
674
675 return(ov_raw_seek(vf,dataoffset));
676}
677
678/* clear out the current logical bitstream decoder */
679static void _decode_clear(OggVorbis_File *vf){
680 vorbis_dsp_clear(&vf->vd);
681 vorbis_block_clear(&vf->vb);
682 vf->ready_state=OPENED;
683}
684
685/* fetch and process a packet. Handles the case where we're at a
686 bitstream boundary and dumps the decoding machine. If the decoding
687 machine is unloaded, it loads it. It also keeps pcm_offset up to
688 date (seek and read both use this. seek uses a special hack with
689 readp).
690
691 return: <0) error, OV_HOLE (lost packet) or OV_EOF
692 0) need more data (only if readp==0)
693 1) got a packet
694*/
695
696static int _fetch_and_process_packet(OggVorbis_File *vf,
697 ogg_packet *op_in,
698 int readp,
699 int spanp){
700 ogg_page og;
701
702 /* handle one packet. Try to fetch it from current stream state */
703 /* extract packets from page */
704 while(1){
705
706 if(vf->ready_state==STREAMSET){
707 int ret=_make_decode_ready(vf);
708 if(ret<0)return ret;
709 }
710
711 /* process a packet if we can. If the machine isn't loaded,
712 neither is a page */
713 if(vf->ready_state==INITSET){
714 while(1) {
715 ogg_packet op;
716 ogg_packet *op_ptr=(op_in?op_in:&op);
717 int result=ogg_stream_packetout(&vf->os,op_ptr);
718 ogg_int64_t granulepos;
719
720 op_in=NULL;
721 if(result==-1)return(OV_HOLE); /* hole in the data. */
722 if(result>0){
723 /* got a packet. process it */
724 granulepos=op_ptr->granulepos;
725 if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
726 header handling. The
727 header packets aren't
728 audio, so if/when we
729 submit them,
730 vorbis_synthesis will
731 reject them */
732
733 /* suck in the synthesis data and track bitrate */
734 {
735 int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
736 /* for proper use of libvorbis within libvorbisfile,
737 oldsamples will always be zero. */
738 if(oldsamples)return(OV_EFAULT);
739
740 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
741 vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
742 vf->bittrack+=op_ptr->bytes*8;
743 }
744
745 /* update the pcm offset. */
746 if(granulepos!=-1 && !op_ptr->e_o_s){
747 int link=(vf->seekable?vf->current_link:0);
748 int i,samples;
749
750 /* this packet has a pcm_offset on it (the last packet
751 completed on a page carries the offset) After processing
752 (above), we know the pcm position of the *last* sample
753 ready to be returned. Find the offset of the *first*
754
755 As an aside, this trick is inaccurate if we begin
756 reading anew right at the last page; the end-of-stream
757 granulepos declares the last frame in the stream, and the
758 last packet of the last page may be a partial frame.
759 So, we need a previous granulepos from an in-sequence page
760 to have a reference point. Thus the !op_ptr->e_o_s clause
761 above */
762
763 if(vf->seekable && link>0)
764 granulepos-=vf->pcmlengths[link*2];
765 if(granulepos<0)granulepos=0; /* actually, this
766 shouldn't be possible
767 here unless the stream
768 is very broken */
769
770 samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
771
772 granulepos-=samples;
773 for(i=0;i<link;i++)
774 granulepos+=vf->pcmlengths[i*2+1];
775 vf->pcm_offset=granulepos;
776 }
777 return(1);
778 }
779 }
780 else
781 break;
782 }
783 }
784
785 if(vf->ready_state>=OPENED){
786 ogg_int64_t ret;
787
788 while(1){
789 /* the loop is not strictly necessary, but there's no sense in
790 doing the extra checks of the larger loop for the common
791 case in a multiplexed bistream where the page is simply
792 part of a different logical bitstream; keep reading until
793 we get one with the correct serialno */
794
795 if(!readp)return(0);
796 if((ret=_get_next_page(vf,&og,-1))<0){
797 return(OV_EOF); /* eof. leave unitialized */
798 }
799
800 /* bitrate tracking; add the header's bytes here, the body bytes
801 are done by packet above */
802 vf->bittrack+=og.header_len*8;
803
804 if(vf->ready_state==INITSET){
805 if(vf->current_serialno!=ogg_page_serialno(&og)){
806
807 /* two possibilities:
808 1) our decoding just traversed a bitstream boundary
809 2) another stream is multiplexed into this logical section */
810
811 if(ogg_page_bos(&og)){
812 /* boundary case */
813 if(!spanp)
814 return(OV_EOF);
815
816 _decode_clear(vf);
817
818 if(!vf->seekable){
819 vorbis_info_clear(vf->vi);
820/* vorbis_comment_clear(vf->vc); */
821 }
822 break;
823
824 }else
825 continue; /* possibility #2 */
826 }
827 }
828
829 break;
830 }
831 }
832
833 /* Do we need to load a new machine before submitting the page? */
834 /* This is different in the seekable and non-seekable cases.
835
836 In the seekable case, we already have all the header
837 information loaded and cached; we just initialize the machine
838 with it and continue on our merry way.
839
840 In the non-seekable (streaming) case, we'll only be at a
841 boundary if we just left the previous logical bitstream and
842 we're now nominally at the header of the next bitstream
843 */
844
845 if(vf->ready_state!=INITSET){
846 int link;
847
848 if(vf->ready_state<STREAMSET){
849 if(vf->seekable){
850 ogg_uint32_t serialno = ogg_page_serialno(&og);
851
852 /* match the serialno to bitstream section. We use this rather than
853 offset positions to avoid problems near logical bitstream
854 boundaries */
855
856 for(link=0;link<vf->links;link++)
857 if(vf->serialnos[link]==serialno)break;
858
859 if(link==vf->links) continue; /* not the desired Vorbis
860 bitstream section; keep
861 trying */
862
863 vf->current_serialno=serialno;
864 vf->current_link=link;
865
866 ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
867 vf->ready_state=STREAMSET;
868
869 }else{
870 /* we're streaming */
871 /* fetch the three header packets, build the info struct */
872
873 int ret=_fetch_headers(vf,vf->vi,NULL,NULL,&og);
874 if(ret)return(ret);
875 vf->current_serialno=vf->os.serialno;
876 vf->current_link++;
877 link=0;
878 }
879 }
880 }
881
882 /* the buffered page is the data we want, and we're ready for it;
883 add it to the stream state */
884 ogg_stream_pagein(&vf->os,&og,true);
885
886 }
887}
888
889static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
890 long ibytes, ov_callbacks callbacks){
891 int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
892 ogg_uint32_t *serialno_list=NULL;
893 int serialno_list_size=0;
894 int ret;
895
896 memset(vf,0,sizeof(*vf));
897 vf->datasource=f;
898 vf->callbacks = callbacks;
899
900 /* init the framing state */
901 ogg_sync_init(&vf->oy);
902
903 /* perhaps some data was previously read into a buffer for testing
904 against other stream types. Allow initialization from this
905 previously read data (especially as we may be reading from a
906 non-seekable stream) */
907 if(initial){
908 char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
909 memcpy(buffer,initial,ibytes);
910 ogg_sync_wrote(&vf->oy,ibytes);
911 }
912
913 /* can we seek? Stevens suggests the seek test was portable */
914 if(offsettest!=-1)vf->seekable=1;
915
916 /* No seeking yet; Set up a 'single' (current) logical bitstream
917 entry for partial open */
918 vf->links=1;
919 vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
920/* vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); */
921 ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
922
923 /* Fetch all BOS pages, store the vorbis header and all seen serial
924 numbers, load subsequent vorbis setup headers */
925 if((ret=_fetch_headers(vf,vf->vi,&serialno_list,&serialno_list_size,NULL))<0){
926 vf->datasource=NULL;
927 ov_clear(vf);
928 }else{
929 /* serial number list for first link needs to be held somewhere
930 for second stage of seekable stream open; this saves having to
931 seek/reread first link's serialnumber data then. */
932 vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
933 vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
934 vf->serialnos[1]=serialno_list_size;
935 memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
936
937 vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
938 vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
939 vf->offsets[0]=0;
940 vf->dataoffsets[0]=vf->offset;
941
942 vf->ready_state=PARTOPEN;
943 }
944 if(serialno_list)_ogg_free(serialno_list);
945 return(ret);
946}
947
948static int _ov_open2(OggVorbis_File *vf){
949 if(vf->ready_state != PARTOPEN) return OV_EINVAL;
950 vf->ready_state=OPENED;
951 if(vf->seekable){
952 int ret=_open_seekable2(vf);
953 if(ret){
954 vf->datasource=NULL;
955 ov_clear(vf);
956 }
957 return(ret);
958 }else
959 vf->ready_state=STREAMSET;
960
961 return 0;
962}
963
964
965/* clear out the OggVorbis_File struct */
966int ov_clear(OggVorbis_File *vf){
967 if(vf){
968 vorbis_block_clear(&vf->vb);
969 vorbis_dsp_clear(&vf->vd);
970 ogg_stream_clear(&vf->os);
971
972 if(vf->vi && vf->links){
973 int i;
974 for(i=0;i<vf->links;i++){
975 vorbis_info_clear(vf->vi+i);
976/* vorbis_comment_clear(vf->vc+i); */
977 }
978 _ogg_free(vf->vi);
979/* _ogg_free(vf->vc); */
980 }
981 if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
982 if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
983 if(vf->serialnos)_ogg_free(vf->serialnos);
984 if(vf->offsets)_ogg_free(vf->offsets);
985 ogg_sync_clear(&vf->oy);
986 if(vf->datasource && vf->callbacks.close_func)
987 (vf->callbacks.close_func)(vf->datasource);
988 memset(vf,0,sizeof(*vf));
989 }
990#ifdef DEBUG_LEAKS
991 _VDBG_dump();
992#endif
993 return(0);
994}
995
996/* inspects the OggVorbis file and finds/documents all the logical
997 bitstreams contained in it. Tries to be tolerant of logical
998 bitstream sections that are truncated/woogie.
999
1000 return: -1) error
1001 0) OK
1002*/
1003
1004int ov_open_callbacks(void *f,OggVorbis_File *vf,
1005 const char *initial,long ibytes,ov_callbacks callbacks){
1006 #if defined(CPU_COLDFIRE)
1007 /* this seems to be the closest we get to an init function, let's init emac
1008 here. rounding is disabled because of MULT31_SHIFT15, which will be
1009 inaccurate with rounding in its current incarnation */
1010 coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
1011 #endif
1012 int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
1013 if(ret)return ret;
1014 return _ov_open2(vf);
1015}
1016
1017/* returns: total PCM length (samples) of content if i==-1 PCM length
1018 (samples) of that logical bitstream for i==0 to n
1019 OV_EINVAL if the stream is not seekable (we can't know the
1020 length) or only partially open
1021*/
1022ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
1023 if(vf->ready_state<OPENED)return(OV_EINVAL);
1024 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1025 if(i<0){
1026 ogg_int64_t acc=0;
1027 int i;
1028 for(i=0;i<vf->links;i++)
1029 acc+=ov_pcm_total(vf,i);
1030 return(acc);
1031 }else{
1032 return(vf->pcmlengths[i*2+1]);
1033 }
1034}
1035
1036/* returns: total milliseconds of content if i==-1
1037 milliseconds in that logical bitstream for i==0 to n
1038 OV_EINVAL if the stream is not seekable (we can't know the
1039 length) or only partially open
1040*/
1041ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
1042 if(vf->ready_state<OPENED)return(OV_EINVAL);
1043 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1044 if(i<0){
1045 ogg_int64_t acc=0;
1046 int i;
1047 for(i=0;i<vf->links;i++)
1048 acc+=ov_time_total(vf,i);
1049 return(acc);
1050 }else{
1051 return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
1052 }
1053}
1054
1055/* seek to an offset relative to the *compressed* data. This also
1056 scans packets to update the PCM cursor. It will cross a logical
1057 bitstream boundary, but only if it can't get any packets out of the
1058 tail of the bitstream we seek to (so no surprises).
1059
1060 returns zero on success, nonzero on failure */
1061
1062int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
1063 ogg_stream_state work_os;
1064 int ret;
1065
1066 if(vf->ready_state<OPENED)return(OV_EINVAL);
1067 if(!vf->seekable)
1068 return(OV_ENOSEEK); /* don't dump machine if we can't seek */
1069
1070 if(pos<0 || pos>vf->end)return(OV_EINVAL);
1071
1072 /* is the seek position outside our current link [if any]? */
1073 if(vf->ready_state>=STREAMSET){
1074 if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1])
1075 _decode_clear(vf); /* clear out stream state */
1076 }
1077
1078 /* don't yet clear out decoding machine (if it's initialized), in
1079 the case we're in the same link. Restart the decode lapping, and
1080 let _fetch_and_process_packet deal with a potential bitstream
1081 boundary */
1082 vf->pcm_offset=-1;
1083 ogg_stream_reset_serialno(&vf->os,
1084 vf->current_serialno); /* must set serialno */
1085 vorbis_synthesis_restart(&vf->vd);
1086
1087 ret=_seek_helper(vf,pos);
1088 if(ret)goto seek_error;
1089
1090 /* we need to make sure the pcm_offset is set, but we don't want to
1091 advance the raw cursor past good packets just to get to the first
1092 with a granulepos. That's not equivalent behavior to beginning
1093 decoding as immediately after the seek position as possible.
1094
1095 So, a hack. We use two stream states; a local scratch state and
1096 the shared vf->os stream state. We use the local state to
1097 scan, and the shared state as a buffer for later decode.
1098
1099 Unfortuantely, on the last page we still advance to last packet
1100 because the granulepos on the last page is not necessarily on a
1101 packet boundary, and we need to make sure the granpos is
1102 correct.
1103 */
1104
1105 {
1106 ogg_page og;
1107 ogg_packet op;
1108 int lastblock=0;
1109 int accblock=0;
1110 int thisblock=0;
1111 int lastflag=0;
1112 int firstflag=0;
1113 ogg_int64_t pagepos=-1;
1114
1115 ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
1116 ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
1117 return from not necessarily
1118 starting from the beginning */
1119
1120 while(1){
1121 if(vf->ready_state>=STREAMSET){
1122 /* snarf/scan a packet if we can */
1123 int result=ogg_stream_packetout(&work_os,&op);
1124
1125 if(result>0){
1126
1127 if(vf->vi[vf->current_link].codec_setup){
1128 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1129 if(thisblock<0){
1130 ogg_stream_packetout(&vf->os,NULL);
1131 thisblock=0;
1132 }else{
1133
1134 /* We can't get a guaranteed correct pcm position out of the
1135 last page in a stream because it might have a 'short'
1136 granpos, which can only be detected in the presence of a
1137 preceding page. However, if the last page is also the first
1138 page, the granpos rules of a first page take precedence. Not
1139 only that, but for first==last, the EOS page must be treated
1140 as if its a normal first page for the stream to open/play. */
1141 if(lastflag && !firstflag)
1142 ogg_stream_packetout(&vf->os,NULL);
1143 else
1144 if(lastblock)accblock+=(lastblock+thisblock)>>2;
1145 }
1146
1147 if(op.granulepos!=-1){
1148 int i,link=vf->current_link;
1149 ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1150 if(granulepos<0)granulepos=0;
1151
1152 for(i=0;i<link;i++)
1153 granulepos+=vf->pcmlengths[i*2+1];
1154 vf->pcm_offset=granulepos-accblock;
1155 if(vf->pcm_offset<0)vf->pcm_offset=0;
1156 break;
1157 }
1158 lastblock=thisblock;
1159 continue;
1160 }else
1161 ogg_stream_packetout(&vf->os,NULL);
1162 }
1163 }
1164
1165 if(!lastblock){
1166 pagepos=_get_next_page(vf,&og,-1);
1167 if(pagepos<0){
1168 vf->pcm_offset=ov_pcm_total(vf,-1);
1169 break;
1170 }
1171 }else{
1172 /* huh? Bogus stream with packets but no granulepos */
1173 vf->pcm_offset=-1;
1174 break;
1175 }
1176
1177 /* has our decoding just traversed a bitstream boundary? */
1178 if(vf->ready_state>=STREAMSET){
1179 if(vf->current_serialno!=ogg_page_serialno(&og)){
1180
1181 /* two possibilities:
1182 1) our decoding just traversed a bitstream boundary
1183 2) another stream is multiplexed into this logical section? */
1184
1185 if(ogg_page_bos(&og)){
1186 /* we traversed */
1187 _decode_clear(vf); /* clear out stream state */
1188 ogg_stream_clear(&work_os);
1189 } /* else, do nothing; next loop will scoop another page */
1190 }
1191 }
1192
1193 if(vf->ready_state<STREAMSET){
1194 int link;
1195 ogg_uint32_t serialno = ogg_page_serialno(&og);
1196
1197 for(link=0;link<vf->links;link++)
1198 if(vf->serialnos[link]==serialno)break;
1199
1200 if(link==vf->links) continue; /* not the desired Vorbis
1201 bitstream section; keep
1202 trying */
1203 vf->current_link=link;
1204 vf->current_serialno=serialno;
1205 ogg_stream_reset_serialno(&vf->os,serialno);
1206 ogg_stream_reset_serialno(&work_os,serialno);
1207 vf->ready_state=STREAMSET;
1208 firstflag=(pagepos<=vf->dataoffsets[link]);
1209 }
1210
1211 ogg_stream_pagein(&vf->os,&og,true);
1212 ogg_stream_pagein(&work_os,&og,true);
1213 lastflag=ogg_page_eos(&og);
1214
1215 }
1216 }
1217
1218 ogg_stream_clear(&work_os);
1219 vf->bittrack=0;
1220 vf->samptrack=0;
1221 return(0);
1222
1223 seek_error:
1224 /* dump the machine so we're in a known state */
1225 vf->pcm_offset=-1;
1226 ogg_stream_clear(&work_os);
1227 _decode_clear(vf);
1228 return OV_EBADLINK;
1229}
1230
1231/* rescales the number x from the range of [0,from] to [0,to]
1232 x is in the range [0,from]
1233 from, to are in the range [1, 1<<62-1] */
1234ogg_int64_t rescale64(ogg_int64_t x, ogg_int64_t from, ogg_int64_t to){
1235 ogg_int64_t frac=0;
1236 ogg_int64_t ret=0;
1237 int i;
1238 if(x >= from) return to;
1239 if(x <= 0) return 0;
1240
1241 for(i=0;i<64;i++){
1242 if(x>=from){
1243 frac|=1;
1244 x-=from;
1245 }
1246 x<<=1;
1247 frac<<=1;
1248 }
1249
1250 for(i=0;i<64;i++){
1251 if(frac & 1){
1252 ret+=to;
1253 }
1254 frac>>=1;
1255 ret>>=1;
1256 }
1257
1258 return ret;
1259}
1260
1261/* Page granularity seek (faster than sample granularity because we
1262 don't do the last bit of decode to find a specific sample).
1263
1264 Seek to the last [granule marked] page preceding the specified pos
1265 location, such that decoding past the returned point will quickly
1266 arrive at the requested position. */
1267int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1268 int link=-1;
1269 ogg_int64_t result=0;
1270 ogg_int64_t total=ov_pcm_total(vf,-1);
1271
1272 if(vf->ready_state<OPENED)return(OV_EINVAL);
1273 if(!vf->seekable)return(OV_ENOSEEK);
1274
1275 if(pos<0 || pos>total)return(OV_EINVAL);
1276
1277 /* which bitstream section does this pcm offset occur in? */
1278 for(link=vf->links-1;link>=0;link--){
1279 total-=vf->pcmlengths[link*2+1];
1280 if(pos>=total)break;
1281 }
1282
1283 /* search within the logical bitstream for the page with the highest
1284 pcm_pos preceding (or equal to) pos. There is a danger here;
1285 missing pages or incorrect frame number information in the
1286 bitstream could make our task impossible. Account for that (it
1287 would be an error condition) */
1288
1289 /* new search algorithm by HB (Nicholas Vinen) */
1290 {
1291 ogg_int64_t end=vf->offsets[link+1];
1292 ogg_int64_t begin=vf->offsets[link];
1293 ogg_int64_t begintime = vf->pcmlengths[link*2];
1294 ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1295 ogg_int64_t target=pos-total+begintime;
1296 ogg_int64_t best=begin;
1297
1298 ogg_page og;
1299 while(begin<end){
1300 ogg_int64_t bisect;
1301
1302 if(end-begin<CHUNKSIZE){
1303 bisect=begin;
1304 }else{
1305 /* take a (pretty decent) guess. */
1306 bisect=begin + rescale64(target-begintime,
1307 endtime-begintime,
1308 end-begin) - CHUNKSIZE;
1309 if(bisect<begin+CHUNKSIZE)
1310 bisect=begin;
1311 }
1312
1313 if(bisect!=vf->offset){
1314 result=_seek_helper(vf,bisect);
1315 if(result) goto seek_error;
1316 }
1317
1318 while(begin<end){
1319 result=_get_next_page(vf,&og,end-vf->offset);
1320 if(result==OV_EREAD) goto seek_error;
1321 if(result<0){
1322 if(bisect<=begin+1)
1323 end=begin; /* found it */
1324 else{
1325 if(bisect==0) goto seek_error;
1326 bisect-=CHUNKSIZE;
1327 if(bisect<=begin)bisect=begin+1;
1328 result=_seek_helper(vf,bisect);
1329 if(result) goto seek_error;
1330 }
1331 }else{
1332 ogg_int64_t granulepos;
1333
1334 if(ogg_page_serialno(&og)!=vf->serialnos[link])
1335 continue;
1336
1337 granulepos=ogg_page_granulepos(&og);
1338 if(granulepos==-1)continue;
1339
1340 if(granulepos<target){
1341 best=result; /* raw offset of packet with granulepos */
1342 begin=vf->offset; /* raw offset of next page */
1343 begintime=granulepos;
1344
1345 if(target-begintime>44100)break;
1346 bisect=begin; /* *not* begin + 1 */
1347 }else{
1348 if(bisect<=begin+1)
1349 end=begin; /* found it */
1350 else{
1351 if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1352 end=result;
1353 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1354 if(bisect<=begin)bisect=begin+1;
1355 result=_seek_helper(vf,bisect);
1356 if(result) goto seek_error;
1357 }else{
1358 end=bisect;
1359 endtime=granulepos;
1360 break;
1361 }
1362 }
1363 }
1364 }
1365 }
1366 }
1367
1368 /* found our page. seek to it, update pcm offset. Easier case than
1369 raw_seek, don't keep packets preceding granulepos. */
1370 {
1371 ogg_page og;
1372 ogg_packet op;
1373
1374 /* seek */
1375 result=_seek_helper(vf,best);
1376 vf->pcm_offset=-1;
1377 if(result) goto seek_error;
1378 result=_get_next_page(vf,&og,-1);
1379 if(result<0) goto seek_error;
1380
1381 if(link!=vf->current_link){
1382 /* Different link; dump entire decode machine */
1383 _decode_clear(vf);
1384
1385 vf->current_link=link;
1386 vf->current_serialno=vf->serialnos[link];
1387 vf->ready_state=STREAMSET;
1388
1389 }else{
1390 vorbis_synthesis_restart(&vf->vd);
1391 }
1392
1393 ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1394 ogg_stream_pagein(&vf->os,&og,true);
1395
1396 /* pull out all but last packet; the one with granulepos */
1397 while(1){
1398 result=ogg_stream_packetpeek(&vf->os,&op);
1399 if(result==0){
1400 /* !!! the packet finishing this page originated on a
1401 preceding page. Keep fetching previous pages until we
1402 get one with a granulepos or without the 'continued' flag
1403 set. Then just use raw_seek for simplicity. */
1404
1405 result=_seek_helper(vf,best);
1406 if(result<0) goto seek_error;
1407
1408 while(1){
1409 result=_get_prev_page(vf,&og);
1410 if(result<0) goto seek_error;
1411 if(ogg_page_serialno(&og)==vf->current_serialno &&
1412 (ogg_page_granulepos(&og)>-1 ||
1413 !ogg_page_continued(&og))){
1414 return ov_raw_seek(vf,result);
1415 }
1416 vf->offset=result;
1417 }
1418 }
1419 if(result<0){
1420 result = OV_EBADPACKET;
1421 goto seek_error;
1422 }
1423 if(op.granulepos!=-1){
1424 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1425 if(vf->pcm_offset<0)vf->pcm_offset=0;
1426 vf->pcm_offset+=total;
1427 break;
1428 }else
1429 result=ogg_stream_packetout(&vf->os,NULL);
1430 }
1431 }
1432 }
1433
1434 /* verify result */
1435 if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1436 result=OV_EFAULT;
1437 goto seek_error;
1438 }
1439 vf->bittrack=0;
1440 vf->samptrack=0;
1441 return(0);
1442
1443 seek_error:
1444 /* dump machine so we're in a known state */
1445 vf->pcm_offset=-1;
1446 _decode_clear(vf);
1447 return (int)result;
1448}
1449
1450/* seek to a sample offset relative to the decompressed pcm stream
1451 returns zero on success, nonzero on failure */
1452
1453int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1454 int thisblock,lastblock=0;
1455 int ret=ov_pcm_seek_page(vf,pos);
1456 if(ret<0)return(ret);
1457 if((ret=_make_decode_ready(vf)))return ret;
1458
1459 /* discard leading packets we don't need for the lapping of the
1460 position we want; don't decode them */
1461
1462 while(1){
1463 ogg_packet op;
1464 ogg_page og;
1465
1466 int ret=ogg_stream_packetpeek(&vf->os,&op);
1467 if(ret>0){
1468 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1469 if(thisblock<0){
1470 ogg_stream_packetout(&vf->os,NULL);
1471 continue; /* non audio packet */
1472 }
1473 if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1474
1475 if(vf->pcm_offset+((thisblock+
1476 vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1477
1478 /* remove the packet from packet queue and track its granulepos */
1479 ogg_stream_packetout(&vf->os,NULL);
1480 vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with
1481 only tracking, no
1482 pcm_decode */
1483 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
1484
1485 /* end of logical stream case is hard, especially with exact
1486 length positioning. */
1487
1488 if(op.granulepos>-1){
1489 int i;
1490 /* always believe the stream markers */
1491 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1492 if(vf->pcm_offset<0)vf->pcm_offset=0;
1493 for(i=0;i<vf->current_link;i++)
1494 vf->pcm_offset+=vf->pcmlengths[i*2+1];
1495 }
1496
1497 lastblock=thisblock;
1498
1499 }else{
1500 if(ret<0 && ret!=OV_HOLE)break;
1501
1502 /* suck in a new page */
1503 if(_get_next_page(vf,&og,-1)<0)break;
1504 if(ogg_page_bos(&og))_decode_clear(vf);
1505
1506 if(vf->ready_state<STREAMSET){
1507 long serialno=ogg_page_serialno(&og);
1508 int link;
1509
1510 for(link=0;link<vf->links;link++)
1511 if(vf->serialnos[link]==(ogg_uint32_t) serialno)break;
1512 if(link==vf->links) continue;
1513 vf->current_link=link;
1514
1515 vf->ready_state=STREAMSET;
1516 vf->current_serialno=ogg_page_serialno(&og);
1517 ogg_stream_reset_serialno(&vf->os,serialno);
1518 ret=_make_decode_ready(vf);
1519 if(ret)return ret;
1520 lastblock=0;
1521 }
1522
1523 ogg_stream_pagein(&vf->os,&og,true);
1524 }
1525 }
1526
1527 vf->bittrack=0;
1528 vf->samptrack=0;
1529 /* discard samples until we reach the desired position. Crossing a
1530 logical bitstream boundary with abandon is OK. */
1531 while(vf->pcm_offset<pos){
1532 ogg_int64_t target=pos-vf->pcm_offset;
1533 long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1534
1535 if(samples>target)samples=target;
1536 vorbis_synthesis_read(&vf->vd,samples);
1537 vf->pcm_offset+=samples;
1538
1539 if(samples<target)
1540 if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
1541 vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1542 }
1543 return 0;
1544}
1545
1546/* seek to a playback time relative to the decompressed pcm stream
1547 returns zero on success, nonzero on failure */
1548int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
1549 /* translate time to PCM position and call ov_pcm_seek */
1550
1551 int link=-1;
1552 ogg_int64_t pcm_total=0;
1553 ogg_int64_t time_total=0;
1554
1555 if(vf->ready_state<OPENED)return(OV_EINVAL);
1556 if(!vf->seekable)return(OV_ENOSEEK);
1557 if(milliseconds<0)return(OV_EINVAL);
1558
1559 /* which bitstream section does this time offset occur in? */
1560 for(link=0;link<vf->links;link++){
1561 ogg_int64_t addsec = ov_time_total(vf,link);
1562 if(milliseconds<time_total+addsec)break;
1563 time_total+=addsec;
1564 pcm_total+=vf->pcmlengths[link*2+1];
1565 }
1566
1567 if(link==vf->links)return(OV_EINVAL);
1568
1569 /* enough information to convert time offset to pcm offset */
1570 {
1571 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
1572 return(ov_pcm_seek(vf,target));
1573 }
1574}
1575
1576/* tell the current stream offset cursor. Note that seek followed by
1577 tell will likely not give the set offset due to caching */
1578ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1579 if(vf->ready_state<OPENED)return(OV_EINVAL);
1580 return(vf->offset);
1581}
1582
1583/* return time offset (milliseconds) of next PCM sample to be read */
1584ogg_int64_t ov_time_tell(OggVorbis_File *vf){
1585 int link=0;
1586 ogg_int64_t pcm_total=0;
1587 ogg_int64_t time_total=0;
1588
1589 if(vf->ready_state<OPENED)return(OV_EINVAL);
1590 if(vf->seekable){
1591 pcm_total=ov_pcm_total(vf,-1);
1592 time_total=ov_time_total(vf,-1);
1593
1594 /* which bitstream section does this time offset occur in? */
1595 for(link=vf->links-1;link>=0;link--){
1596 pcm_total-=vf->pcmlengths[link*2+1];
1597 time_total-=ov_time_total(vf,link);
1598 if(vf->pcm_offset>=pcm_total)break;
1599 }
1600 }
1601
1602 return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1603}
1604
1605/* link: -1) return the vorbis_info struct for the bitstream section
1606 currently being decoded
1607 0-n) to request information for a specific bitstream section
1608
1609 In the case of a non-seekable bitstream, any call returns the
1610 current bitstream. NULL in the case that the machine is not
1611 initialized */
1612
1613vorbis_info *ov_info(OggVorbis_File *vf,int link){
1614 if(vf->seekable){
1615 if(link<0)
1616 if(vf->ready_state>=STREAMSET)
1617 return vf->vi+vf->current_link;
1618 else
1619 return vf->vi;
1620 else
1621 if(link>=vf->links)
1622 return NULL;
1623 else
1624 return vf->vi+link;
1625 }else{
1626 return vf->vi;
1627 }
1628}
1629
1630/* input values: pcm_channels) a float vector per channel of output
1631 length) the sample length being read by the app
1632
1633 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1634 0) EOF
1635 n) number of samples of PCM actually returned. The
1636 below works on a packet-by-packet basis, so the
1637 return length is not related to the 'length' passed
1638 in, just guaranteed to fit.
1639
1640 *section) set to the logical bitstream number */
1641
1642long ov_read_fixed(OggVorbis_File *vf,ogg_int32_t ***pcm_channels,int length,
1643 int *bitstream){
1644 if(vf->ready_state<OPENED)return(OV_EINVAL);
1645
1646 while(1){
1647 if(vf->ready_state==INITSET){
1648 ogg_int32_t **pcm;
1649 long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1650 if(samples){
1651 if(pcm_channels)*pcm_channels=pcm;
1652 if(samples>length)samples=length;
1653 vorbis_synthesis_read(&vf->vd,samples);
1654 vf->pcm_offset+=samples;
1655 if(bitstream)*bitstream=vf->current_link;
1656 return samples;
1657
1658 }
1659 }
1660
1661 /* suck in another packet */
1662 {
1663 int ret=_fetch_and_process_packet(vf,NULL,1,1);
1664 if(ret==OV_EOF)
1665 return(0);
1666 if(ret<=0)
1667 return(ret);
1668 }
1669 }
1670}
1671