/// <summary> 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. /// /// </summary> public override void initialize() { 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.NumComps; int numLvls; int avgPktLen; #if DO_TIMING long stime = 0L; #endif // 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.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // 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 (((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper())) { avgPktLen += CSJ2K.j2k.codestream.Markers.SOP_LENGTH; } // Add EPH length if set if (((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper())) { avgPktLen += CSJ2K.j2k.codestream.Markers.EPH_LENGTH; } for (int c = 0; c < numComps; c++) { numLvls = src.getAnSubbandTree(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 += num_Layers * 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 = numPrec[t][c][rl].x * numPrec[t][c][rl].y; totenclength += num_Layers * 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.Length; np = src.ImgWidth * src.ImgHeight / 8f; // SOT marker must be taken into account for (int t = 0; t < numTiles; t++) { headEnc.reset(); headEnc.encodeTilePartHeader(0, t); ho += headEnc.Length; } layers = new EBCOTLayer[num_Layers]; for (n = num_Layers - 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.getAnSubbandTree(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 = numPrec[t][c][rl].x * numPrec[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 < num_Layers - 1) { // At an optimized layer basebytes = System.Math.Floor(lyrSpec.getTargetBitrate(i) * np); if (i < lyrSpec.NOptPoints - 1) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" 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 = System.Math.Exp(System.Math.Log((double) nextbytes / basebytes) / loopnlyrs); layers[n].optimize = true; for (l = 0; l < loopnlyrs; l++) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" newbytes = (int) basebytes - lastbytes - ho; if (newbytes < minlsz) { // Skip layer (too small) basebytes *= ls; num_Layers--; continue; } //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" 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 = num_Layers - 2; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" nextbytes = (int) (lyrSpec.TotBitrate * np) - ho; newbytes = nextbytes - ((n >= 0)?layers[n].maxBytes:0); while (newbytes < minlsz) { if (num_Layers == 1) { if (newbytes <= 0) { throw new System.ArgumentException("Overall target bitrate too " + "low, given the current " + "bit stream header overhead"); } break; } // Delete last layer num_Layers--; 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 removed prog1 = (Progression[]) encSpec.pocs.getDefault(); int nValidProg = prog1.Length; for (int prg = 0; prg < prog1.Length; prg++) { if (prog1[prg].lye > num_Layers) { prog1[prg].lye = num_Layers; } } if (nValidProg == 0) { throw new System.InvalidOperationException("Unable to initialize rate allocator: No " + "default progression type has been defined."); } // Tile specific values for (int t = 0; t < numTiles; t++) { if (encSpec.pocs.isTileSpecified(t)) { prog1 = (Progression[]) encSpec.pocs.getTileDef(t); nValidProg = prog1.Length; for (int prg = 0; prg < prog1.Length; prg++) { if (prog1[prg].lye > num_Layers) { prog1[prg].lye = num_Layers; } } if (nValidProg == 0) { throw new System.InvalidOperationException("Unable to initialize rate allocator:" + " No default progression type has been " + "defined for tile " + t); } } } // End loop on tiles #if DO_TIMING initTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif }
/// <summary> This function attempts to estimate a rate-distortion slope threshold /// which will achieve a target number of code bytes close the /// `targetBytes' value. /// /// </summary> /// <param name="targetBytes">The target number of bytes for the current layer /// /// </param> /// <param name="lastLayer">The previous layer information. /// /// </param> /// <returns> The value of the slope threshold for the estimated layer /// /// </returns> private float estimateLayerThreshold(int targetBytes, EBCOTLayer lastLayer) { float log_sl1; // The log of the first slope used for interpolation float log_sl2; // The log of the second slope used for interpolation float log_len1; // The log of the first length used for interpolation float log_len2; // The log of the second length used for interpolation float log_isl; // The log of the interpolated slope float log_ilen; // Log of the interpolated length float log_ab; // Log of actual bytes in last layer int sidx; // Index into the summary R-D info array float log_off; // The log of the offset proportion int tlen; // The corrected target layer length float lthresh; // The threshold of the last layer float eth; // The estimated threshold // In order to estimate the threshold we base ourselves in the summary // R-D info in RDSlopesRates. In order to use it we must compensate // for the overhead of the packet heads. The proportion of overhead is // estimated using the last layer simulation results. // NOTE: the model used in this method is that the slope varies // linearly with the log of the rate (i.e. length). // NOTE: the model used in this method is that the distortion is // proprotional to a power of the rate. Thus, the slope is also // proportional to another power of the rate. This translates as the // log of the slope varies linearly with the log of the rate, which is // what we use. // 1) Find the offset of the length predicted from the summary R-D // information, to the actual length by using the last layer. // We ensure that the threshold we use for estimation actually // includes some data. lthresh = lastLayer.rdThreshold; if (lthresh > maxSlope) lthresh = maxSlope; // If the slope of the last layer is too small then we just include // all the rest (not possible to do better). if (lthresh < FLOAT_ABS_PRECISION) return 0f; sidx = getLimitedSIndexFromSlope(lthresh); // If the index is outside of the summary info array use the last two, // or first two, indexes, as appropriate if (sidx >= RD_SUMMARY_SIZE - 1) sidx = RD_SUMMARY_SIZE - 2; // Get the logs of the lengths and the slopes if (RDSlopesRates[sidx + 1] == 0) { // Pathological case, we can not use log of 0. Add // RDSlopesRates[sidx]+1 bytes to the rates (just a crude simple // solution to this rare case) //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len1 = (float) System.Math.Log((RDSlopesRates[sidx] << 1) + 1); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len2 = (float) System.Math.Log(RDSlopesRates[sidx] + 1); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_ab = (float) System.Math.Log(lastLayer.actualBytes + RDSlopesRates[sidx] + 1); } else { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len1 = (float) System.Math.Log(RDSlopesRates[sidx]); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len2 = (float) System.Math.Log(RDSlopesRates[sidx + 1]); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_ab = (float) System.Math.Log(lastLayer.actualBytes); } //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_sl1 = (float) System.Math.Log(getSlopeFromSIndex(sidx)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_sl2 = (float) System.Math.Log(getSlopeFromSIndex(sidx + 1)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_isl = (float) System.Math.Log(lthresh); log_ilen = log_len1 + (log_isl - log_sl1) * (log_len1 - log_len2) / (log_sl1 - log_sl2); log_off = log_ab - log_ilen; // Do not use negative offsets (i.e. offset proportion larger than 1) // since that is probably a sign that our model is off. To be // conservative use an offset of 0 (i.e. offset proportiojn 1). if (log_off < 0) log_off = 0f; // 2) Correct the target layer length by the offset. //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" tlen = (int) (targetBytes / (float) System.Math.Exp(log_off)); // 3) Find, from the summary R-D info, the thresholds that generate // lengths just above and below our corrected target layer length. // Look for the index in the summary info array that gives the largest // length smaller than the target length for (sidx = RD_SUMMARY_SIZE - 1; sidx >= 0; sidx--) { if (RDSlopesRates[sidx] >= tlen) break; } sidx++; // Correct if out of the array if (sidx >= RD_SUMMARY_SIZE) sidx = RD_SUMMARY_SIZE - 1; if (sidx <= 0) sidx = 1; // Get the log of the lengths and the slopes that are just above and // below the target length. if (RDSlopesRates[sidx] == 0) { // Pathological case, we can not use log of 0. Add // RDSlopesRates[sidx-1]+1 bytes to the rates (just a crude simple // solution to this rare case) //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len1 = (float) System.Math.Log(RDSlopesRates[sidx - 1] + 1); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len2 = (float) System.Math.Log((RDSlopesRates[sidx - 1] << 1) + 1); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_ilen = (float) System.Math.Log(tlen + RDSlopesRates[sidx - 1] + 1); } else { // Normal case, we can safely take the logs. //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len1 = (float) System.Math.Log(RDSlopesRates[sidx]); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_len2 = (float) System.Math.Log(RDSlopesRates[sidx - 1]); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_ilen = (float) System.Math.Log(tlen); } //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_sl1 = (float) System.Math.Log(getSlopeFromSIndex(sidx)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" log_sl2 = (float) System.Math.Log(getSlopeFromSIndex(sidx - 1)); // 4) Interpolate the two thresholds to find the target threshold. log_isl = log_sl1 + (log_ilen - log_len1) * (log_sl1 - log_sl2) / (log_len1 - log_len2); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" eth = (float) System.Math.Exp(log_isl); // Correct out of bounds results if (eth > lthresh) eth = lthresh; if (eth < FLOAT_ABS_PRECISION) eth = 0f; // Return the estimated threshold return eth; }