int process_packet(int readp)
{
Page og=new Page();
// handle one packet. Try to fetch it from current stream state
// extract packets from page
while(true)
{
// process a packet if we can. If the machine isn't loaded,
// neither is a page
if(decode_ready)
{
Packet op=new Packet();
int result=os.packetout(op);
long granulepos;
// if(result==-1)return(-1); // hole in the data. For now, swallow
// and go. We'll need to add a real
// error code in a bit.
if(result>0)
{
// got a packet. process it
granulepos=op.granulepos;
if(vb.synthesis(op)==0)
{ // lazy check for lazy
// header handling. The
// header packets aren't
// audio, so if/when we
// submit them,
// vorbis_synthesis will
// reject them
// suck in the synthesis data and track bitrate
{
int oldsamples=vd.synthesis_pcmout(null, null);
vd.synthesis_blockin(vb);
samptrack+=vd.synthesis_pcmout(null, null)-oldsamples;
bittrack+=op.bytes*8;
}
// update the pcm offset.
if(granulepos!=-1 && op.e_o_s==0)
{
int link=(skable?current_link:0);
int samples;
// this packet has a pcm_offset on it (the last packet
// completed on a page carries the offset) After processing
// (above), we know the pcm position of the *last* sample
// ready to be returned. Find the offset of the *first*
//
// As an aside, this trick is inaccurate if we begin
// reading anew right at the last page; the end-of-stream
// granulepos declares the last frame in the stream, and the
// last packet of the last page may be a partial frame.
// So, we need a previous granulepos from an in-sequence page
// to have a reference point. Thus the !op.e_o_s clause above
samples=vd.synthesis_pcmout(null, null);
granulepos-=samples;
for(int i=0;i<link;i++)
{
granulepos+=pcmlengths[i];
}
pcm_offset=granulepos;
}
return(1);
}
}
}
if(readp==0)return(0);
if(get_next_page(og,-1)<0)return(0); // eof. leave unitialized
// bitrate tracking; add the header's bytes here, the body bytes
// are done by packet above
bittrack+=og.header_len*8;
// has our decoding just traversed a bitstream boundary?
if(decode_ready)
{
if(current_serialno!=og.serialno())
{
decode_clear();
}
}
// Do we need to load a new machine before submitting the page?
// This is different in the seekable and non-seekable cases.
//
// In the seekable case, we already have all the header
// information loaded and cached; we just initialize the machine
// with it and continue on our merry way.
//
// In the non-seekable (streaming) case, we'll only be at a
// boundary if we just left the previous logical bitstream and
// we're now nominally at the header of the next bitstream
if(!decode_ready)
{
int i;
if(skable)
{
current_serialno=og.serialno();
// match the serialno to bitstream section. We use this rather than
// offset positions to avoid problems near logical bitstream
// boundaries
for(i=0;i<links;i++)
{
if(serialnos[i]==current_serialno)break;
}
if(i==links)return(-1); // sign of a bogus stream. error out,
// leave machine uninitialized
current_link=i;
os.init(current_serialno);
os.reset();
}
else
{
// we're streaming
// fetch the three header packets, build the info struct
int[] foo = new int[1];
int ret=fetch_headers(vi[0], vc[0], foo, og);
current_serialno=foo[0];
if(ret!=0)return ret;
current_link++;
i=0;
}
make_decode_ready();
}
os.pagein(og);
}
}