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