ebcotrateallocator.java
来自「jpeg2000算法实现」· Java 代码 · 共 1,831 行 · 第 1/5 页
JAVA
1,831 行
/** * Prints the timing information, if collected, and calls 'finalize' on * the super class. * */ public void finalize() throws Throwable { if (DO_TIMING) { StringBuffer sb; sb = new StringBuffer("EBCOTRateAllocator wall clock times:\n"); sb.append(" initialization: "); sb.append(initTime); sb.append(" ms\n"); sb.append(" layer building: "); sb.append(buildTime); sb.append(" ms\n"); sb.append(" final writing: "); sb.append(writeTime); sb.append(" ms"); FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,sb.toString()); } super.finalize(); } /** * Runs the rate allocation algorithm and writes the data to the bit * stream writer object provided to the constructor. * */ public void runAndWrite() throws IOException { //Now, run the rate allocation buildAndWriteLayers(); } /** * Initializes the layers array. This must be called after the main header * has been entirely written or simulated, so as to take its overhead into * account. This method will get all the code-blocks and then initialize * the target bitrates for each layer, according to the specifications. * */ public void initialize() throws IOException{ int n,i,l; int ho; // The header overhead (in bytes) float np;// The number of pixels divided by the number of bits per byte double ls; // Step for log-scale double basebytes; int lastbytes,newbytes,nextbytes; int loopnlyrs; int minlsz; // The minimum allowable number of bytes in a layer int totenclength; int maxpkt; int numTiles = src.getNumTiles(); int numComps = src.getNumComps(); int numLvls; int avgPktLen; long stime = 0L; // Start by getting all the code-blocks, we need this in order to have // an idea of the total encoded bitrate. getAllCodeBlocks(); if (DO_TIMING) stime = System.currentTimeMillis(); // Now get the total encoded length totenclength = RDSlopesRates[0]; // all the encoded data // Make a rough estimation of the packet head overhead, as 2 bytes per // packet in average (plus EPH / SOP) , and add that to the total // encoded length for( int t=0 ; t<numTiles ; t++ ){ avgPktLen = 2; // Add SOP length if set if (((String)encSpec.sops.getTileDef(t)).equalsIgnoreCase("on")) { avgPktLen += Markers.SOP_LENGTH; } // Add EPH length if set if (((String)encSpec.ephs.getTileDef(t)).equalsIgnoreCase("on")) { avgPktLen += Markers.EPH_LENGTH; } for( int c=0 ; c<numComps ; c++ ){ numLvls = src.getSubbandTree(t,c).resLvl+1; if( !src.precinctPartitionUsed(c,t) ) { // Precinct partition is not used so there is only // one packet per resolution level/layer totenclength += numLayers*avgPktLen*numLvls; } else { // Precinct partition is used so for each // component/tile/resolution level, we get the maximum // number of packets for ( int rl=0 ; rl<numLvls ; rl++ ) { maxpkt = maxNumPrec[t][c][rl].x * maxNumPrec[t][c][rl].y; totenclength += numLayers*avgPktLen*maxpkt; } } } // End loop on components } // End loop on tiles // If any layer specifies more than 'totenclength' as its target // length then 'totenclength' is used. This is to prevent that // estimated layers get excessively large target lengths due to an // excessively large target bitrate. At the end the last layer is set // to the target length corresponding to the overall target // bitrate. Thus, 'totenclength' can not limit the total amount of // encoded data, as intended. ho = headEnc.getLength(); np = src.getImgWidth()*src.getImgHeight()/8f; // SOT marker must be taken into account for(int t=0; t<numTiles; t++){ headEnc.reset(); headEnc.encodeTilePartHeader(0,t); ho += headEnc.getLength(); } layers = new EBCOTLayer[numLayers]; for (n = numLayers-1; n>=0; n--) { layers[n] = new EBCOTLayer(); } minlsz = 0; // To keep compiler happy for( int t=0 ; t<numTiles ; t++ ){ for( int c=0 ; c<numComps ; c++ ){ numLvls = src.getSubbandTree(t,c).resLvl+1; if ( !src.precinctPartitionUsed(c,t) ) { // Precinct partition is not used minlsz += MIN_AVG_PACKET_SZ*numLvls; } else { // Precinct partition is used for ( int rl=0 ; rl<numLvls ; rl++ ) { maxpkt = maxNumPrec[t][c][rl].x * maxNumPrec[t][c][rl].y; minlsz += MIN_AVG_PACKET_SZ*maxpkt; } } } // End loop on components } // End loop on tiles // Initialize layers n = 0; i = 0; lastbytes = 0; while (n < numLayers-1) { // At an optimized layer basebytes = Math.floor(lyrSpec.getTargetBitrate(i)*np); if (i < lyrSpec.getNOptPoints()-1) { nextbytes = (int) (lyrSpec.getTargetBitrate(i+1)*np); // Limit target length to 'totenclength' if (nextbytes > totenclength) nextbytes = totenclength; } else { nextbytes = 1; } loopnlyrs = lyrSpec.getExtraLayers(i)+1; ls = Math.exp(Math.log((double)nextbytes/basebytes)/loopnlyrs); layers[n].optimize = true; for (l = 0; l < loopnlyrs; l++) { newbytes = (int)basebytes - lastbytes - ho; if (newbytes < minlsz) { // Skip layer (too small) basebytes *= ls; numLayers--; continue; } lastbytes = (int)basebytes - ho; layers[n].maxBytes = lastbytes; basebytes *= ls; n++; } i++; // Goto next optimization point } // Ensure minimum size of last layer (this one determines overall // bitrate) n = numLayers-2; nextbytes = (int) (lyrSpec.getTotBitrate()*np) - ho; newbytes = nextbytes - ((n>=0) ? layers[n].maxBytes : 0); while (newbytes < minlsz) { if (numLayers == 1) { if (newbytes <= 0) { throw new IllegalArgumentException("Overall target bitrate too "+ "low, given the current "+ "bit stream header overhead"); } break; } // Delete last layer numLayers--; n--; newbytes = nextbytes - ((n>=0) ? layers[n].maxBytes : 0); } // Set last layer to the overall target bitrate n++; layers[n].maxBytes = nextbytes; layers[n].optimize = true; // Re-initialize progression order changes if needed Default values Progression[] prog1,prog2; prog1 = (Progression[])encSpec.ps.getDefault(); int nValidProg = prog1.length; for(int prg=0; prg<prog1.length;prg++){ if(prog1[prg].lye>numLayers){ prog1[prg].lye = numLayers; nValidProg=prg+1; break; } } if(nValidProg==0) throw new Error("Unable to initialize rate allocator"); if(nValidProg!=prog1.length){ prog2 = new Progression[nValidProg]; for(int prg=0; prg<nValidProg; prg++) prog2[prg] = prog1[prg]; encSpec.ps.setDefault(prog2); } // Tile specific values for(int t=0; t<numTiles; t++){ if(encSpec.ps.isTileSpecified(t)){ prog1 = (Progression[])encSpec.ps.getTileDef(t); nValidProg = prog1.length; for(int prg=0; prg<prog1.length;prg++){ if(prog1[prg].lye>numLayers){ prog1[prg].lye = numLayers; nValidProg=prg+1; break; } } if(nValidProg==0) throw new Error("Unable to initialize rate allocator"); if(nValidProg!=prog1.length){ prog2 = new Progression[nValidProg]; for(int prg=0; prg<nValidProg; prg++) prog2[prg] = prog1[prg]; encSpec.ps.setTileDef(t,prog2); } } } // End loop on tiles if (DO_TIMING) initTime += System.currentTimeMillis()-stime; } /** * This method gets all the coded code-blocks from the EBCOT entropy coder * for every component and every tile. Each coded code-block is stored in * a 5D array according to the component, the resolution level, the tile, * the subband it belongs and its position in the subband. * * <P> For each code-block, the valid slopes are computed and converted * into the mantissa-exponent representation. * */ private void getAllCodeBlocks() { int numComps, numTiles, numBytes; int c, r, t, s, sidx, k; int slope; SubbandAn subb; CBlkRateDistStats ccb = null; Coord ncblks = null; int last_sidx; float fslope; long stime = 0L; maxSlope = 0f; minSlope = Float.MAX_VALUE; //Get the number of components and tiles numComps = src.getNumComps(); numTiles = src.getNumTiles(); //Get all coded code-blocks Goto first tile src.setTile(0,0); for (t=0; t<numTiles; t++) { //loop on tiles for (c=0; c<numComps; c++) { //loop on components //Get next coded code-block coordinates while ( (ccb = src.getNextCodeBlock(c,ccb)) != null) { if (DO_TIMING) stime = System.currentTimeMillis(); subb = ccb.sb; //Get the coded code-block resolution level index r = subb.resLvl; //Get the coded code-block subband index s = subb.sbandIdx; //Get the number of blocks in the current subband ncblks = src.getNumCodeBlocks(subb,ncblks); // Add code-block contribution to summary R-D table // RDSlopesRates last_sidx = -1; for (k=ccb.nVldTrunc-1; k>=0; k--) { fslope = ccb.truncSlopes[k]; if (fslope > maxSlope) maxSlope = fslope; if (fslope < minSlope) minSlope = fslope; sidx = getLimitedSIndexFromSlope(fslope); for (; sidx > last_sidx; sidx--) { RDSlopesRates[sidx] += ccb.truncRates[ccb.truncIdxs[k]]; } last_sidx = getLimitedSIndexFromSlope(fslope); } //Fills code-blocks array cblks[t][c][r][s][(ccb.m*ncblks.x)+ccb.n] = ccb; ccb = null; if(DO_TIMING) initTime += System.currentTimeMillis()-stime; } } //Goto next tile if(t<numTiles-1) //not at last tile src.nextTile(); } } /** * This method builds all the bit stream layers and then writes them to * the output bit stream. Firstly it builds all the layers by computing * the threshold according to the layer target bit-rate, and then it * writes the layer bit streams according to the progressive type. * */ private void buildAndWriteLayers() throws IOException { int maxBytes, actualBytes, packetBytes; float rdThreshold; int numLvls; SubbandAn sb; float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; int tIndx[][][]; int[] tileLengths; // Length of each tile int tmp; boolean sopUsed; // Should SOP markers be used ? boolean ephUsed; // Should EPH markers be used ? int numComps = src.getNumComps(); int numTiles = src.getNumTiles(); int[][] mrl = packetEnc.getMRL(); int x0, y0, x1, y1; int x_inc, y_inc, x_inc_rl, y_inc_rl; int x0_rl, y0_rl, precinctIdx; Coord xys[],xyInc; long stime = 0L; if (DO_TIMING) stime = System.currentTimeMillis(); // Start with the maximum slope rdThreshold = maxSlope; tileLengths = new int[numTiles]; actualBytes = 0; // +------------------------------+ // | First we build the layers | // +------------------------------+ // Bitstream is simulated to know tile length
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?