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