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