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