137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang/************************************************************************
22da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * Copyright (C) 2002-2009, Xiph.org Foundation
32da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd
437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * All rights reserved.
537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * Redistribution and use in source and binary forms, with or without
72da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * modification, are permitted provided that the following conditions
82da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * are met:
937fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
1037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *     * Redistributions of source code must retain the above copyright
1137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * notice, this list of conditions and the following disclaimer.
1237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *     * Redistributions in binary form must reproduce the above
1337fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * copyright notice, this list of conditions and the following disclaimer
1437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * in the documentation and/or other materials provided with the
1537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * distribution.
162da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang *     * Neither the names of the Xiph.org Foundation nor Pinknoise
172da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * Productions Ltd nor the names of its contributors may be used to
182da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * endorse or promote products derived from this software without
192da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * specific prior written permission.
2037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
2137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2337fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2737fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2837fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2937fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang ************************************************************************
337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang function: stdio-based convenience library for opening/seeking/decoding
357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang last mod: $Id: vorbisfile.c,v 1.6.2.5 2003/11/20 06:16:17 xiphmont Exp $
367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3737fe158a8611dd11ec0253ab1552399b780988dcGloria Wang ************************************************************************/
387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include <stdlib.h>
407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include <stdio.h>
41d75baf2eee5ddd155009e7f0a79b175ae6026762Gloria Wang//#include <gerrno.h>
427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include <string.h>
437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include <math.h>
447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "codec_internal.h"
467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "ivorbisfile.h"
477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "os.h"
497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#include "misc.h"
507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
51d75baf2eee5ddd155009e7f0a79b175ae6026762Gloria Wangint gerrno;
527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define  NOTOPEN   0
547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define  PARTOPEN  1
557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define  OPENED    2
567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define  STREAMSET 3 /* serialno and link set, but not to current link */
577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define  LINKSET   4 /* serialno and link set to current link */
587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#define  INITSET   5
597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* A 'chained bitstream' is a Vorbis bitstream that contains more than
617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   one logical bitstream arranged end to end (the only form of Ogg
627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   multiplexing allowed in a Vorbis bitstream; grouping [parallel
637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   multiplexing] is not allowed in Vorbis) */
647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* A Vorbis file can be played beginning to end (streamed) without
667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   worrying ahead of time about chaining (see decoder_example.c).  If
677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   we have the whole file, however, and want random access
687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   (seeking/scrubbing) or desire to know the total length/time of a
697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   file, we need to account for the possibility of chaining. */
707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* We can handle things a number of ways; we can determine the entire
727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   bitstream structure right off the bat, or find pieces on demand.
737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   This example determines and caches structure for the entire
747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   bitstream, but builds a virtual decoder on the fly when moving
757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   between links in the chain. */
767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* There are also different ways to implement seeking.  Enough
787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   information exists in an Ogg bitstream to seek to
797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   sample-granularity positions in the output.  Or, one can seek by
807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   picking some portion of the stream roughly in the desired area if
817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   we only want coarse navigation through the stream. */
827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/*************************************************************************
847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * Many, many internal helpers.  The intention is not to be confusing;
857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * rampant duplication and monolithic function implementation would be
867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * harder to understand anyway.  The high level functions are last.  Begin
877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * grokking near the end of the file */
887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* read a little more data from the file/pipe into the ogg_sync framer */
917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic long _get_data(OggVorbis_File *vf){
92d75baf2eee5ddd155009e7f0a79b175ae6026762Gloria Wang  gerrno=0;
937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->datasource){
947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    unsigned char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE);
957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(bytes>0)ogg_sync_wrote(vf->oy,bytes);
97d75baf2eee5ddd155009e7f0a79b175ae6026762Gloria Wang    if(bytes==0 && gerrno)return -1;
987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return bytes;
997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else
1007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return 0;
1017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* save a tiny smidge of verbosity to make the code more readable */
1047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
1057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->datasource){
1067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
1077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->offset=offset;
1087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_sync_reset(vf->oy);
1097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
1107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* shouldn't happen unless someone writes a broken callback */
1117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return;
1127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
1137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* The read/seek functions track absolute position within the stream */
1167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* from the head of the stream, get the next page.  boundary specifies
1187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   if the function is allowed to fetch more data from the stream (and
1197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   how much) or only use internally buffered data.
1207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   boundary: -1) unbounded search
1227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang              0) read no additional data; use cached only
1237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      n) search for a new page beginning for n bytes
1247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
1267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang              n) found a page at absolute offset n
1277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang              produces a refcounted page */
1297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
1317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				  ogg_int64_t boundary){
1327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(boundary>0)boundary+=vf->offset;
1337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(1){
1347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    long more;
1357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(boundary>0 && vf->offset>=boundary)return OV_FALSE;
1377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    more=ogg_sync_pageseek(vf->oy,og);
1387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(more<0){
1407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* skipped n bytes */
1417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vf->offset-=more;
1427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }else{
1437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(more==0){
1447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* send more paramedics */
1457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(!boundary)return OV_FALSE;
1467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	{
1477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  long ret=_get_data(vf);
1487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(ret==0)return OV_EOF;
1497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(ret<0)return OV_EREAD;
1507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
1517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }else{
1527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* got a page.  Return the offset at the page beginning,
1537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang           advance the internal offset past the page end */
1547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_int64_t ret=vf->offset;
1557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->offset+=more;
1567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return ret;
1577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
1597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
1617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* find the latest page beginning before the current stream cursor
1647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   position. Much dirtier than the above as Ogg doesn't have any
1657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   backward search linkage.  no 'readp' as it will certainly have to
1667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   read. */
1677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */
1687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
1707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t begin=vf->offset;
1717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t end=begin;
1727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t ret;
1737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t offset=-1;
1747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(offset==-1){
1767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    begin-=CHUNKSIZE;
1777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(begin<0)
1787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      begin=0;
1797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    _seek_helper(vf,begin);
1807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    while(vf->offset<end){
1817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ret=_get_next_page(vf,og,end-vf->offset);
1827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret==OV_EREAD)return OV_EREAD;
1837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret<0){
1847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	break;
1857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }else{
1867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	offset=ret;
1877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
1887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
1897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
1907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* we have the offset.  Actually snork and hold the page now */
1927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _seek_helper(vf,offset);
1937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ret=_get_next_page(vf,og,CHUNKSIZE);
1947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(ret<0)
1957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* this shouldn't be possible */
1967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return OV_EFAULT;
1977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return offset;
1997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* finds each bitstream link one at a time using a bisection search
2027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   (has to begin by knowing the offset of the lb's initial page).
2037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   Recurses for each link so it can alloc the link storage after
2047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   finding them all, then unroll and fill the cache at the same time */
2057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _bisect_forward_serialno(OggVorbis_File *vf,
2067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				    ogg_int64_t begin,
2077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				    ogg_int64_t searched,
2087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				    ogg_int64_t end,
2097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				    ogg_uint32_t currentno,
2107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				    long m){
2117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t endsearched=end;
2127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t next=end;
2137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
2147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t ret;
2157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* the below guards against garbage seperating the last and
2177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     first pages of two links. */
2187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(searched<endsearched){
2197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t bisect;
2207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(endsearched-searched<CHUNKSIZE){
2227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      bisect=searched;
2237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }else{
2247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      bisect=(searched+endsearched)/2;
2257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
2267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    _seek_helper(vf,bisect);
2287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ret=_get_next_page(vf,&og,-1);
2297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret==OV_EREAD)return OV_EREAD;
2307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret<0 || ogg_page_serialno(&og)!=currentno){
2317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      endsearched=bisect;
2327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret>=0)next=ret;
2337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }else{
2347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      searched=ret+og.header_len+og.body_len;
2357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
2367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_page_release(&og);
2377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
2387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _seek_helper(vf,next);
2407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ret=_get_next_page(vf,&og,-1);
2417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(ret==OV_EREAD)return OV_EREAD;
2427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(searched>=end || ret<0){
2447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_page_release(&og);
2457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->links=m+1;
2467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
2477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
2487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->offsets[m+1]=searched;
2497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
2507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ret=_bisect_forward_serialno(vf,next,vf->offset,
2517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				 end,ogg_page_serialno(&og),m+1);
2527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_page_release(&og);
2537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret==OV_EREAD)return OV_EREAD;
2547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
2557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->offsets[m]=begin;
2577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->serialnos[m]=currentno;
2587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
2597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _decode_clear(OggVorbis_File *vf){
2627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state==INITSET){
2637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_dsp_destroy(vf->vd);
2647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->vd=0;
2657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->ready_state=STREAMSET;
2667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
2677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state>=STREAMSET){
2697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_info_clear(&vf->vi);
2707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_comment_clear(&vf->vc);
2717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->ready_state=OPENED;
2727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
2737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
2747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* uses the local ogg_stream storage in vf; this is important for
2777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   non-streaming input sources */
2787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* consumes the page that's passed in (if any) */
2797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* state is LINKSET upon successful return */
2807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _fetch_headers(OggVorbis_File *vf,
2827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			  vorbis_info *vi,
2837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			  vorbis_comment *vc,
2847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			  ogg_uint32_t *serialno,
2857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			  ogg_page *og_ptr){
2867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
2877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet op={0,0,0,0,0,0};
2887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int i,ret;
2897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state>OPENED)_decode_clear(vf);
2917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!og_ptr){
2937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
2947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(llret==OV_EREAD)return OV_EREAD;
2957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(llret<0)return OV_ENOTVORBIS;
2967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    og_ptr=&og;
2977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
2987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
3007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(serialno)*serialno=vf->os->serialno;
3017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* extract the initial header from the first page and verify that the
3037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     Ogg bitstream is in fact Vorbis data */
3047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vorbis_info_init(vi);
3067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vorbis_comment_init(vc);
3077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  i=0;
3097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(i<3){
3107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_stream_pagein(vf->os,og_ptr);
3117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    while(i<3){
3127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int result=ogg_stream_packetout(vf->os,&op);
3137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(result==0)break;
3147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(result==-1){
3157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=OV_EBADHEADER;
3167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	goto bail_header;
3177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
3187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if((ret=vorbis_dsp_headerin(vi,vc,&op))){
3197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	goto bail_header;
3207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
3217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      i++;
3227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(i<3)
3247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
3257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=OV_EBADHEADER;
3267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	goto bail_header;
3277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
3287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
3297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
3317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
3327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->ready_state=LINKSET;
3337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
3347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang bail_header:
3367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
3377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
3387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vorbis_info_clear(vi);
3397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vorbis_comment_clear(vc);
3407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->ready_state=OPENED;
3417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ret;
3437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
3447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* we no longer preload all vorbis_info (and the associated
3467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   codec_setup) structs.  Call this to seek and fetch the info from
3477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   the bitstream, if needed */
3487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _set_link_number(OggVorbis_File *vf,int link){
3497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(link != vf->current_link) _decode_clear(vf);
3507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<STREAMSET){
3517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    _seek_helper(vf,vf->offsets[link]);
3527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_stream_reset_serialno(vf->os,vf->serialnos[link]);
3537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->current_serialno=vf->serialnos[link];
3547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->current_link=link;
3557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return _fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,NULL);
3567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
3577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
3587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
3597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _set_link_number_preserve_pos(OggVorbis_File *vf,int link){
3617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t pos=vf->offset;
3627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int ret=_set_link_number(vf,link);
3637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(ret)return ret;
3647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _seek_helper(vf,pos);
3657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(pos<vf->offsets[link] || pos>=vf->offsets[link+1])
3667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->ready_state=STREAMSET;
3677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
3687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
3697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* last step of the OggVorbis_File initialization; get all the offset
3717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   positions.  Only called by the seekable initialization (local
3727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   stream storage is hacked slightly; pay attention to how that's
3737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   done) */
3747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* this is void and does not propogate errors up because we want to be
3767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   able to open and use damaged bitstreams as well as we can.  Just
3777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   watch out for missing information for links in the OggVorbis_File
3787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   struct */
3797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void _prefetch_all_offsets(OggVorbis_File *vf, ogg_int64_t dataoffset){
3807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
3817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int i;
3827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t ret;
3837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
3857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
3867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  for(i=0;i<vf->links;i++){
3887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(i==0){
3897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* we already grabbed the initial header earlier.  Just set the offset */
3907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vf->dataoffsets[i]=dataoffset;
3917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      _seek_helper(vf,dataoffset);
3927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }else{
3947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* seek to the location of the initial header */
3967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      _seek_helper(vf,vf->offsets[i]);
3987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(_fetch_headers(vf,&vf->vi,&vf->vc,NULL,NULL)<0){
3997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    	vf->dataoffsets[i]=-1;
4007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }else{
4017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->dataoffsets[i]=vf->offset;
4027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
4037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
4047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* fetch beginning PCM offset */
4067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->dataoffsets[i]!=-1){
4087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_int64_t accumulated=0,pos;
4097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      long        lastblock=-1;
4107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int         result;
4117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);
4137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      while(1){
4157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_packet op={0,0,0,0,0,0};
4167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=_get_next_page(vf,&og,-1);
4187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(ret<0)
4197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* this should not be possible unless the file is
4207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang             truncated/mangled */
4217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
4227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(ogg_page_serialno(&og)!=vf->serialnos[i])
4247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
4257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	pos=ogg_page_granulepos(&og);
4277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* count blocksizes of all frames in the page */
4297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_stream_pagein(vf->os,&og);
4307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	while((result=ogg_stream_packetout(vf->os,&op))){
4317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(result>0){ /* ignore holes */
4327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    long thisblock=vorbis_packet_blocksize(&vf->vi,&op);
4337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(lastblock!=-1)
4347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      accumulated+=(lastblock+thisblock)>>2;
4357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    lastblock=thisblock;
4367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
4377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
4387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_packet_release(&op);
4397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(pos!=-1){
4417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* pcm offset of last packet on the first audio page */
4427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  accumulated= pos-accumulated;
4437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
4447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
4457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
4467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* less than zero?  This is a stream with samples trimmed off
4487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang         the beginning, a normal occurrence; set the offset to zero */
4497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(accumulated<0)accumulated=0;
4507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vf->pcmlengths[i*2]=accumulated;
4527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
4537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* get the PCM length of this link. To do this,
4557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       get the last page of the stream */
4567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    {
4577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_int64_t end=vf->offsets[i+1];
4587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      _seek_helper(vf,end);
4597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      while(1){
4617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=_get_prev_page(vf,&og);
4627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(ret<0){
4637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* this should not be possible */
4647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vorbis_info_clear(&vf->vi);
4657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vorbis_comment_clear(&vf->vc);
4667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
4677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
4687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(ogg_page_granulepos(&og)!=-1){
4697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
4707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
4717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
4727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->offset=ret;
4737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
4747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
4757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
4767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
4777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
4787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
4797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _make_decode_ready(OggVorbis_File *vf){
4807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int i;
4817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  switch(vf->ready_state){
4827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  case OPENED:
4837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  case STREAMSET:
4847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for(i=0;i<vf->links;i++)
4857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->offsets[i+1]>=vf->offset)break;
4867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(i==vf->links)return -1;
4877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    i=_set_link_number_preserve_pos(vf,i);
4887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(i)return i;
4897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* fall through */
4907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  case LINKSET:
4917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->vd=vorbis_dsp_create(&vf->vi);
4927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->ready_state=INITSET;
4937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->bittrack=0;
4947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->samptrack=0;
4957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  case INITSET:
4967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return 0;
4977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  default:
4987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return -1;
4997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
5007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
5027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _open_seekable2(OggVorbis_File *vf){
5047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_uint32_t serialno=vf->current_serialno;
5057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_uint32_t tempserialno;
5067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t dataoffset=vf->offset, end;
5077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
5087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* we're partially open and have a first link header state in
5107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     storage in vf */
5117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* we can seek, so set out learning all about this file */
5127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
5137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
5147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* We get the offset for the last page of the physical bitstream.
5167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     Most OggVorbis files will contain a single logical bitstream */
5177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  end=_get_prev_page(vf,&og);
5187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(end<0)return (int)end;
5197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* more than one logical bitstream? */
5217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  tempserialno=ogg_page_serialno(&og);
5227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
5237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(tempserialno!=serialno){
5257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* Chained bitstream. Bisect-search each logical bitstream
5277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       section.  Do so based on serial number only */
5287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return OV_EREAD;
5297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
5317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* Only one logical bitstream */
5337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return OV_EREAD;
5347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
5367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* the initial header memory is referenced by vf after; don't free it */
5387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _prefetch_all_offsets(vf,dataoffset);
5397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ov_raw_seek(vf,0);
5407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
5417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* fetch and process a packet.  Handles the case where we're at a
5437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   bitstream boundary and dumps the decoding machine.  If the decoding
5447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   machine is unloaded, it loads it.  It also keeps pcm_offset up to
5457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   date (seek and read both use this.  seek uses a special hack with
5467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   readp).
5477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   return: <0) error, OV_HOLE (lost packet) or OV_EOF
5497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            0) need more data (only if readp==0)
5507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    1) got a packet
5517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang*/
5527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _fetch_and_process_packet(OggVorbis_File *vf,
5547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				     int readp,
5557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				     int spanp){
5567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
5577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet op={0,0,0,0,0,0};
5587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int ret=0;
5597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* handle one packet.  Try to fetch it from current stream state */
5617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* extract packets from page */
5627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(1){
5637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* process a packet if we can.  If the machine isn't loaded,
5657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       neither is a page */
5667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->ready_state==INITSET){
5677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      while(1) {
5687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	int result=ogg_stream_packetout(vf->os,&op);
5697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_int64_t granulepos;
5707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result<0){
5727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  ret=OV_HOLE; /* hole in the data. */
5737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  goto cleanup;
5747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
5757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result>0){
5767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* got a packet.  process it */
5777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  granulepos=op.granulepos;
5787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(!vorbis_dsp_synthesis(vf->vd,&op,1)){ /* lazy check for lazy
5797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang						      header handling.  The
5807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang						      header packets aren't
5817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang						      audio, so if/when we
5827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang						      submit them,
5837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang						      vorbis_synthesis will
5847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang						      reject them */
5857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    vf->samptrack+=vorbis_dsp_pcmout(vf->vd,NULL,0);
5877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    vf->bittrack+=op.bytes*8;
5887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    /* update the pcm offset. */
5907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(granulepos!=-1 && !op.e_o_s){
5917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      int link=(vf->seekable?vf->current_link:0);
5927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      int i,samples;
5937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      /* this packet has a pcm_offset on it (the last packet
5957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         completed on a page carries the offset) After processing
5967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         (above), we know the pcm position of the *last* sample
5977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         ready to be returned. Find the offset of the *first*
5987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
5997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         As an aside, this trick is inaccurate if we begin
6007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         reading anew right at the last page; the end-of-stream
6017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         granulepos declares the last frame in the stream, and the
6027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         last packet of the last page may be a partial frame.
6037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         So, we need a previous granulepos from an in-sequence page
6047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         to have a reference point.  Thus the !op.e_o_s clause
6057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	         above */
6067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      if(vf->seekable && link>0)
6087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		granulepos-=vf->pcmlengths[link*2];
6097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      if(granulepos<0)granulepos=0; /* actually, this
6107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang					       shouldn't be possible
6117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang					       here unless the stream
6127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang					       is very broken */
6137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      samples=vorbis_dsp_pcmout(vf->vd,NULL,0);
6157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      granulepos-=samples;
6177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      for(i=0;i<link;i++)
6187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	        granulepos+=vf->pcmlengths[i*2+1];
6197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      vf->pcm_offset=granulepos;
6207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    }
6217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    ret=1;
6227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    goto cleanup;
6237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
6247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
6257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	else
6267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
6277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
6287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
6297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->ready_state>=OPENED){
6317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int ret;
6327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(!readp){
6337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=0;
6347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	goto cleanup;
6357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
6367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ret=(int)_get_next_page(vf,&og,-1);
6377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret<0){
6387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=OV_EOF; /* eof. leave unitialized */
6397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	goto cleanup;
6407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
6417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* bitrate tracking; add the header's bytes here, the body bytes
6437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	   are done by packet above */
6447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vf->bittrack+=og.header_len*8;
6457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* has our decoding just traversed a bitstream boundary? */
6477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->ready_state==INITSET){
6487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(vf->current_serialno!=ogg_page_serialno(&og)){
6497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(!spanp){
6507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    ret=OV_EOF;
6517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    goto cleanup;
6527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
6537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  _decode_clear(vf);
6557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
6567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
6577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
6587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* Do we need to load a new machine before submitting the page? */
6607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* This is different in the seekable and non-seekable cases.
6617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       In the seekable case, we already have all the header
6637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       information loaded and cached; we just initialize the machine
6647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       with it and continue on our merry way.
6657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       In the non-seekable (streaming) case, we'll only be at a
6677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       boundary if we just left the previous logical bitstream and
6687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       we're now nominally at the header of the next bitstream
6697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    */
6707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->ready_state!=INITSET){
6727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int link,ret;
6737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->ready_state<STREAMSET){
6757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(vf->seekable){
6767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->current_serialno=ogg_page_serialno(&og);
6777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* match the serialno to bitstream section.  We use this rather than
6797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	     offset positions to avoid problems near logical bitstream
6807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	     boundaries */
6817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  for(link=0;link<vf->links;link++)
6827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(vf->serialnos[link]==vf->current_serialno)break;
6837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(link==vf->links){
6847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    ret=OV_EBADLINK; /* sign of a bogus stream.  error out,
6857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang				leave machine uninitialized */
6867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    goto cleanup;
6877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
6887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->current_link=link;
6907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og);
6917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(ret) goto cleanup;
6927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}else{
6947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* we're streaming */
6957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* fetch the three header packets, build the info struct */
6967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
6977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  int ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og);
6987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(ret) goto cleanup;
6997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->current_link++;
7007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
7017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
7027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(_make_decode_ready(vf)) return OV_EBADLINK;
7047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
7057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_stream_pagein(vf->os,&og);
7067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
7077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang cleanup:
7087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
7097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
7107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ret;
7117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
7127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* if, eg, 64 bit stdio is configured by default, this will build with
7147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   fseek64 */
7157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
7167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(f==NULL)return -1;
7177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return fseek(f,(long)off,whence);
7187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
7197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
7217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		     long ibytes, ov_callbacks callbacks){
7227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
7237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int ret;
7247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  memset(vf,0,sizeof(*vf));
7267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* Tremor assumes in multiple places that right shift of a signed
7287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     integer is an arithmetic shift */
7297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if( (-1>>1) != -1) return OV_EIMPL;
7307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->datasource=f;
7327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->callbacks = callbacks;
7337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* init the framing state */
7357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->oy=ogg_sync_create();
7367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* perhaps some data was previously read into a buffer for testing
7387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     against other stream types.  Allow initialization from this
7397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     previously read data (as we may be reading from a non-seekable
7407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     stream) */
7417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(initial){
7427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes);
7437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    memcpy(buffer,initial,ibytes);
7447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_sync_wrote(vf->oy,ibytes);
7457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
7467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* can we seek? Stevens suggests the seek test was portable */
7487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(offsettest!=-1)vf->seekable=1;
7497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* No seeking yet; Set up a 'single' (current) logical bitstream
7517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     entry for partial open */
7527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->links=1;
7537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->os=ogg_stream_create(-1); /* fill in the serialno later */
7547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* Try to fetch the headers, maintaining all the storage */
7567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if((ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,NULL))<0){
7577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->datasource=NULL;
7587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ov_clear(vf);
7597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else if(vf->ready_state < PARTOPEN)
7607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->ready_state=PARTOPEN;
7617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ret;
7627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
7637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic int _ov_open2(OggVorbis_File *vf){
7657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state < OPENED)
7667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->ready_state=OPENED;
7677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->seekable){
7687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int ret=_open_seekable2(vf);
7697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret){
7707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vf->datasource=NULL;
7717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ov_clear(vf);
7727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
7737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return ret;
7747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
7757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
7767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
7777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* clear out the OggVorbis_File struct */
7807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_clear(OggVorbis_File *vf){
7817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf){
7827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_dsp_destroy(vf->vd);
7837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->vd=0;
7847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_stream_destroy(vf->os);
7857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_info_clear(&vf->vi);
7867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_comment_clear(&vf->vc);
7877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
7887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
7897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->serialnos)_ogg_free(vf->serialnos);
7907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->offsets)_ogg_free(vf->offsets);
7917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_sync_destroy(vf->oy);
7927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
7937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
7947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    memset(vf,0,sizeof(*vf));
7957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
7967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#ifdef DEBUG_LEAKS
7977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _VDBG_dump();
7987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#endif
7997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
8007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* inspects the OggVorbis file and finds/documents all the logical
8037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   bitstreams contained in it.  Tries to be tolerant of logical
8047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   bitstream sections that are truncated/woogie.
8057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   return: -1) error
8077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            0) OK
8087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang*/
8097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
8117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ov_callbacks callbacks){
8127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
8137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(ret)return ret;
8147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return _ov_open2(vf);
8157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
8187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ov_callbacks callbacks = {
8197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (size_t (*)(void *, size_t, size_t, void *))  fread,
8207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
8217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (int (*)(void *))                             fclose,
8227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (long (*)(void *))                            ftell
8237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  };
8247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
8267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* Only partially open the vorbis file; test for Vorbisness, and load
8297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   the headers for the first chain.  Do not seek (although test for
8307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   seekability).  Use ov_test_open to finish opening the file, else
8317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   ov_clear to close/free it. Same return codes as open. */
8327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
8347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ov_callbacks callbacks)
8357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
8367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return _ov_open1(f,vf,initial,ibytes,callbacks);
8377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
8407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ov_callbacks callbacks = {
8417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (size_t (*)(void *, size_t, size_t, void *))  fread,
8427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
8437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (int (*)(void *))                             fclose,
8447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    (long (*)(void *))                            ftell
8457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  };
8467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
8487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_test_open(OggVorbis_File *vf){
8517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state!=PARTOPEN)return OV_EINVAL;
8527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return _ov_open2(vf);
8537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* How many logical bitstreams in this physical bitstream? */
8567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanglong ov_streams(OggVorbis_File *vf){
8577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return vf->links;
8587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* Is the FILE * associated with vf seekable? */
8617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanglong ov_seekable(OggVorbis_File *vf){
8627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return vf->seekable;
8637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
8647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* returns the bitrate for a given logical bitstream or the entire
8667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   physical bitstream.  If the file is open for random access, it will
8677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   find the *actual* average bitrate.  If the file is streaming, it
8687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   returns the nominal bitrate (if set) else the average of the
8697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   upper/lower bounds (if set) else -1 (unset).
8707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   If you want the actual bitrate field settings, get them from the
8727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   vorbis_info structs */
8737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
8747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanglong ov_bitrate(OggVorbis_File *vf,int i){
8757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
8767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i>=vf->links)return OV_EINVAL;
8777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable && i!=0)return ov_bitrate(vf,0);
8787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i<0){
8797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t bits=0;
8807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int i;
8817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for(i=0;i<vf->links;i++)
8827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
8837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* This once read: return(rint(bits/ov_time_total(vf,-1)));
8847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
8857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     * so this is slightly transformed to make it work.
8867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     */
8877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return (long)(bits*1000/ov_time_total(vf,-1));
8887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
8897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->seekable){
8907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* return the actual bitrate */
8917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      return (long)((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));
8927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }else{
8937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* return nominal if set */
8947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->vi.bitrate_nominal>0){
8957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return vf->vi.bitrate_nominal;
8967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }else{
8977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(vf->vi.bitrate_upper>0){
8987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(vf->vi.bitrate_lower>0){
8997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    return (vf->vi.bitrate_upper+vf->vi.bitrate_lower)/2;
9007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }else{
9017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    return vf->vi.bitrate_upper;
9027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
9037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
9047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return OV_FALSE;
9057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
9067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
9077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
9087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
9097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* returns the actual bitrate since last call.  returns -1 if no
9117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   additional data to offer since last call (or at beginning of stream),
9127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   EINVAL if stream is only partially open
9137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang*/
9147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanglong ov_bitrate_instant(OggVorbis_File *vf){
9157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  long ret;
9167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
9177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->samptrack==0)return OV_FALSE;
9187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ret=(long)(vf->bittrack/vf->samptrack*vf->vi.rate);
9197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->bittrack=0;
9207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->samptrack=0;
9217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return ret;
9227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
9237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* Guess */
9257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanglong ov_serialnumber(OggVorbis_File *vf,int i){
9267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i>=vf->links)return ov_serialnumber(vf,vf->links-1);
9277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable && i>=0)return ov_serialnumber(vf,-1);
9287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i<0){
9297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return vf->current_serialno;
9307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
9317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return vf->serialnos[i];
9327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
9337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
9347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* returns: total raw (compressed) length of content if i==-1
9367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            raw (compressed) length of that logical bitstream for i==0 to n
9377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    OV_EINVAL if the stream is not seekable (we can't know the length)
9387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    or if stream is only partially open
9397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang*/
9407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
9417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
9427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable || i>=vf->links)return OV_EINVAL;
9437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i<0){
9447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t acc=0;
9457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int i;
9467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for(i=0;i<vf->links;i++)
9477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      acc+=ov_raw_total(vf,i);
9487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return acc;
9497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
9507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return vf->offsets[i+1]-vf->offsets[i];
9517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
9527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
9537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* returns: total PCM length (samples) of content if i==-1 PCM length
9557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    (samples) of that logical bitstream for i==0 to n
9567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    OV_EINVAL if the stream is not seekable (we can't know the
9577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    length) or only partially open
9587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang*/
9597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
9607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
9617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable || i>=vf->links)return OV_EINVAL;
9627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i<0){
9637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t acc=0;
9647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int i;
9657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for(i=0;i<vf->links;i++)
9667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      acc+=ov_pcm_total(vf,i);
9677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return acc;
9687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
9697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return vf->pcmlengths[i*2+1];
9707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
9717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
9727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* returns: total milliseconds of content if i==-1
9747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang            milliseconds in that logical bitstream for i==0 to n
9757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    OV_EINVAL if the stream is not seekable (we can't know the
9767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    length) or only partially open
9777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang*/
9787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
9797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
9807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable || i>=vf->links)return OV_EINVAL;
9817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(i<0){
9827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t acc=0;
9837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int i;
9847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for(i=0;i<vf->links;i++)
9857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      acc+=ov_time_total(vf,i);
9867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return acc;
9877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
9887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return ((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi.rate;
9897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
9907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
9917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* seek to an offset relative to the *compressed* data. This also
9937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   scans packets to update the PCM cursor. It will cross a logical
9947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   bitstream boundary, but only if it can't get any packets out of the
9957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   tail of the bitstream we seek to (so no surprises).
9967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   returns zero on success, nonzero on failure */
9987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
9997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
10007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_stream_state *work_os=NULL;
10017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
10027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet op={0,0,0,0,0,0};
10037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
10057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable)
10067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return OV_ENOSEEK; /* don't dump machine if we can't seek */
10077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(pos<0 || pos>vf->end)return OV_EINVAL;
10097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* don't yet clear out decoding machine (if it's initialized), in
10117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     the case we're in the same link.  Restart the decode lapping, and
10127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     let _fetch_and_process_packet deal with a potential bitstream
10137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     boundary */
10147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->pcm_offset=-1;
10157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_stream_reset_serialno(vf->os,
10167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			    vf->current_serialno); /* must set serialno */
10177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vorbis_dsp_restart(vf->vd);
10187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _seek_helper(vf,pos);
10207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* we need to make sure the pcm_offset is set, but we don't want to
10227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     advance the raw cursor past good packets just to get to the first
10237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     with a granulepos.  That's not equivalent behavior to beginning
10247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     decoding as immediately after the seek position as possible.
10257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     So, a hack.  We use two stream states; a local scratch state and
10277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     the shared vf->os stream state.  We use the local state to
10287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     scan, and the shared state as a buffer for later decode.
10297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     Unfortuantely, on the last page we still advance to last packet
10317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     because the granulepos on the last page is not necessarily on a
10327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     packet boundary, and we need to make sure the granpos is
10337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     correct.
10347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  */
10357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  {
10377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int lastblock=0;
10387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int accblock=0;
10397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int thisblock;
10407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int eosflag;
10417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */
10437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    while(1){
10447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->ready_state>=STREAMSET){
10457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* snarf/scan a packet if we can */
10467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	int result=ogg_stream_packetout(work_os,&op);
10477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result>0){
10497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(vf->vi.codec_setup){
10517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    thisblock=vorbis_packet_blocksize(&vf->vi,&op);
10527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(thisblock<0){
10537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      ogg_stream_packetout(vf->os,NULL);
10547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      thisblock=0;
10557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    }else{
10567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      if(eosflag)
10587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		ogg_stream_packetout(vf->os,NULL);
10597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      else
10607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		if(lastblock)accblock+=(lastblock+thisblock)>>2;
10617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    }
10627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(op.granulepos!=-1){
10647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      int i,link=vf->current_link;
10657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
10667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      if(granulepos<0)granulepos=0;
10677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      for(i=0;i<link;i++)
10697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		granulepos+=vf->pcmlengths[i*2+1];
10707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      vf->pcm_offset=granulepos-accblock;
10717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      break;
10727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    }
10737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    lastblock=thisblock;
10747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    continue;
10757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }else
10767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    ogg_stream_packetout(vf->os,NULL);
10777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
10787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
10797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(!lastblock){
10817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(_get_next_page(vf,&og,-1)<0){
10827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->pcm_offset=ov_pcm_total(vf,-1);
10837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
10847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
10857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }else{
10867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* huh?  Bogus stream with packets but no granulepos */
10877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->pcm_offset=-1;
10887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	break;
10897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
10907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* did we just grab a page from other than current link? */
10927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->ready_state>=STREAMSET)
10937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(vf->current_serialno!=ogg_page_serialno(&og)){
10947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  _decode_clear(vf); /* clear out stream state */
10957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  ogg_stream_destroy(work_os);
10967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
10977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
10987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->ready_state<STREAMSET){
10997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	int link;
11007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->current_serialno=ogg_page_serialno(&og);
11027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	for(link=0;link<vf->links;link++)
11037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(vf->serialnos[link]==vf->current_serialno)break;
11047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(link==vf->links)
11057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  goto seek_error; /* sign of a bogus stream.  error out,
11067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			      leave machine uninitialized */
11077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* need to initialize machine to this link */
11097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	{
11107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  int ret=_set_link_number_preserve_pos(vf,link);
11117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(ret) goto seek_error;
11127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
11137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_stream_reset_serialno(vf->os,vf->current_serialno);
11147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_stream_reset_serialno(work_os,vf->current_serialno);
11157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
11187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      {
11207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_page dup;
11217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_page_dup(&dup,&og);
11227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	eosflag=ogg_page_eos(&og);
11237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_stream_pagein(vf->os,&og);
11247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_stream_pagein(work_os,&dup);
11257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
11267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
11277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
11287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
11307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
11317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_stream_destroy(work_os);
11327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->bittrack=0;
11337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->samptrack=0;
11347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
11357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang seek_error:
11377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
11387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
11397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* dump the machine so we're in a known state */
11417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->pcm_offset=-1;
11427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_stream_destroy(work_os);
11437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _decode_clear(vf);
11447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return OV_EBADLINK;
11457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
11467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* Page granularity seek (faster than sample granularity because we
11487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   don't do the last bit of decode to find a specific sample).
11497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   Seek to the last [granule marked] page preceeding the specified pos
11517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   location, such that decoding past the returned point will quickly
11527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   arrive at the requested position. */
11537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
11547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int link=-1;
11557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t result=0;
11567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t total=ov_pcm_total(vf,-1);
11577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
11587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet op={0,0,0,0,0,0};
11597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
11617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable)return OV_ENOSEEK;
11627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(pos<0 || pos>total)return OV_EINVAL;
11637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* which bitstream section does this pcm offset occur in? */
11657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  for(link=vf->links-1;link>=0;link--){
11667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    total-=vf->pcmlengths[link*2+1];
11677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(pos>=total)break;
11687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
11697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(link!=vf->current_link){
11727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int ret=_set_link_number(vf,link);
11737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret) goto seek_error;
11747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }else{
11757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_dsp_restart(vf->vd);
11767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
11777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_stream_reset_serialno(vf->os,vf->serialnos[link]);
11797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* search within the logical bitstream for the page with the highest
11817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     pcm_pos preceeding (or equal to) pos.  There is a danger here;
11827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     missing pages or incorrect frame number information in the
11837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     bitstream could make our task impossible.  Account for that (it
11847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     would be an error condition) */
11857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* new search algorithm by HB (Nicholas Vinen) */
11877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  {
11887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t end=vf->offsets[link+1];
11897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t begin=vf->offsets[link];
11907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t begintime = vf->pcmlengths[link*2];
11917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
11927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t target=pos-total+begintime;
11937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t best=begin;
11947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    while(begin<end){
11967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_int64_t bisect;
11977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
11987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(end-begin<CHUNKSIZE){
11997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	bisect=begin;
12007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }else{
12017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* take a (pretty decent) guess. */
12027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	bisect=begin +
12037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
12047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(bisect<=begin)
12057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  bisect=begin+1;
12067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
12077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      _seek_helper(vf,bisect);
12097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      while(begin<end){
12117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	result=_get_next_page(vf,&og,end-vf->offset);
12127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result==OV_EREAD) goto seek_error;
12137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result<0){
12147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(bisect<=begin+1)
12157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    end=begin; /* found it */
12167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  else{
12177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(bisect==0) goto seek_error;
12187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    bisect-=CHUNKSIZE;
12197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(bisect<=begin)bisect=begin+1;
12207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    _seek_helper(vf,bisect);
12217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
12227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}else{
12237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  ogg_int64_t granulepos=ogg_page_granulepos(&og);
12247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(granulepos==-1)continue;
12257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(granulepos<target){
12267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    best=result;  /* raw offset of packet with granulepos */
12277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    begin=vf->offset; /* raw offset of next page */
12287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    begintime=granulepos;
12297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(target-begintime>44100)break;
12317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    bisect=begin; /* *not* begin + 1 */
12327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }else{
12337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(bisect<=begin+1)
12347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      end=begin;  /* found it */
12357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    else{
12367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
12377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		end=result;
12387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		bisect-=CHUNKSIZE; /* an endless loop otherwise. */
12397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		if(bisect<=begin)bisect=begin+1;
12407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		_seek_helper(vf,bisect);
12417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      }else{
12427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		end=result;
12437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		endtime=granulepos;
12447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		break;
12457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      }
12467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    }
12477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
12487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
12497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
12507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
12517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* found our page. seek to it, update pcm offset. Easier case than
12537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang       raw_seek, don't keep packets preceeding granulepos. */
12547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    {
12557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* seek */
12577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      _seek_helper(vf,best);
12587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vf->pcm_offset=-1;
12597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(_get_next_page(vf,&og,-1)<0){
12617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_page_release(&og);
12627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return OV_EOF; /* shouldn't happen */
12637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
12647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_stream_pagein(vf->os,&og);
12667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* pull out all but last packet; the one with granulepos */
12687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      while(1){
12697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	result=ogg_stream_packetpeek(vf->os,&op);
12707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result==0){
12717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  /* !!! the packet finishing this page originated on a
12727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang             preceeding page. Keep fetching previous pages until we
12737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang             get one with a granulepos or without the 'continued' flag
12747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang             set.  Then just use raw_seek for simplicity. */
12757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  _seek_helper(vf,best);
12777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
12787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  while(1){
12797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    result=_get_prev_page(vf,&og);
12807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(result<0) goto seek_error;
12817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    if(ogg_page_granulepos(&og)>-1 ||
12827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	       !ogg_page_continued(&og)){
12837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	      return ov_raw_seek(vf,result);
12847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    }
12857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    vf->offset=result;
12867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  }
12877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
12887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(result<0){
12897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  result = OV_EBADPACKET;
12907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  goto seek_error;
12917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
12927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(op.granulepos!=-1){
12937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
12947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(vf->pcm_offset<0)vf->pcm_offset=0;
12957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->pcm_offset+=total;
12967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  break;
12977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}else
12987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  result=ogg_stream_packetout(vf->os,NULL);
12997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
13007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
13017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
13027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* verify result */
13047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
13057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    result=OV_EFAULT;
13067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    goto seek_error;
13077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
13087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->bittrack=0;
13097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->samptrack=0;
13107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
13127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
13137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
13147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang seek_error:
13167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
13187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
13197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* dump machine so we're in a known state */
13217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->pcm_offset=-1;
13227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  _decode_clear(vf);
13237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return (int)result;
13247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
13257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* seek to a sample offset relative to the decompressed pcm stream
13277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   returns zero on success, nonzero on failure */
13287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
13307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet op={0,0,0,0,0,0};
13317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page og={0,0,0,0};
13327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int thisblock,lastblock=0;
13337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int ret=ov_pcm_seek_page(vf,pos);
13347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(ret<0)return ret;
13357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(_make_decode_ready(vf))return OV_EBADLINK;
13367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* discard leading packets we don't need for the lapping of the
13387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     position we want; don't decode them */
13397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(1){
13417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int ret=ogg_stream_packetpeek(vf->os,&op);
13437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret>0){
13447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      thisblock=vorbis_packet_blocksize(&vf->vi,&op);
13457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(thisblock<0){
13467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ogg_stream_packetout(vf->os,NULL);
13477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	continue; /* non audio packet */
13487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
13497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
13507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->pcm_offset+((thisblock+
13527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			  vorbis_info_blocksize(&vf->vi,1))>>2)>=pos)break;
13537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* remove the packet from packet queue and track its granulepos */
13557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_stream_packetout(vf->os,NULL);
13567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      vorbis_dsp_synthesis(vf->vd,&op,0);  /* set up a vb with
13577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang					      only tracking, no
13587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang					      pcm_decode */
13597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* end of logical stream case is hard, especially with exact
13617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 length positioning. */
13627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(op.granulepos>-1){
13647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	int i;
13657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* always believe the stream markers */
13667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
13677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(vf->pcm_offset<0)vf->pcm_offset=0;
13687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	for(i=0;i<vf->current_link;i++)
13697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->pcm_offset+=vf->pcmlengths[i*2+1];
13707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
13717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      lastblock=thisblock;
13737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }else{
13757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret<0 && ret!=OV_HOLE)break;
13767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      /* suck in a new page */
13787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(_get_next_page(vf,&og,-1)<0)break;
13797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
13807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->ready_state<STREAMSET){
13827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	int link,ret;
13837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->current_serialno=ogg_page_serialno(&og);
13857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	for(link=0;link<vf->links;link++)
13867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(vf->serialnos[link]==vf->current_serialno)break;
13877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(link==vf->links){
13887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  ogg_page_release(&og);
13897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  ogg_packet_release(&op);
13907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  return OV_EBADLINK;
13917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
13927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
13947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->current_link=link;
13957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og);
13967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(ret) return ret;
13977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(_make_decode_ready(vf))return OV_EBADLINK;
13987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	lastblock=0;
13997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
14007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ogg_stream_pagein(vf->os,&og);
14027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
14037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
14047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->bittrack=0;
14067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  vf->samptrack=0;
14077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* discard samples until we reach the desired position. Crossing a
14087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang     logical bitstream boundary with abandon is OK. */
14097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(vf->pcm_offset<pos){
14107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    ogg_int64_t target=pos-vf->pcm_offset;
14117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    long samples=vorbis_dsp_pcmout(vf->vd,NULL,0);
14127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(samples>target)samples=(long)target;
14147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vorbis_dsp_read(vf->vd,samples);
14157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    vf->pcm_offset+=samples;
14167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(samples<target)
14187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(_fetch_and_process_packet(vf,1,1)<=0)
14197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
14207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
14217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_page_release(&og);
14237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_packet_release(&op);
14247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return 0;
14257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
14267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* seek to a playback time relative to the decompressed pcm stream
14287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   returns zero on success, nonzero on failure */
14297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
14307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* translate time to PCM position and call ov_pcm_seek */
14317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int link=-1;
14337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
14347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t time_total=ov_time_total(vf,-1);
14357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
14377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable)return OV_ENOSEEK;
14387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(milliseconds<0 || milliseconds>time_total)return OV_EINVAL;
14397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* which bitstream section does this time offset occur in? */
14417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  for(link=vf->links-1;link>=0;link--){
14427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    pcm_total-=vf->pcmlengths[link*2+1];
14437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    time_total-=ov_time_total(vf,link);
14447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(milliseconds>=time_total)break;
14457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
14467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* enough information to convert time offset to pcm offset */
14487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  {
14497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int ret=_set_link_number(vf,link);
14507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret)return ret;
14517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return
14527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ov_pcm_seek(vf,pcm_total+(milliseconds-time_total)*
14537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		  vf->vi.rate/1000);
14547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
14557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
14567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* page-granularity version of ov_time_seek
14587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   returns zero on success, nonzero on failure */
14597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){
14607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* translate time to PCM position and call ov_pcm_seek */
14617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int link=-1;
14637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
14647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t time_total=ov_time_total(vf,-1);
14657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
14677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(!vf->seekable)return OV_ENOSEEK;
14687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(milliseconds<0 || milliseconds>time_total)return OV_EINVAL;
14697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* which bitstream section does this time offset occur in? */
14717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  for(link=vf->links-1;link>=0;link--){
14727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    pcm_total-=vf->pcmlengths[link*2+1];
14737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    time_total-=ov_time_total(vf,link);
14747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(milliseconds>=time_total)break;
14757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
14767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  /* enough information to convert time offset to pcm offset */
14787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  {
14797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int ret=_set_link_number(vf,link);
14807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(ret)return ret;
14817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    return
14827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      ov_pcm_seek_page(vf,pcm_total+(milliseconds-time_total)*
14837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		       vf->vi.rate/1000);
14847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
14857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
14867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* tell the current stream offset cursor.  Note that seek followed by
14887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   tell will likely not give the set offset due to caching */
14897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangogg_int64_t ov_raw_tell(OggVorbis_File *vf){
14907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
14917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return vf->offset;
14927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
14937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
14947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* return PCM offset (sample) of next PCM sample to be read */
14957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
14967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
14977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return vf->pcm_offset;
14987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
14997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* return time offset (milliseconds) of next PCM sample to be read */
15017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangogg_int64_t ov_time_tell(OggVorbis_File *vf){
15027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  int link=0;
15037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t pcm_total=0;
15047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  ogg_int64_t time_total=0;
15057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
15077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->seekable){
15087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    pcm_total=ov_pcm_total(vf,-1);
15097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    time_total=ov_time_total(vf,-1);
15107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* which bitstream section does this time offset occur in? */
15127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for(link=vf->links-1;link>=0;link--){
15137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      pcm_total-=vf->pcmlengths[link*2+1];
15147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      time_total-=ov_time_total(vf,link);
15157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(vf->pcm_offset>=pcm_total)break;
15167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
15177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
15187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi.rate;
15207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
15217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/*  link:   -1) return the vorbis_info struct for the bitstream section
15237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                currently being decoded
15247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang           0-n) to request information for a specific bitstream section
15257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    In the case of a non-seekable bitstream, any call returns the
15277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    current bitstream.  NULL in the case that the machine is not
15287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    initialized */
15297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangvorbis_info *ov_info(OggVorbis_File *vf,int link){
15317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->seekable){
15327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(link>=vf->links)return NULL;
15337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(link>=0){
15347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int ret=_set_link_number_preserve_pos(vf,link);
15357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret)return NULL;
15367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
15377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
15387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return &vf->vi;
15397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
15407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* grr, strong typing, grr, no templates/inheritence, grr */
15427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangvorbis_comment *ov_comment(OggVorbis_File *vf,int link){
15437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->seekable){
15447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(link>=vf->links)return NULL;
15457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(link>=0){
15467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int ret=_set_link_number_preserve_pos(vf,link);
15477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret)return NULL;
15487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
15497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
15507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  return &vf->vc;
15517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
15527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/* up to this point, everything could more or less hide the multiple
15547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   logical bitstream nature of chaining from the toplevel application
15557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   if the toplevel application didn't particularly care.  However, at
15567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   the point that we actually read audio back, the multiple-section
15577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   nature must surface: Multiple bitstream sections do not necessarily
15587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   have to have the same number of channels or sampling rate.
15597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   ov_read returns the sequential logical bitstream number currently
15617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   being decoded along with the PCM data in order that the toplevel
15627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   application can take action on channel/sample rate changes.  This
15637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   number will be incremented even for streamed (non-seekable) streams
15647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   (for seekable streams, it represents the actual logical bitstream
15657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   index within the physical bitstream.  Note that the accessor
15667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   functions above are aware of this dichotomy).
15677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   input values: buffer) a buffer to hold packed PCM data for return
15697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		 length) the byte length requested to be placed into buffer
15707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
15727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang                   0) EOF
15737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		   n) number of bytes of PCM actually returned.  The
15747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		   below works on a packet-by-packet basis, so the
15757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		   return length is not related to the 'length' passed
15767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		   in, just guaranteed to fit.
15777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	    *section) set to the logical bitstream number */
15797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanglong ov_read(OggVorbis_File *vf,void *buffer,int bytes_req,int *bitstream){
15817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  long samples;
15837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  long channels;
15847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  if(vf->ready_state<OPENED)return OV_EINVAL;
15867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
15877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  while(1){
15887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    if(vf->ready_state==INITSET){
15897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      channels=vf->vi.channels;
15907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      samples=vorbis_dsp_pcmout(vf->vd,buffer,(bytes_req>>1)/channels);
15917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(samples){
15927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if(samples>0){
15937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vorbis_dsp_read(vf->vd,samples);
15947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  vf->pcm_offset+=samples;
15957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  if(bitstream)*bitstream=vf->current_link;
15967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	  return samples*2*channels;
15977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
15987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return samples;
15997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      }
16007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
16017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
16027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    /* suck in another packet */
16037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    {
16047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      int ret=_fetch_and_process_packet(vf,1,1);
16057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret==OV_EOF)
16067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return 0;
16077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang      if(ret<=0)
16087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return ret;
16097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
16107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
16117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang  }
16127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1613