1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
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. *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
12 ********************************************************************
14 function: stdio-based convenience library for opening/seeking/decoding
17 ********************************************************************/
19 #include "config-tremor.h"
26 #include "ivorbiscodec.h"
27 #include "ivorbisfile.h"
32 /* A 'chained bitstream' is a Vorbis bitstream that contains more than
33 one logical bitstream arranged end to end (the only form of Ogg
34 multiplexing allowed in a Vorbis bitstream; grouping [parallel
35 multiplexing] is not allowed in Vorbis) */
37 /* A Vorbis file can be played beginning to end (streamed) without
38 worrying ahead of time about chaining (see decoder_example.c). If
39 we have the whole file, however, and want random access
40 (seeking/scrubbing) or desire to know the total length/time of a
41 file, we need to account for the possibility of chaining. */
43 /* We can handle things a number of ways; we can determine the entire
44 bitstream structure right off the bat, or find pieces on demand.
45 This example determines and caches structure for the entire
46 bitstream, but builds a virtual decoder on the fly when moving
47 between links in the chain. */
49 /* There are also different ways to implement seeking. Enough
50 information exists in an Ogg bitstream to seek to
51 sample-granularity positions in the output. Or, one can seek by
52 picking some portion of the stream roughly in the desired area if
53 we only want coarse navigation through the stream. */
55 /*************************************************************************
56 * Many, many internal helpers. The intention is not to be confusing;
57 * rampant duplication and monolithic function implementation would be
58 * harder to understand anyway. The high level functions are last. Begin
59 * grokking near the end of the file */
62 /* read a little more data from the file/pipe into the ogg_sync framer */
63 static long _get_data(OggVorbis_File
*vf
){
65 char *buffer
=(char *)ogg_sync_bufferin(vf
->oy
,CHUNKSIZE
);
66 long bytes
=(vf
->callbacks
.read_func
)(buffer
,1,CHUNKSIZE
,vf
->datasource
);
67 if(bytes
>0)ogg_sync_wrote(vf
->oy
,bytes
);
73 /* save a tiny smidge of verbosity to make the code more readable */
74 static void _seek_helper(OggVorbis_File
*vf
,ogg_int64_t offset
){
76 (vf
->callbacks
.seek_func
)(vf
->datasource
, offset
, SEEK_SET
);
78 ogg_sync_reset(vf
->oy
);
80 /* shouldn't happen unless someone writes a broken callback */
85 /* The read/seek functions track absolute position within the stream */
87 /* from the head of the stream, get the next page. boundary specifies
88 if the function is allowed to fetch more data from the stream (and
89 how much) or only use internally buffered data.
91 boundary: -1) unbounded search
92 0) read no additional data; use cached only
93 n) search for a new page beginning for n bytes
95 return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
96 n) found a page at absolute offset n
98 produces a refcounted page */
100 static ogg_int64_t
_get_next_page(OggVorbis_File
*vf
,ogg_page
*og
,
101 ogg_int64_t boundary
){
102 if(boundary
>0)boundary
+=vf
->offset
;
106 if(boundary
>0 && vf
->offset
>=boundary
)return(OV_FALSE
);
107 more
=ogg_sync_pageseek(vf
->oy
,og
);
110 /* skipped n bytes */
114 /* send more paramedics */
115 if(!boundary
)return(OV_FALSE
);
117 long ret
=_get_data(vf
);
118 if(ret
==0)return(OV_EOF
);
119 if(ret
<0)return(OV_EREAD
);
122 /* got a page. Return the offset at the page beginning,
123 advance the internal offset past the page end */
124 ogg_int64_t ret
=vf
->offset
;
133 /* find the latest page beginning before the current stream cursor
134 position. Much dirtier than the above as Ogg doesn't have any
135 backward search linkage. no 'readp' as it will certainly have to
137 /* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */
139 static ogg_int64_t
_get_prev_page(OggVorbis_File
*vf
,ogg_page
*og
){
140 ogg_int64_t begin
=vf
->offset
;
141 ogg_int64_t end
=begin
;
143 ogg_int64_t offset
=-1;
149 _seek_helper(vf
,begin
);
150 while(vf
->offset
<end
){
151 ret
=_get_next_page(vf
,og
,end
-vf
->offset
);
152 if(ret
==OV_EREAD
)return(OV_EREAD
);
161 /* we have the offset. Actually snork and hold the page now */
162 _seek_helper(vf
,offset
);
163 ret
=_get_next_page(vf
,og
,CHUNKSIZE
);
165 /* this shouldn't be possible */
171 /* finds each bitstream link one at a time using a bisection search
172 (has to begin by knowing the offset of the lb's initial page).
173 Recurses for each link so it can alloc the link storage after
174 finding them all, then unroll and fill the cache at the same time */
175 static int _bisect_forward_serialno(OggVorbis_File
*vf
,
177 ogg_int64_t searched
,
179 ogg_uint32_t currentno
,
181 ogg_int64_t endsearched
=end
;
182 ogg_int64_t next
=end
;
183 ogg_page og
={0,0,0,0};
186 /* the below guards against garbage seperating the last and
187 first pages of two links. */
188 while(searched
<endsearched
){
191 if(endsearched
-searched
<CHUNKSIZE
){
194 bisect
=(searched
+endsearched
)/2;
197 _seek_helper(vf
,bisect
);
198 ret
=_get_next_page(vf
,&og
,-1);
199 if(ret
==OV_EREAD
)return(OV_EREAD
);
200 if(ret
<0 || ogg_page_serialno(&og
)!=currentno
){
204 searched
=ret
+og
.header_len
+og
.body_len
;
206 ogg_page_release(&og
);
209 _seek_helper(vf
,next
);
210 ret
=_get_next_page(vf
,&og
,-1);
211 if(ret
==OV_EREAD
)return(OV_EREAD
);
213 if(searched
>=end
|| ret
<0){
214 ogg_page_release(&og
);
216 vf
->offsets
=_ogg_malloc((vf
->links
+1)*sizeof(*vf
->offsets
));
217 vf
->serialnos
=_ogg_malloc(vf
->links
*sizeof(*vf
->serialnos
));
218 vf
->offsets
[m
+1]=searched
;
220 ret
=_bisect_forward_serialno(vf
,next
,vf
->offset
,
221 end
,ogg_page_serialno(&og
),m
+1);
222 ogg_page_release(&og
);
223 if(ret
==OV_EREAD
)return(OV_EREAD
);
226 vf
->offsets
[m
]=begin
;
227 vf
->serialnos
[m
]=currentno
;
231 /* uses the local ogg_stream storage in vf; this is important for
232 non-streaming input sources */
233 /* consumes the page that's passed in (if any) */
235 static int _fetch_headers(OggVorbis_File
*vf
,
238 ogg_uint32_t
*serialno
,
240 ogg_page og
={0,0,0,0};
241 ogg_packet op
={0,0,0,0,0,0};
245 ogg_int64_t llret
=_get_next_page(vf
,&og
,CHUNKSIZE
);
246 if(llret
==OV_EREAD
)return(OV_EREAD
);
247 if(llret
<0)return OV_ENOTVORBIS
;
251 ogg_stream_reset_serialno(vf
->os
,ogg_page_serialno(og_ptr
));
252 if(serialno
)*serialno
=vf
->os
->serialno
;
253 vf
->ready_state
=STREAMSET
;
255 /* extract the initial header from the first page and verify that the
256 Ogg bitstream is in fact Vorbis data */
258 vorbis_info_init(vi
);
259 vorbis_comment_init(vc
);
263 ogg_stream_pagein(vf
->os
,og_ptr
);
265 int result
=ogg_stream_packetout(vf
->os
,&op
);
271 if((ret
=vorbis_synthesis_headerin(vi
,vc
,&op
))){
277 if(_get_next_page(vf
,og_ptr
,CHUNKSIZE
)<0){
283 ogg_packet_release(&op
);
284 ogg_page_release(&og
);
288 ogg_packet_release(&op
);
289 ogg_page_release(&og
);
290 vorbis_info_clear(vi
);
291 vorbis_comment_clear(vc
);
292 vf
->ready_state
=OPENED
;
297 /* last step of the OggVorbis_File initialization; get all the
298 vorbis_info structs and PCM positions. Only called by the seekable
299 initialization (local stream storage is hacked slightly; pay
300 attention to how that's done) */
302 /* this is void and does not propogate errors up because we want to be
303 able to open and use damaged bitstreams as well as we can. Just
304 watch out for missing information for links in the OggVorbis_File
306 static void _prefetch_all_headers(OggVorbis_File
*vf
, ogg_int64_t dataoffset
){
307 ogg_page og
={0,0,0,0};
311 vf
->vi
=_ogg_realloc(vf
->vi
,vf
->links
*sizeof(*vf
->vi
));
312 vf
->vc
=_ogg_realloc(vf
->vc
,vf
->links
*sizeof(*vf
->vc
));
313 vf
->dataoffsets
=_ogg_malloc(vf
->links
*sizeof(*vf
->dataoffsets
));
314 vf
->pcmlengths
=_ogg_malloc(vf
->links
*2*sizeof(*vf
->pcmlengths
));
316 for(i
=0;i
<vf
->links
;i
++){
318 /* we already grabbed the initial header earlier. Just set the offset */
319 vf
->dataoffsets
[i
]=dataoffset
;
320 _seek_helper(vf
,dataoffset
);
324 /* seek to the location of the initial header */
326 _seek_helper(vf
,vf
->offsets
[i
]);
327 if(_fetch_headers(vf
,vf
->vi
+i
,vf
->vc
+i
,NULL
,NULL
)<0){
328 vf
->dataoffsets
[i
]=-1;
330 vf
->dataoffsets
[i
]=vf
->offset
;
334 /* fetch beginning PCM offset */
336 if(vf
->dataoffsets
[i
]!=-1){
337 ogg_int64_t accumulated
=0,pos
;
341 ogg_stream_reset_serialno(vf
->os
,vf
->serialnos
[i
]);
344 ogg_packet op
={0,0,0,0,0,0};
346 ret
=_get_next_page(vf
,&og
,-1);
348 /* this should not be possible unless the file is
352 if(ogg_page_serialno(&og
)!=vf
->serialnos
[i
])
355 pos
=ogg_page_granulepos(&og
);
357 /* count blocksizes of all frames in the page */
358 ogg_stream_pagein(vf
->os
,&og
);
359 while((result
=ogg_stream_packetout(vf
->os
,&op
))){
360 if(result
>0){ /* ignore holes */
361 long thisblock
=vorbis_packet_blocksize(vf
->vi
+i
,&op
);
363 accumulated
+=(lastblock
+thisblock
)>>2;
367 ogg_packet_release(&op
);
370 /* pcm offset of last packet on the first audio page */
371 accumulated
= pos
-accumulated
;
376 /* less than zero? This is a stream with samples trimmed off
377 the beginning, a normal occurrence; set the offset to zero */
378 if(accumulated
<0)accumulated
=0;
380 vf
->pcmlengths
[i
*2]=accumulated
;
383 /* get the PCM length of this link. To do this,
384 get the last page of the stream */
386 ogg_int64_t end
=vf
->offsets
[i
+1];
387 _seek_helper(vf
,end
);
390 ret
=_get_prev_page(vf
,&og
);
392 /* this should not be possible */
393 vorbis_info_clear(vf
->vi
+i
);
394 vorbis_comment_clear(vf
->vc
+i
);
397 if(ogg_page_granulepos(&og
)!=-1){
398 vf
->pcmlengths
[i
*2+1]=ogg_page_granulepos(&og
)-vf
->pcmlengths
[i
*2];
405 ogg_page_release(&og
);
408 static void _make_decode_ready(OggVorbis_File
*vf
){
409 if(vf
->ready_state
!=STREAMSET
)return;
411 vorbis_synthesis_init(&vf
->vd
,vf
->vi
+vf
->current_link
);
413 vorbis_synthesis_init(&vf
->vd
,vf
->vi
);
415 vorbis_block_init(&vf
->vd
,&vf
->vb
);
416 vf
->ready_state
=INITSET
;
422 static int _open_seekable2(OggVorbis_File
*vf
){
423 ogg_uint32_t serialno
=vf
->current_serialno
;
424 ogg_uint32_t tempserialno
;
425 ogg_int64_t dataoffset
=vf
->offset
, end
;
426 ogg_page og
={0,0,0,0};
428 /* we're partially open and have a first link header state in
430 /* we can seek, so set out learning all about this file */
431 (vf
->callbacks
.seek_func
)(vf
->datasource
,0,SEEK_END
);
432 vf
->offset
=vf
->end
=(vf
->callbacks
.tell_func
)(vf
->datasource
);
434 /* We get the offset for the last page of the physical bitstream.
435 Most OggVorbis files will contain a single logical bitstream */
436 end
=_get_prev_page(vf
,&og
);
437 if(end
<0)return(end
);
439 /* more than one logical bitstream? */
440 tempserialno
=ogg_page_serialno(&og
);
441 ogg_page_release(&og
);
443 if(tempserialno
!=serialno
){
445 /* Chained bitstream. Bisect-search each logical bitstream
446 section. Do so based on serial number only */
447 if(_bisect_forward_serialno(vf
,0,0,end
+1,serialno
,0)<0)return(OV_EREAD
);
451 /* Only one logical bitstream */
452 if(_bisect_forward_serialno(vf
,0,end
,end
+1,serialno
,0))return(OV_EREAD
);
456 /* the initial header memory is referenced by vf after; don't free it */
457 _prefetch_all_headers(vf
,dataoffset
);
458 return(ov_raw_seek(vf
,0));
461 /* clear out the current logical bitstream decoder */
462 static void _decode_clear(OggVorbis_File
*vf
){
463 vorbis_dsp_clear(&vf
->vd
);
464 vorbis_block_clear(&vf
->vb
);
465 vf
->ready_state
=OPENED
;
468 /* fetch and process a packet. Handles the case where we're at a
469 bitstream boundary and dumps the decoding machine. If the decoding
470 machine is unloaded, it loads it. It also keeps pcm_offset up to
471 date (seek and read both use this. seek uses a special hack with
474 return: <0) error, OV_HOLE (lost packet) or OV_EOF
475 0) need more data (only if readp==0)
479 static int _fetch_and_process_packet(OggVorbis_File
*vf
,
481 int spanp
) ICODE_ATTR_TREMOR_NOT_MDCT
;
482 static int _fetch_and_process_packet(OggVorbis_File
*vf
,
485 ogg_page og
={0,0,0,0};
486 ogg_packet op
={0,0,0,0,0,0};
489 /* handle one packet. Try to fetch it from current stream state */
490 /* extract packets from page */
493 /* process a packet if we can. If the machine isn't loaded,
495 if(vf
->ready_state
==INITSET
){
497 int result
=ogg_stream_packetout(vf
->os
,&op
);
498 ogg_int64_t granulepos
;
501 ret
=OV_HOLE
; /* hole in the data. */
505 /* got a packet. process it */
506 granulepos
=op
.granulepos
;
507 if(!vorbis_synthesis(&vf
->vb
,&op
,1)){ /* lazy check for lazy
509 header packets aren't
512 vorbis_synthesis will
515 /* suck in the synthesis data and track bitrate */
517 int oldsamples
=vorbis_synthesis_pcmout(&vf
->vd
,NULL
);
518 /* for proper use of libvorbis within libvorbisfile,
519 oldsamples will always be zero. */
525 vorbis_synthesis_blockin(&vf
->vd
,&vf
->vb
);
526 vf
->samptrack
+=vorbis_synthesis_pcmout(&vf
->vd
,NULL
)-oldsamples
;
527 vf
->bittrack
+=op
.bytes
*8;
530 /* update the pcm offset. */
531 if(granulepos
!=-1 && !op
.e_o_s
){
532 int link
=(vf
->seekable
?vf
->current_link
:0);
535 /* this packet has a pcm_offset on it (the last packet
536 completed on a page carries the offset) After processing
537 (above), we know the pcm position of the *last* sample
538 ready to be returned. Find the offset of the *first*
540 As an aside, this trick is inaccurate if we begin
541 reading anew right at the last page; the end-of-stream
542 granulepos declares the last frame in the stream, and the
543 last packet of the last page may be a partial frame.
544 So, we need a previous granulepos from an in-sequence page
545 to have a reference point. Thus the !op.e_o_s clause
548 if(vf
->seekable
&& link
>0)
549 granulepos
-=vf
->pcmlengths
[link
*2];
550 if(granulepos
<0)granulepos
=0; /* actually, this
551 shouldn't be possible
552 here unless the stream
555 samples
=vorbis_synthesis_pcmout(&vf
->vd
,NULL
);
559 granulepos
+=vf
->pcmlengths
[i
*2+1];
560 vf
->pcm_offset
=granulepos
;
571 if(vf
->ready_state
>=OPENED
){
577 if((ret
=_get_next_page(vf
,&og
,-1))<0){
578 ret
=OV_EOF
; /* eof. leave unitialized */
582 /* bitrate tracking; add the header's bytes here, the body bytes
583 are done by packet above */
584 vf
->bittrack
+=og
.header_len
*8;
586 /* has our decoding just traversed a bitstream boundary? */
587 if(vf
->ready_state
==INITSET
){
588 if(vf
->current_serialno
!=ogg_page_serialno(&og
)){
597 vorbis_info_clear(vf
->vi
);
598 vorbis_comment_clear(vf
->vc
);
604 /* Do we need to load a new machine before submitting the page? */
605 /* This is different in the seekable and non-seekable cases.
607 In the seekable case, we already have all the header
608 information loaded and cached; we just initialize the machine
609 with it and continue on our merry way.
611 In the non-seekable (streaming) case, we'll only be at a
612 boundary if we just left the previous logical bitstream and
613 we're now nominally at the header of the next bitstream
616 if(vf
->ready_state
!=INITSET
){
619 if(vf
->ready_state
<STREAMSET
){
621 vf
->current_serialno
=ogg_page_serialno(&og
);
623 /* match the serialno to bitstream section. We use this rather than
624 offset positions to avoid problems near logical bitstream
626 for(link
=0;link
<vf
->links
;link
++)
627 if(vf
->serialnos
[link
]==vf
->current_serialno
)break;
629 ret
=OV_EBADLINK
; /* sign of a bogus stream. error out,
630 leave machine uninitialized */
634 vf
->current_link
=link
;
636 ogg_stream_reset_serialno(vf
->os
,vf
->current_serialno
);
637 vf
->ready_state
=STREAMSET
;
640 /* we're streaming */
641 /* fetch the three header packets, build the info struct */
643 int ret
=_fetch_headers(vf
,vf
->vi
,vf
->vc
,&vf
->current_serialno
,&og
);
644 if(ret
) goto cleanup
;
650 _make_decode_ready(vf
);
652 ogg_stream_pagein(vf
->os
,&og
);
655 ogg_packet_release(&op
);
656 ogg_page_release(&og
);
660 static int _ov_open1(void *f
,OggVorbis_File
*vf
,char *initial
,
661 long ibytes
, ov_callbacks callbacks
){
662 int offsettest
=(f
?callbacks
.seek_func(f
,0,SEEK_CUR
):-1);
665 memset(vf
,0,sizeof(*vf
));
667 vf
->callbacks
= callbacks
;
669 /* init the framing state */
670 vf
->oy
=ogg_sync_create();
672 /* perhaps some data was previously read into a buffer for testing
673 against other stream types. Allow initialization from this
674 previously read data (as we may be reading from a non-seekable
677 char *buffer
=(char *)ogg_sync_bufferin(vf
->oy
,ibytes
);
678 memcpy(buffer
,initial
,ibytes
);
679 ogg_sync_wrote(vf
->oy
,ibytes
);
682 /* can we seek? Stevens suggests the seek test was portable */
683 if(offsettest
!=-1)vf
->seekable
=1;
685 /* No seeking yet; Set up a 'single' (current) logical bitstream
686 entry for partial open */
688 vf
->vi
=_ogg_calloc(vf
->links
,sizeof(*vf
->vi
));
689 vf
->vc
=_ogg_calloc(vf
->links
,sizeof(*vf
->vc
));
690 vf
->os
=ogg_stream_create(-1); /* fill in the serialno later */
692 /* Try to fetch the headers, maintaining all the storage */
693 if((ret
=_fetch_headers(vf
,vf
->vi
,vf
->vc
,&vf
->current_serialno
,NULL
))<0){
696 }else if(vf
->ready_state
< PARTOPEN
)
697 vf
->ready_state
=PARTOPEN
;
701 static int _ov_open2(OggVorbis_File
*vf
){
702 if(vf
->ready_state
< OPENED
)
703 vf
->ready_state
=OPENED
;
705 int ret
=_open_seekable2(vf
);
716 /* clear out the OggVorbis_File struct */
717 int ov_clear(OggVorbis_File
*vf
){
719 vorbis_block_clear(&vf
->vb
);
720 vorbis_dsp_clear(&vf
->vd
);
721 ogg_stream_destroy(vf
->os
);
723 if(vf
->vi
&& vf
->links
){
725 for(i
=0;i
<vf
->links
;i
++){
726 vorbis_info_clear(vf
->vi
+i
);
727 vorbis_comment_clear(vf
->vc
+i
);
732 if(vf
->dataoffsets
)_ogg_free(vf
->dataoffsets
);
733 if(vf
->pcmlengths
)_ogg_free(vf
->pcmlengths
);
734 if(vf
->serialnos
)_ogg_free(vf
->serialnos
);
735 if(vf
->offsets
)_ogg_free(vf
->offsets
);
736 ogg_sync_destroy(vf
->oy
);
738 if(vf
->datasource
)(vf
->callbacks
.close_func
)(vf
->datasource
);
739 memset(vf
,0,sizeof(*vf
));
747 /* inspects the OggVorbis file and finds/documents all the logical
748 bitstreams contained in it. Tries to be tolerant of logical
749 bitstream sections that are truncated/woogie.
755 int ov_open_callbacks(void *f
,OggVorbis_File
*vf
,char *initial
,long ibytes
,
756 ov_callbacks callbacks
){
757 #if defined(CPU_COLDFIRE)
758 /* this seems to be the closest we get to an init function, let's init emac
759 here. rounding is disabled because of MULT31_SHIFT15, which will be
760 inaccurate with rounding in its current incarnation */
761 coldfire_set_macsr(EMAC_FRACTIONAL
| EMAC_SATURATE
);
763 int ret
=_ov_open1(f
,vf
,initial
,ibytes
,callbacks
);
765 return _ov_open2(vf
);
768 /* returns: total PCM length (samples) of content if i==-1 PCM length
769 (samples) of that logical bitstream for i==0 to n
770 OV_EINVAL if the stream is not seekable (we can't know the
771 length) or only partially open
773 ogg_int64_t
ov_pcm_total(OggVorbis_File
*vf
,int i
){
774 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
775 if(!vf
->seekable
|| i
>=vf
->links
)return(OV_EINVAL
);
779 for(i
=0;i
<vf
->links
;i
++)
780 acc
+=ov_pcm_total(vf
,i
);
783 return(vf
->pcmlengths
[i
*2+1]);
787 /* returns: total milliseconds of content if i==-1
788 milliseconds in that logical bitstream for i==0 to n
789 OV_EINVAL if the stream is not seekable (we can't know the
790 length) or only partially open
792 ogg_int64_t
ov_time_total(OggVorbis_File
*vf
,int i
){
793 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
794 if(!vf
->seekable
|| i
>=vf
->links
)return(OV_EINVAL
);
798 for(i
=0;i
<vf
->links
;i
++)
799 acc
+=ov_time_total(vf
,i
);
802 return(((ogg_int64_t
)vf
->pcmlengths
[i
*2+1])*1000/vf
->vi
[i
].rate
);
806 /* seek to an offset relative to the *compressed* data. This also
807 scans packets to update the PCM cursor. It will cross a logical
808 bitstream boundary, but only if it can't get any packets out of the
809 tail of the bitstream we seek to (so no surprises).
811 returns zero on success, nonzero on failure */
813 int ov_raw_seek(OggVorbis_File
*vf
,ogg_int64_t pos
){
814 ogg_stream_state
*work_os
=NULL
;
815 ogg_page og
={0,0,0,0};
816 ogg_packet op
={0,0,0,0,0,0};
818 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
820 return(OV_ENOSEEK
); /* don't dump machine if we can't seek */
822 if(pos
<0 || pos
>vf
->end
)return(OV_EINVAL
);
824 /* don't yet clear out decoding machine (if it's initialized), in
825 the case we're in the same link. Restart the decode lapping, and
826 let _fetch_and_process_packet deal with a potential bitstream
829 ogg_stream_reset_serialno(vf
->os
,
830 vf
->current_serialno
); /* must set serialno */
831 vorbis_synthesis_restart(&vf
->vd
);
833 _seek_helper(vf
,pos
);
835 /* we need to make sure the pcm_offset is set, but we don't want to
836 advance the raw cursor past good packets just to get to the first
837 with a granulepos. That's not equivalent behavior to beginning
838 decoding as immediately after the seek position as possible.
840 So, a hack. We use two stream states; a local scratch state and
841 the shared vf->os stream state. We use the local state to
842 scan, and the shared state as a buffer for later decode.
844 Unfortuantely, on the last page we still advance to last packet
845 because the granulepos on the last page is not necessarily on a
846 packet boundary, and we need to make sure the granpos is
856 work_os
=ogg_stream_create(vf
->current_serialno
); /* get the memory ready */
858 if(vf
->ready_state
>=STREAMSET
){
859 /* snarf/scan a packet if we can */
860 int result
=ogg_stream_packetout(work_os
,&op
);
864 if(vf
->vi
[vf
->current_link
].codec_setup
){
865 thisblock
=vorbis_packet_blocksize(vf
->vi
+vf
->current_link
,&op
);
867 ogg_stream_packetout(vf
->os
,NULL
);
872 ogg_stream_packetout(vf
->os
,NULL
);
874 if(lastblock
)accblock
+=(lastblock
+thisblock
)>>2;
877 if(op
.granulepos
!=-1){
878 int i
,link
=vf
->current_link
;
879 ogg_int64_t granulepos
=op
.granulepos
-vf
->pcmlengths
[link
*2];
880 if(granulepos
<0)granulepos
=0;
883 granulepos
+=vf
->pcmlengths
[i
*2+1];
884 vf
->pcm_offset
=granulepos
-accblock
;
890 ogg_stream_packetout(vf
->os
,NULL
);
895 if(_get_next_page(vf
,&og
,-1)<0){
896 vf
->pcm_offset
=ov_pcm_total(vf
,-1);
900 /* huh? Bogus stream with packets but no granulepos */
905 /* has our decoding just traversed a bitstream boundary? */
906 if(vf
->ready_state
>=STREAMSET
)
907 if(vf
->current_serialno
!=ogg_page_serialno(&og
)){
908 _decode_clear(vf
); /* clear out stream state */
909 ogg_stream_destroy(work_os
);
912 if(vf
->ready_state
<STREAMSET
){
915 vf
->current_serialno
=ogg_page_serialno(&og
);
916 for(link
=0;link
<vf
->links
;link
++)
917 if(vf
->serialnos
[link
]==vf
->current_serialno
)break;
919 goto seek_error
; /* sign of a bogus stream. error out,
920 leave machine uninitialized */
922 vf
->current_link
=link
;
924 ogg_stream_reset_serialno(vf
->os
,vf
->current_serialno
);
925 ogg_stream_reset_serialno(work_os
,vf
->current_serialno
);
926 vf
->ready_state
=STREAMSET
;
932 ogg_page_dup(&dup
,&og
);
933 eosflag
=ogg_page_eos(&og
);
934 ogg_stream_pagein(vf
->os
,&og
);
935 ogg_stream_pagein(work_os
,&dup
);
940 ogg_packet_release(&op
);
941 ogg_page_release(&og
);
942 ogg_stream_destroy(work_os
);
948 ogg_packet_release(&op
);
949 ogg_page_release(&og
);
951 /* dump the machine so we're in a known state */
953 ogg_stream_destroy(work_os
);
958 /* Page granularity seek (faster than sample granularity because we
959 don't do the last bit of decode to find a specific sample).
961 Seek to the last [granule marked] page preceeding the specified pos
962 location, such that decoding past the returned point will quickly
963 arrive at the requested position. */
964 int ov_pcm_seek_page(OggVorbis_File
*vf
,ogg_int64_t pos
){
966 ogg_int64_t result
=0;
967 ogg_int64_t total
=ov_pcm_total(vf
,-1);
968 ogg_page og
={0,0,0,0};
969 ogg_packet op
={0,0,0,0,0,0};
971 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
972 if(!vf
->seekable
)return(OV_ENOSEEK
);
973 if(pos
<0 || pos
>total
)return(OV_EINVAL
);
975 /* which bitstream section does this pcm offset occur in? */
976 for(link
=vf
->links
-1;link
>=0;link
--){
977 total
-=vf
->pcmlengths
[link
*2+1];
981 /* search within the logical bitstream for the page with the highest
982 pcm_pos preceeding (or equal to) pos. There is a danger here;
983 missing pages or incorrect frame number information in the
984 bitstream could make our task impossible. Account for that (it
985 would be an error condition) */
987 /* new search algorithm by HB (Nicholas Vinen) */
989 ogg_int64_t end
=vf
->offsets
[link
+1];
990 ogg_int64_t begin
=vf
->offsets
[link
];
991 ogg_int64_t begintime
= vf
->pcmlengths
[link
*2];
992 ogg_int64_t endtime
= vf
->pcmlengths
[link
*2+1]+begintime
;
993 ogg_int64_t target
=pos
-total
+begintime
;
994 ogg_int64_t best
=begin
;
999 if(end
-begin
<CHUNKSIZE
){
1002 /* take a (pretty decent) guess. */
1004 (target
-begintime
)*(end
-begin
)/(endtime
-begintime
) - CHUNKSIZE
;
1009 _seek_helper(vf
,bisect
);
1012 result
=_get_next_page(vf
,&og
,end
-vf
->offset
);
1013 if(result
==OV_EREAD
) goto seek_error
;
1016 end
=begin
; /* found it */
1018 if(bisect
==0) goto seek_error
;
1020 if(bisect
<=begin
)bisect
=begin
+1;
1021 _seek_helper(vf
,bisect
);
1024 ogg_int64_t granulepos
=ogg_page_granulepos(&og
);
1025 if(granulepos
==-1)continue;
1026 if(granulepos
<target
){
1027 best
=result
; /* raw offset of packet with granulepos */
1028 begin
=vf
->offset
; /* raw offset of next page */
1029 begintime
=granulepos
;
1031 if(target
-begintime
>44100)break;
1032 bisect
=begin
; /* *not* begin + 1 */
1035 end
=begin
; /* found it */
1037 if(end
==vf
->offset
){ /* we're pretty close - we'd be stuck in */
1039 bisect
-=CHUNKSIZE
; /* an endless loop otherwise. */
1040 if(bisect
<=begin
)bisect
=begin
+1;
1041 _seek_helper(vf
,bisect
);
1053 /* found our page. seek to it, update pcm offset. Easier case than
1054 raw_seek, don't keep packets preceeding granulepos. */
1058 _seek_helper(vf
,best
);
1061 if(_get_next_page(vf
,&og
,-1)<0){
1062 ogg_page_release(&og
);
1063 return(OV_EOF
); /* shouldn't happen */
1066 if(link
!=vf
->current_link
){
1067 /* Different link; dump entire decode machine */
1070 vf
->current_link
=link
;
1071 vf
->current_serialno
=ogg_page_serialno(&og
);
1072 vf
->ready_state
=STREAMSET
;
1075 vorbis_synthesis_restart(&vf
->vd
);
1078 ogg_stream_reset_serialno(vf
->os
,vf
->current_serialno
);
1079 ogg_stream_pagein(vf
->os
,&og
);
1081 /* pull out all but last packet; the one with granulepos */
1083 result
=ogg_stream_packetpeek(vf
->os
,&op
);
1085 /* !!! the packet finishing this page originated on a
1086 preceeding page. Keep fetching previous pages until we
1087 get one with a granulepos or without the 'continued' flag
1088 set. Then just use raw_seek for simplicity. */
1090 _seek_helper(vf
,best
);
1093 result
=_get_prev_page(vf
,&og
);
1094 if(result
<0) goto seek_error
;
1095 if(ogg_page_granulepos(&og
)>-1 ||
1096 !ogg_page_continued(&og
)){
1097 return ov_raw_seek(vf
,result
);
1103 result
= OV_EBADPACKET
;
1106 if(op
.granulepos
!=-1){
1107 vf
->pcm_offset
=op
.granulepos
-vf
->pcmlengths
[vf
->current_link
*2];
1108 if(vf
->pcm_offset
<0)vf
->pcm_offset
=0;
1109 vf
->pcm_offset
+=total
;
1112 result
=ogg_stream_packetout(vf
->os
,NULL
);
1118 if(vf
->pcm_offset
>pos
|| pos
>ov_pcm_total(vf
,-1)){
1125 ogg_page_release(&og
);
1126 ogg_packet_release(&op
);
1131 ogg_page_release(&og
);
1132 ogg_packet_release(&op
);
1134 /* dump machine so we're in a known state */
1140 /* seek to a sample offset relative to the decompressed pcm stream
1141 returns zero on success, nonzero on failure */
1143 int ov_pcm_seek(OggVorbis_File
*vf
,ogg_int64_t pos
){
1144 ogg_packet op
={0,0,0,0,0,0};
1145 ogg_page og
={0,0,0,0};
1147 int thisblock
,lastblock
=0;
1148 int ret
=ov_pcm_seek_page(vf
,pos
);
1149 if(ret
<0)return(ret
);
1150 _make_decode_ready(vf
);
1152 /* discard leading packets we don't need for the lapping of the
1153 position we want; don't decode them */
1157 int ret
=ogg_stream_packetpeek(vf
->os
,&op
);
1159 thisblock
=vorbis_packet_blocksize(vf
->vi
+vf
->current_link
,&op
);
1161 ogg_stream_packetout(vf
->os
,NULL
);
1162 continue; /* non audio packet */
1164 if(lastblock
)vf
->pcm_offset
+=(lastblock
+thisblock
)>>2;
1166 if(vf
->pcm_offset
+((thisblock
+
1167 vorbis_info_blocksize(vf
->vi
,1))>>2)>=pos
)break;
1169 /* remove the packet from packet queue and track its granulepos */
1170 ogg_stream_packetout(vf
->os
,NULL
);
1171 vorbis_synthesis(&vf
->vb
,&op
,0); /* set up a vb with
1174 vorbis_synthesis_blockin(&vf
->vd
,&vf
->vb
);
1176 /* end of logical stream case is hard, especially with exact
1177 length positioning. */
1179 if(op
.granulepos
>-1){
1181 /* always believe the stream markers */
1182 vf
->pcm_offset
=op
.granulepos
-vf
->pcmlengths
[vf
->current_link
*2];
1183 if(vf
->pcm_offset
<0)vf
->pcm_offset
=0;
1184 for(i
=0;i
<vf
->current_link
;i
++)
1185 vf
->pcm_offset
+=vf
->pcmlengths
[i
*2+1];
1188 lastblock
=thisblock
;
1191 if(ret
<0 && ret
!=OV_HOLE
)break;
1193 /* suck in a new page */
1194 if(_get_next_page(vf
,&og
,-1)<0)break;
1195 if(vf
->current_serialno
!=ogg_page_serialno(&og
))_decode_clear(vf
);
1197 if(vf
->ready_state
<STREAMSET
){
1200 vf
->current_serialno
=ogg_page_serialno(&og
);
1201 for(link
=0;link
<vf
->links
;link
++)
1202 if(vf
->serialnos
[link
]==vf
->current_serialno
)break;
1203 if(link
==vf
->links
){
1204 ogg_page_release(&og
);
1205 ogg_packet_release(&op
);
1206 return(OV_EBADLINK
);
1208 vf
->current_link
=link
;
1210 ogg_stream_reset_serialno(vf
->os
,vf
->current_serialno
);
1211 vf
->ready_state
=STREAMSET
;
1212 _make_decode_ready(vf
);
1216 ogg_stream_pagein(vf
->os
,&og
);
1222 /* discard samples until we reach the desired position. Crossing a
1223 logical bitstream boundary with abandon is OK. */
1224 while(vf
->pcm_offset
<pos
){
1225 ogg_int64_t target
=pos
-vf
->pcm_offset
;
1226 long samples
=vorbis_synthesis_pcmout(&vf
->vd
,NULL
);
1228 if(samples
>target
)samples
=target
;
1229 vorbis_synthesis_read(&vf
->vd
,samples
);
1230 vf
->pcm_offset
+=samples
;
1233 if(_fetch_and_process_packet(vf
,1,1)<=0)
1234 vf
->pcm_offset
=ov_pcm_total(vf
,-1); /* eof */
1237 ogg_page_release(&og
);
1238 ogg_packet_release(&op
);
1242 /* seek to a playback time relative to the decompressed pcm stream
1243 returns zero on success, nonzero on failure */
1244 int ov_time_seek(OggVorbis_File
*vf
,ogg_int64_t milliseconds
){
1245 /* translate time to PCM position and call ov_pcm_seek */
1248 ogg_int64_t pcm_total
=ov_pcm_total(vf
,-1);
1249 ogg_int64_t time_total
=ov_time_total(vf
,-1);
1251 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
1252 if(!vf
->seekable
)return(OV_ENOSEEK
);
1253 if(milliseconds
<0 || milliseconds
>time_total
)return(OV_EINVAL
);
1255 /* which bitstream section does this time offset occur in? */
1256 for(link
=vf
->links
-1;link
>=0;link
--){
1257 pcm_total
-=vf
->pcmlengths
[link
*2+1];
1258 time_total
-=ov_time_total(vf
,link
);
1259 if(milliseconds
>=time_total
)break;
1262 /* enough information to convert time offset to pcm offset */
1264 ogg_int64_t target
=pcm_total
+(milliseconds
-time_total
)*vf
->vi
[link
].rate
/1000;
1265 return(ov_pcm_seek(vf
,target
));
1269 /* tell the current stream offset cursor. Note that seek followed by
1270 tell will likely not give the set offset due to caching */
1271 ogg_int64_t
ov_raw_tell(OggVorbis_File
*vf
){
1272 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
1276 /* return time offset (milliseconds) of next PCM sample to be read */
1277 ogg_int64_t
ov_time_tell(OggVorbis_File
*vf
) ICODE_ATTR_TREMOR_NOT_MDCT
;
1278 ogg_int64_t
ov_time_tell(OggVorbis_File
*vf
){
1280 ogg_int64_t pcm_total
=0;
1281 ogg_int64_t time_total
=0;
1283 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
1285 pcm_total
=ov_pcm_total(vf
,-1);
1286 time_total
=ov_time_total(vf
,-1);
1288 /* which bitstream section does this time offset occur in? */
1289 for(link
=vf
->links
-1;link
>=0;link
--){
1290 pcm_total
-=vf
->pcmlengths
[link
*2+1];
1291 time_total
-=ov_time_total(vf
,link
);
1292 if(vf
->pcm_offset
>=pcm_total
)break;
1296 return(time_total
+(1000*vf
->pcm_offset
-pcm_total
)/vf
->vi
[link
].rate
);
1299 /* link: -1) return the vorbis_info struct for the bitstream section
1300 currently being decoded
1301 0-n) to request information for a specific bitstream section
1303 In the case of a non-seekable bitstream, any call returns the
1304 current bitstream. NULL in the case that the machine is not
1307 vorbis_info
*ov_info(OggVorbis_File
*vf
,int link
){
1310 if(vf
->ready_state
>=STREAMSET
)
1311 return vf
->vi
+vf
->current_link
;
1324 /* input values: pcm_channels) a float vector per channel of output
1325 length) the sample length being read by the app
1327 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1329 n) number of samples of PCM actually returned. The
1330 below works on a packet-by-packet basis, so the
1331 return length is not related to the 'length' passed
1332 in, just guaranteed to fit.
1334 *section) set to the logical bitstream number */
1336 long ov_read_fixed(OggVorbis_File
*vf
,ogg_int32_t
***pcm_channels
,int length
,
1338 if(vf
->ready_state
<OPENED
)return(OV_EINVAL
);
1341 if(vf
->ready_state
==INITSET
){
1343 long samples
=vorbis_synthesis_pcmout(&vf
->vd
,&pcm
);
1345 if(pcm_channels
)*pcm_channels
=pcm
;
1346 if(samples
>length
)samples
=length
;
1347 vorbis_synthesis_read(&vf
->vd
,samples
);
1348 vf
->pcm_offset
+=samples
;
1349 if(bitstream
)*bitstream
=vf
->current_link
;
1355 /* suck in another packet */
1357 int ret
=_fetch_and_process_packet(vf
,1,1);
1358 if(ret
==OV_EOF
)return(0);
1359 if(ret
<=0)return(ret
);