package net.sourceforge.jaad.aac.syntax; import static java.lang.System.arraycopy; import net.sourceforge.jaad.aac.AACException; /** * This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed * under the Public Domain license. Code changes provided by the JCodec project * are distributed under FreeBSD license. * * @author in-somnia */ public class BitStream implements IBitStream { private static final int WORD_BITS = 32; private static final int WORD_BYTES = 4; private static final int BYTE_MASK = 0xff; public static BitStream createBitStream(byte[] data) { BitStream bs = new BitStream(); bs.setData(data); return bs; } private byte[] buffer; private int pos; //offset in the buffer array private int cache; //current 4 bytes, that are read from the buffer protected int bitsCached; //remaining bits in current cache protected int position; //number of total bits read public BitStream() { } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#destroy() */ @Override public void destroy() { reset(); buffer = null; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#setData(byte[]) */ @Override public final void setData(byte[] data) { //make the buffer size an integer number of words final int size = WORD_BYTES*((data.length+WORD_BYTES-1)/WORD_BYTES); //only reallocate if needed if(buffer==null||buffer.length!=size) buffer = new byte[size]; arraycopy(data, 0, buffer, 0, data.length); reset(); } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#byteAlign() */ @Override public void byteAlign() throws AACException { final int toFlush = bitsCached&7; if(toFlush>0) skipBits(toFlush); } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#reset() */ @Override public final void reset() { pos = 0; bitsCached = 0; cache = 0; position = 0; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#getPosition() */ @Override public int getPosition() { return position; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#getBitsLeft() */ @Override public int getBitsLeft() { return buffer != null ? 8*(buffer.length-pos)+bitsCached : 0; } /** * Reads the next four bytes. * @param peek if true, the stream pointer will not be increased */ protected int readCache(boolean peek) throws AACException { int i; if(pos>buffer.length-WORD_BYTES) throw AACException.endOfStream(); else i = ((buffer[pos]&BYTE_MASK)<<24) |((buffer[pos+1]&BYTE_MASK)<<16) |((buffer[pos+2]&BYTE_MASK)<<8) |(buffer[pos+3]&BYTE_MASK); if(!peek) pos += WORD_BYTES; return i; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#readBits(int) */ @Override public int readBits(int n) throws AACException { int result; if(bitsCached>=n) { bitsCached -= n; result = (cache>>bitsCached)&maskBits(n); position += n; } else { position += n; final int c = cache&maskBits(bitsCached); final int left = n-bitsCached; cache = readCache(false); bitsCached = WORD_BITS-left; result = ((cache>>bitsCached)&maskBits(left))|(c<<left); } return result; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#readBit() */ @Override public int readBit() throws AACException { int i; if(bitsCached>0) { bitsCached--; i = (cache>>(bitsCached))&1; position++; } else { cache = readCache(false); bitsCached = WORD_BITS-1; position++; i = (cache>>bitsCached)&1; } return i; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#readBool() */ @Override public boolean readBool() throws AACException { return (readBit()&0x1)!=0; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#peekBits(int) */ @Override public int peekBits(int n) throws AACException { int ret; if(bitsCached>=n) { ret = (cache>>(bitsCached-n))&maskBits(n); } else { //old cache final int c = cache&maskBits(bitsCached); n -= bitsCached; //read next & combine ret = ((readCache(true)>>WORD_BITS-n)&maskBits(n))|(c<<n); } return ret; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#peekBit() */ @Override public int peekBit() throws AACException { int ret; if(bitsCached>0) { ret = (cache>>(bitsCached-1))&1; } else { final int word = readCache(true); ret = (word>>WORD_BITS-1)&1; } return ret; } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#skipBits(int) */ @Override public void skipBits(int n) throws AACException { position += n; if(n<=bitsCached) { bitsCached -= n; } else { n -= bitsCached; while(n>=WORD_BITS) { n -= WORD_BITS; readCache(false); } if(n>0) { cache = readCache(false); bitsCached = WORD_BITS-n; } else { cache = 0; bitsCached = 0; } } } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#skipBit() */ @Override public void skipBit() throws AACException { position++; if(bitsCached>0) { bitsCached--; } else { cache = readCache(false); bitsCached = WORD_BITS-1; } } /* (non-Javadoc) * @see net.sourceforge.jaad.aac.syntax.IBitStream#maskBits(int) */ @Override public int maskBits(int n) { int i; if(n==32) i = -1; else i = (1<<n)-1; return i; } }