/* * Copyright (C) 2011 in-somnia * * This file is part of JAAD. * * JAAD is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * JAAD 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 Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see <http://www.gnu.org/licenses/>. */ 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.BitStream; import net.sourceforge.jaad.aac.syntax.ICSInfo; import net.sourceforge.jaad.aac.syntax.ICStream; /** * Reversable variable length coding * Decodes scalefactors if error resilience is used. */ public class RVLC implements RVLCTables { private static final int ESCAPE_FLAG = 7; public void decode(BitStream 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 = null; //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(BitStream 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 = null; //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(BitStream 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(BitStream 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]; } }