Example #1
0
		// fetch and process a packet.  Handles the case where we're at a
		// bitstream boundary and dumps the decoding machine.  If the decoding
		// machine is unloaded, it loads it.  It also keeps pcm_offset up to
		// date (seek and read both use this.  seek uses a special hack with
		// readp). 
		//
		// return: -1) hole in the data (lost packet) 
		//          0) need more date (only if readp==0)/eof
		//          1) got a packet 

		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);
			}
		}