package net.sourceforge.jaad.aac.error; import net.sourceforge.jaad.aac.AACException; import net.sourceforge.jaad.aac.huffman.HCB; import net.sourceforge.jaad.aac.syntax.IBitStream; import net.sourceforge.jaad.aac.syntax.ICSInfo; import net.sourceforge.jaad.aac.syntax.ICStream; /** * 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. * * Reversable variable length coding * Decodes scalefactors if error resilience is used. * * @author in-somnia */ public class RVLC implements RVLCTables { private static final int ESCAPE_FLAG = 7; public void decode(IBitStream _in, ICStream ics, int[][] scaleFactors) throws AACException { final int bits = (ics.getInfo().isEightShortFrame()) ? 11 : 9; final boolean sfConcealment = _in.readBool(); final int revGlobalGain = _in.readBits(8); final int rvlcSFLen = _in.readBits(bits); final ICSInfo info = ics.getInfo(); final int windowGroupCount = info.getWindowGroupCount(); final int maxSFB = info.getMaxSFB(); final int[][] sfbCB = {{}}; //ics.getSectionData().getSfbCB(); int sf = ics.getGlobalGain(); int intensityPosition = 0; int noiseEnergy = sf-90-256; boolean intensityUsed = false, noiseUsed = false; int sfb; for(int g = 0; g<windowGroupCount; g++) { for(sfb = 0; sfb<maxSFB; sfb++) { switch(sfbCB[g][sfb]) { case HCB.ZERO_HCB: scaleFactors[g][sfb] = 0; break; case HCB.INTENSITY_HCB: case HCB.INTENSITY_HCB2: if(!intensityUsed) intensityUsed = true; intensityPosition += decodeHuffman(_in); scaleFactors[g][sfb] = intensityPosition; break; case HCB.NOISE_HCB: if(noiseUsed) { noiseEnergy += decodeHuffman(_in); scaleFactors[g][sfb] = noiseEnergy; } else { noiseUsed = true; noiseEnergy = decodeHuffman(_in); } break; default: sf += decodeHuffman(_in); scaleFactors[g][sfb] = sf; break; } } } int lastIntensityPosition = 0; if(intensityUsed) lastIntensityPosition = decodeHuffman(_in); noiseUsed = false; if(_in.readBool()) decodeEscapes(_in, ics, scaleFactors); } private void decodeEscapes(IBitStream _in, ICStream ics, int[][] scaleFactors) throws AACException { final ICSInfo info = ics.getInfo(); final int windowGroupCount = info.getWindowGroupCount(); final int maxSFB = info.getMaxSFB(); final int[][] sfbCB = {{}}; //ics.getSectionData().getSfbCB(); final int escapesLen = _in.readBits(8); boolean noiseUsed = false; int sfb, val; for(int g = 0; g<windowGroupCount; g++) { for(sfb = 0; sfb<maxSFB; sfb++) { if(sfbCB[g][sfb]==HCB.NOISE_HCB&&!noiseUsed) noiseUsed = true; else if(Math.abs(sfbCB[g][sfb])==ESCAPE_FLAG) { val = decodeHuffmanEscape(_in); if(sfbCB[g][sfb]==-ESCAPE_FLAG) scaleFactors[g][sfb] -= val; else scaleFactors[g][sfb] += val; } } } } private int decodeHuffman(IBitStream _in) throws AACException { int off = 0; int i = RVLC_BOOK[off][1]; int cw = _in.readBits(i); int j; while((cw!=RVLC_BOOK[off][2])&&(i<10)) { off++; j = RVLC_BOOK[off][1]-i; i += j; cw <<= j; cw |= _in.readBits(j); } return RVLC_BOOK[off][0]; } private int decodeHuffmanEscape(IBitStream _in) throws AACException { int off = 0; int i = ESCAPE_BOOK[off][1]; int cw = _in.readBits(i); int j; while((cw!=ESCAPE_BOOK[off][2])&&(i<21)) { off++; j = ESCAPE_BOOK[off][1]-i; i += j; cw <<= j; cw |= _in.readBits(j); } return ESCAPE_BOOK[off][0]; } }