/* * 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.Constants; import net.sourceforge.jaad.aac.syntax.ICSInfo; import net.sourceforge.jaad.aac.syntax.ICStream; /** * Huffman Codeword Reordering * Decodes spectral data for ICStreams if error resilience is used for * section data. */ //TODO: needs decodeSpectralDataER() in BitStream public class HCR implements Constants { private static class Codeword { int cb, decoded, sp_offset; BitsBuffer bits; private void fill(int sp, int cb) { sp_offset = sp; this.cb = cb; decoded = 0; bits = new BitsBuffer(); } } private static final int NUM_CB = 6; private static final int NUM_CB_ER = 22; private static final int MAX_CB = 32; private static final int VCB11_FIRST = 16; private static final int VCB11_LAST = 31; private static final int[] PRE_SORT_CB_STD = {11, 9, 7, 5, 3, 1}; private static final int[] PRE_SORT_CB_ER = {11, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 9, 7, 5, 3, 1}; private static final int[] MAX_CW_LEN = {0, 11, 9, 20, 16, 13, 11, 14, 12, 17, 14, 49, 0, 0, 0, 0, 14, 17, 21, 21, 25, 25, 29, 29, 29, 29, 33, 33, 33, 37, 37, 41}; //bit-twiddling helpers private static final int[] S = {1, 2, 4, 8, 16}; private static final int[] B = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF}; //32 bit rewind and reverse private static int rewindReverse(int v, int len) { v = ((v>>S[0])&B[0])|((v<<S[0])&~B[0]); v = ((v>>S[1])&B[1])|((v<<S[1])&~B[1]); v = ((v>>S[2])&B[2])|((v<<S[2])&~B[2]); v = ((v>>S[3])&B[3])|((v<<S[3])&~B[3]); v = ((v>>S[4])&B[4])|((v<<S[4])&~B[4]); //shift off low bits v >>= (32-len); return v; } //64 bit rewind and reverse static int[] rewindReverse64(int hi, int lo, int len) { int[] i = new int[2]; if(len<=32) { i[0] = 0; i[1] = rewindReverse(lo, len); } else { lo = ((lo>>S[0])&B[0])|((lo<<S[0])&~B[0]); hi = ((hi>>S[0])&B[0])|((hi<<S[0])&~B[0]); lo = ((lo>>S[1])&B[1])|((lo<<S[1])&~B[1]); hi = ((hi>>S[1])&B[1])|((hi<<S[1])&~B[1]); lo = ((lo>>S[2])&B[2])|((lo<<S[2])&~B[2]); hi = ((hi>>S[2])&B[2])|((hi<<S[2])&~B[2]); lo = ((lo>>S[3])&B[3])|((lo<<S[3])&~B[3]); hi = ((hi>>S[3])&B[3])|((hi<<S[3])&~B[3]); lo = ((lo>>S[4])&B[4])|((lo<<S[4])&~B[4]); hi = ((hi>>S[4])&B[4])|((hi<<S[4])&~B[4]); //shift off low bits i[1] = (hi>>(64-len))|(lo<<(len-32)); i[1] = lo>>(64-len); } return i; } private static boolean isGoodCB(int cb, int sectCB) { boolean b = false; if((sectCB>HCB.ZERO_HCB&§CB<=HCB.ESCAPE_HCB)||(sectCB>=VCB11_FIRST&§CB<=VCB11_LAST)) { if(cb<HCB.ESCAPE_HCB) b = ((sectCB==cb)||(sectCB==cb+1)); else b = (sectCB==cb); } return b; } //sectionDataResilience = hDecoder->aacSectionDataResilienceFlag public static void decodeReorderedSpectralData(ICStream ics, BitStream in, short[] spectralData, boolean sectionDataResilience) throws AACException { final ICSInfo info = ics.getInfo(); final int windowGroupCount = info.getWindowGroupCount(); final int maxSFB = info.getMaxSFB(); final int[] swbOffsets = info.getSWBOffsets(); final int swbOffsetMax = info.getSWBOffsetMax(); //TODO: //final SectionData sectData = ics.getSectionData(); final int[][] sectStart = null; //sectData.getSectStart(); final int[][] sectEnd = null; //sectData.getSectEnd(); final int[] numSec = null; //sectData.getNumSec(); final int[][] sectCB = null; //sectData.getSectCB(); final int[][] sectSFBOffsets = null; //info.getSectSFBOffsets(); //check parameter final int spDataLen = ics.getReorderedSpectralDataLength(); if(spDataLen==0) return; final int longestLen = ics.getLongestCodewordLength(); if(longestLen==0||longestLen>=spDataLen) throw new AACException("length of longest HCR codeword out of range"); //create spOffsets final int[] spOffsets = new int[8]; final int shortFrameLen = spectralData.length/8; spOffsets[0] = 0; int g; for(g = 1; g<windowGroupCount; g++) { spOffsets[g] = spOffsets[g-1]+shortFrameLen*info.getWindowGroupLength(g-1); } final Codeword[] codeword = new Codeword[512]; final BitsBuffer[] segment = new BitsBuffer[512]; int lastCB; int[] preSortCB; if(sectionDataResilience) { preSortCB = PRE_SORT_CB_ER; lastCB = NUM_CB_ER; } else { preSortCB = PRE_SORT_CB_STD; lastCB = NUM_CB; } int PCWs_done = 0; int segmentsCount = 0; int numberOfCodewords = 0; int bitsread = 0; int sfb, w_idx, i, thisCB, thisSectCB, cws; //step 1: decode PCW's (set 0), and stuff data in easier-to-use format for(int sortloop = 0; sortloop<lastCB; sortloop++) { //select codebook to process this pass thisCB = preSortCB[sortloop]; for(sfb = 0; sfb<maxSFB; sfb++) { for(w_idx = 0; 4*w_idx<(Math.min(swbOffsets[sfb+1], swbOffsetMax)-swbOffsets[sfb]); w_idx++) { for(g = 0; g<windowGroupCount; g++) { for(i = 0; i<numSec[g]; i++) { if((sectStart[g][i]<=sfb)&&(sectEnd[g][i]>sfb)) { /* check whether codebook used here is the one we want to process */ thisSectCB = sectCB[g][i]; if(isGoodCB(thisCB, thisSectCB)) { //precalculation int sect_sfb_size = sectSFBOffsets[g][sfb+1]-sectSFBOffsets[g][sfb]; int inc = (thisSectCB<HCB.FIRST_PAIR_HCB) ? 4 : 2; int group_cws_count = (4*info.getWindowGroupLength(g))/inc; int segwidth = Math.min(MAX_CW_LEN[thisSectCB], longestLen); //read codewords until end of sfb or end of window group for(cws = 0; (cws<group_cws_count)&&((cws+w_idx*group_cws_count)<sect_sfb_size); cws++) { int sp = spOffsets[g]+sectSFBOffsets[g][sfb]+inc*(cws+w_idx*group_cws_count); //read and decode PCW if(PCWs_done==0) { //read in normal segments if(bitsread+segwidth<=spDataLen) { segment[segmentsCount].readSegment(segwidth, in); bitsread += segwidth; //Huffman.decodeSpectralDataER(segment[segmentsCount], thisSectCB, spectralData, sp); //keep leftover bits segment[segmentsCount].rewindReverse(); segmentsCount++; } else { //remaining after last segment if(bitsread<spDataLen) { final int additional_bits = spDataLen-bitsread; segment[segmentsCount].readSegment(additional_bits, in); segment[segmentsCount].len += segment[segmentsCount-1].len; segment[segmentsCount].rewindReverse(); if(segment[segmentsCount-1].len>32) { segment[segmentsCount-1].bufb = segment[segmentsCount].bufb +segment[segmentsCount-1].showBits(segment[segmentsCount-1].len-32); segment[segmentsCount-1].bufa = segment[segmentsCount].bufa +segment[segmentsCount-1].showBits(32); } else { segment[segmentsCount-1].bufa = segment[segmentsCount].bufa +segment[segmentsCount-1].showBits(segment[segmentsCount-1].len); segment[segmentsCount-1].bufb = segment[segmentsCount].bufb; } segment[segmentsCount-1].len += additional_bits; } bitsread = spDataLen; PCWs_done = 1; codeword[0].fill(sp, thisSectCB); } } else { codeword[numberOfCodewords-segmentsCount].fill(sp, thisSectCB); } numberOfCodewords++; } } } } } } } } if(segmentsCount==0) throw new AACException("no segments in HCR"); final int numberOfSets = numberOfCodewords/segmentsCount; //step 2: decode nonPCWs int trial, codewordBase, segmentID, codewordID; for(int set = 1; set<=numberOfSets; set++) { for(trial = 0; trial<segmentsCount; trial++) { for(codewordBase = 0; codewordBase<segmentsCount; codewordBase++) { segmentID = (trial+codewordBase)%segmentsCount; codewordID = codewordBase+set*segmentsCount-segmentsCount; //data up if(codewordID>=numberOfCodewords-segmentsCount) break; if((codeword[codewordID].decoded==0)&&(segment[segmentID].len>0)) { if(codeword[codewordID].bits.len!=0) segment[segmentID].concatBits(codeword[codewordID].bits); int tmplen = segment[segmentID].len; /*int ret = Huffman.decodeSpectralDataER(segment[segmentID], codeword[codewordID].cb, spectralData, codeword[codewordID].sp_offset); if(ret>=0) codeword[codewordID].decoded = 1; else { codeword[codewordID].bits = segment[segmentID]; codeword[codewordID].bits.len = tmplen; }*/ } } } for(i = 0; i<segmentsCount; i++) { segment[i].rewindReverse(); } } } }