summaryrefslogtreecommitdiff
path: root/songdbj/com/jcraft/jogg/StreamState.java
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/com/jcraft/jogg/StreamState.java')
-rw-r--r--songdbj/com/jcraft/jogg/StreamState.java657
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);
+ }
+}