diff options
Diffstat (limited to 'songdbj/com/jcraft/jogg/StreamState.java')
| -rw-r--r-- | songdbj/com/jcraft/jogg/StreamState.java | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/songdbj/com/jcraft/jogg/StreamState.java b/songdbj/com/jcraft/jogg/StreamState.java new file mode 100644 index 0000000..2f34b37 --- /dev/null +++ b/songdbj/com/jcraft/jogg/StreamState.java @@ -0,0 +1,657 @@ +/* JOrbis + * Copyright (C) 2000 ymnk, JCraft,Inc. + * + * Written by: 2000 ymnk<ymnk@jcraft.com> + * + * Many thanks to + * Monty <monty@xiph.org> and + * The XIPHOPHORUS Company http://www.xiph.org/ . + * JOrbis has been based on their awesome works, Vorbis codec. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package com.jcraft.jogg; + +public class StreamState{ + byte[] body_data; /* bytes from packet bodies */ + int body_storage; /* storage elements allocated */ + int body_fill; /* elements stored; fill mark */ +private int body_returned; /* elements of fill returned */ + + + int[] lacing_vals; /* The values that will go to the segment table */ + long[] granule_vals; /* pcm_pos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + int lacing_storage; + int lacing_fill; + int lacing_packet; + int lacing_returned; + + byte[] header=new byte[282]; /* working space for header encode */ + int header_fill; + + public int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + int serialno; + int pageno; + long packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ + long granulepos; + + public StreamState(){ + init(); + } + + StreamState(int serialno){ + this(); + init(serialno); + } + void init(){ + body_storage=16*1024; + body_data=new byte[body_storage]; + lacing_storage=1024; + lacing_vals=new int[lacing_storage]; + granule_vals=new long[lacing_storage]; + } + public void init(int serialno){ + if(body_data==null){ init(); } + else{ + for(int i=0; i<body_data.length; i++) body_data[i]=0; + for(int i=0; i<lacing_vals.length; i++) lacing_vals[i]=0; + for(int i=0; i<granule_vals.length; i++) granule_vals[i]=0; + } + this.serialno=serialno; + } + public void clear(){ + body_data=null; + lacing_vals=null; + granule_vals=null; + //memset(os,0,sizeof(ogg_stream_state)); + } + void destroy(){ + clear(); + } + void body_expand(int needed){ + if(body_storage<=body_fill+needed){ + body_storage+=(needed+1024); + byte[] foo=new byte[body_storage]; + System.arraycopy(body_data, 0, foo, 0, body_data.length); + body_data=foo; +//System.out.println("expand: body_fill="+body_fill+", body_storage="+body_data.length); + } + } + void lacing_expand(int needed){ + if(lacing_storage<=lacing_fill+needed){ + lacing_storage+=(needed+32); + int[] foo=new int[lacing_storage]; + System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length); + lacing_vals=foo; + + long[] bar=new long[lacing_storage]; + System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length); + granule_vals=bar; + } + } + + /* submit data to the internal buffer of the framing engine */ + public int packetin(Packet op){ + int lacing_val=op.bytes/255+1; + + if(body_returned!=0){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + body_fill-=body_returned; + if(body_fill!=0){ +// memmove(os->body_data,os->body_data+os->body_returned, +// os->body_fill*sizeof(char)); + System.arraycopy(body_data, body_returned, body_data, 0, body_fill); + } + body_returned=0; + } + + /* make sure we have the buffer storage */ + body_expand(op.bytes); + lacing_expand(lacing_val); + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes); + body_fill+=op.bytes; +//System.out.println("add: "+body_fill); + + /* Store lacing vals for this packet */ + int j; + for(j=0;j<lacing_val-1;j++){ + lacing_vals[lacing_fill+j]=255; + granule_vals[lacing_fill+j]=granulepos; + } + lacing_vals[lacing_fill+j]=(op.bytes)%255; + granulepos=granule_vals[lacing_fill+j]=op.granulepos; + + /* flag the first segment as the beginning of the packet */ + lacing_vals[lacing_fill]|= 0x100; + + lacing_fill+=lacing_val; + + /* for the sake of completeness */ + packetno++; + + if(op.e_o_s!=0)e_o_s=1; + return(0); + } + + public int packetout(Packet op){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=lacing_returned; + + if(lacing_packet<=ptr){ + return(0); + } + + if((lacing_vals[ptr]&0x400)!=0){ + /* We lost sync here; let the app know */ + lacing_returned++; + + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + packetno++; + return(-1); + } + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=lacing_vals[ptr]&0xff; + int bytes=0; + + op.packet_base=body_data; + op.packet=body_returned; + op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */ + op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */ + bytes+=size; + + while(size==255){ + int val=lacing_vals[++ptr]; + size=val&0xff; + if((val&0x200)!=0)op.e_o_s=0x200; + bytes+=size; + } + + op.packetno=packetno; + op.granulepos=granule_vals[ptr]; + op.bytes=bytes; + +//System.out.println(this+" # body_returned="+body_returned); + body_returned+=bytes; +//System.out.println(this+"## body_returned="+body_returned); + + lacing_returned=ptr+1; + } + packetno++; + return(1); + } + + + // add the incoming page to the stream state; we decompose the page + // into packet segments here as well. + + public int pagein(Page og){ + byte[] header_base=og.header_base; + int header=og.header; + byte[] body_base=og.body_base; + int body=og.body; + int bodysize=og.body_len; + int segptr=0; + + int version=og.version(); + int continued=og.continued(); + int bos=og.bos(); + int eos=og.eos(); + long granulepos=og.granulepos(); + int _serialno=og.serialno(); + int _pageno=og.pageno(); + int segments=header_base[header+26]&0xff; + + // clean up 'returned data' + { + int lr=lacing_returned; + int br=body_returned; + + // body data + +//System.out.println("br="+br+", body_fill="+body_fill); + + if(br!=0){ + body_fill-=br; + if(body_fill!=0){ + System.arraycopy(body_data, br, body_data, 0, body_fill); + } + body_returned=0; + } + +//System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned); + + if(lr!=0){ + // segment table + if((lacing_fill-lr)!=0){ + System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr); + System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr); + } + lacing_fill-=lr; + lacing_packet-=lr; + lacing_returned=0; + } + } + + // check the serial number + if(_serialno!=serialno)return(-1); + if(version>0)return(-1); + + lacing_expand(segments+1); + + // are we in sequence? + if(_pageno!=pageno){ + int i; + + // unroll previous partial packet (if any) + for(i=lacing_packet;i<lacing_fill;i++){ + body_fill-=lacing_vals[i]&0xff; +//System.out.println("??"); + } + lacing_fill=lacing_packet; + + // make a note of dropped data in segment table + if(pageno!=-1){ + lacing_vals[lacing_fill++]=0x400; + lacing_packet++; + } + + // are we a 'continued packet' page? If so, we'll need to skip + // some segments + if(continued!=0){ + bos=0; + for(;segptr<segments;segptr++){ + int val=(header_base[header+27+segptr]&0xff); + body+=val; + bodysize-=val; + if(val<255){ + segptr++; + break; + } + } + } + } + +//System.out.println("bodysize="+bodysize); + + if(bodysize!=0){ + body_expand(bodysize); + System.arraycopy(body_base, body, body_data, body_fill, bodysize); + body_fill+=bodysize; + } + +//System.out.println("bodyfill="+body_fill); + + { + int saved=-1; + while(segptr<segments){ + int val=(header_base[header+27+segptr]&0xff); + lacing_vals[lacing_fill]=val; + granule_vals[lacing_fill]=-1; + + if(bos!=0){ + lacing_vals[lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=lacing_fill; + + lacing_fill++; + segptr++; + + if(val<255)lacing_packet=lacing_fill; + } + + /* set the granulepos on the last pcmval of the last full packet */ + if(saved!=-1){ + granule_vals[saved]=granulepos; + } + } + + if(eos!=0){ + e_o_s=1; + if(lacing_fill>0) + lacing_vals[lacing_fill-1]|=0x200; + } + + pageno=_pageno+1; + return(0); + } + + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not gurantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + ogg_stream_page will flush the last page in a stream even if it's + undersized; you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you need to flush an undersized + page in the middle of a stream for some reason. */ + + public int flush(Page og){ + +//System.out.println(this+" ---body_returned: "+body_returned); + + int i; + int vals=0; + int maxvals=(lacing_fill>255?255:lacing_fill); + int bytes=0; + int acc=0; + long granule_pos=granule_vals[0]; + + if(maxvals==0)return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;vals<maxvals;vals++){ + if((lacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + } + else{ + for(vals=0;vals<maxvals;vals++){ + if(acc>4096)break; + acc+=(lacing_vals[vals]&0x0ff); + granule_pos=granule_vals[vals]; + } + } + + /* construct the header in temp storage */ + System.arraycopy("OggS".getBytes(), 0, header, 0, 4); + + /* stream structure version */ + header[4]=0x00; + + /* continued packet flag? */ + header[5]=0x00; + if((lacing_vals[0]&0x100)==0)header[5]|=0x01; + /* first page flag? */ + if(b_o_s==0) header[5]|=0x02; + /* last page flag? */ + if(e_o_s!=0 && lacing_fill==vals) header[5]|=0x04; + b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + header[i]=(byte)granule_pos; + granule_pos>>>=8; + } + + /* 32 bits of stream serial number */ + { + int _serialno=serialno; + for(i=14;i<18;i++){ + header[i]=(byte)_serialno; + _serialno>>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(pageno==-1)pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + int _pageno=pageno++; + for(i=18;i<22;i++){ + header[i]=(byte)_pageno; + _pageno>>>=8; + } + } + + /* zero for computation; filled in later */ + header[22]=0; + header[23]=0; + header[24]=0; + header[25]=0; + + /* segment table */ + header[26]=(byte)vals; + for(i=0;i<vals;i++){ + header[i+27]=(byte)lacing_vals[i]; + bytes+=(header[i+27]&0xff); + } + + /* set pointers in the ogg_page struct */ + og.header_base=header; + og.header=0; + og.header_len=header_fill=vals+27; + og.body_base=body_data; + og.body=body_returned; + og.body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + +//System.out.println("###body_returned: "+body_returned); + + lacing_fill-=vals; + System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4); + System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8); + body_returned+=bytes; + +//System.out.println("####body_returned: "+body_returned); + + /* calculate the checksum */ + + og.checksum(); + + /* done */ + return(1); + } + + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + public int pageout(Page og){ +// if(body_returned!=0){ +// /* advance packet data according to the body_returned pointer. We +// had to keep it around to return a pointer into the buffer last +// call */ +// +// body_fill-=body_returned; +// if(body_fill!=0){ // overlap? +// System.arraycopy(body_data, body_returned, body_data, 0, body_fill); +// } +// body_returned=0; +// } +// +//System.out.println("pageout: e_o_s="+e_o_s+" lacing_fill="+lacing_fill+" body_fill="+body_fill+", lacing_fill="+lacing_fill+" b_o_s="+b_o_s); +// +// if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */ +// body_fill > 4096 || /* 'page nominal size' case */ +// lacing_fill>=255 || /* 'segment table full' case */ +// (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */ +// int vals=0,bytes=0; +// int maxvals=(lacing_fill>255?255:lacing_fill); +// long acc=0; +// long pcm_pos=granule_vals[0]; +// +// /* construct a page */ +// /* decide how many segments to include */ +// +// /* If this is the initial header case, the first page must only include +// the initial header packet */ +// if(b_o_s==0){ /* 'initial header page' case */ +// pcm_pos=0; +// for(vals=0;vals<maxvals;vals++){ +// if((lacing_vals[vals]&0x0ff)<255){ +// vals++; +// break; +// } +// } +// } +// else{ +// for(vals=0;vals<maxvals;vals++){ +// if(acc>4096)break; +// acc+=lacing_vals[vals]&0x0ff; +// pcm_pos=granule_vals[vals]; +// } +// } +// +// /* construct the header in temp storage */ +// System.arraycopy("OggS".getBytes(), 0, header, 0, 4); +// +// /* stream structure version */ +// header[4]=0x00; +// +// /* continued packet flag? */ +// header[5]=0x00; +// if((lacing_vals[0]&0x100)==0)header[5]|=0x01; +// /* first page flag? */ +// if(b_o_s==0)header[5]|=0x02; +// /* last page flag? */ +// if(e_o_s!=0 && lacing_fill==vals)header[5]|=0x04; +// b_o_s=1; +// +// /* 64 bits of PCM position */ +// for(int i=6;i<14;i++){ +// header[i]=(byte)pcm_pos; +// pcm_pos>>>=8; +// } +// +// /* 32 bits of stream serial number */ +// { +// int serialn=serialno; +// for(int i=14;i<18;i++){ +// header[i]=(byte)serialn; +// serialn>>>=8; +// } +// } +// +// +///* 32 bits of page counter (we have both counter and page header +// because this val can roll over) */ +// if(pageno==-1)pageno=0; /* because someone called +// stream_reset; this would be a +// strange thing to do in an +// encode stream, but it has +// plausible uses */ +// { +// int pagen=pageno++; +// for(int i=18;i<22;i++){ +// header[i]=(byte)pagen; +// pagen>>>=8; +// } +// } +// +// /* zero for computation; filled in later */ +// header[22]=0; +// header[23]=0; +// header[24]=0; +// header[25]=0; +// +// /* segment table */ +// header[26]=(byte)vals; +// for(int i=0;i<vals;i++){ +// header[i+27]=(byte)lacing_vals[i]; +// bytes+=header[i+27]&0xff; +//// bytes+=header[i+27]=(lacing_vals[i]&0xff); +// } +// +// /* advance the lacing data and set the body_returned pointer */ +// +// lacing_fill-=vals; +// System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill); +// System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill); +// body_returned=bytes; +// +// /* set pointers in the ogg_page struct */ +// og.header_base=header; +// og.header=0; +// og.header_len=header_fill=vals+27; +// +// og.body_base=body_data; +// og.body=0; +// og.body_len=bytes; +// +// /* calculate the checksum */ +// +// og.checksum(); +// return(1); +// } +// /* not enough data to construct a page and not end of stream */ +// return(0); +//System.out.println("pageout: "+body_returned); + if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */ + body_fill-body_returned> 4096 || /* 'page nominal size' case */ + lacing_fill>=255 || /* 'segment table full' case */ + (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */ + return flush(og); + } + return 0; + } + + public int eof(){ + return e_o_s; + } + + public int reset(){ + body_fill=0; + body_returned=0; + + lacing_fill=0; + lacing_packet=0; + lacing_returned=0; + + header_fill=0; + + e_o_s=0; + b_o_s=0; + pageno=-1; + packetno=0; + granulepos=0; + return(0); + } +} |