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 + -
显示快捷键?