/*
* CVS identifier:
*
* $Id: EBCOTRateAllocator.java,v 1.97 2002/05/22 14:59:44 grosbois Exp $
*
* Class: EBCOTRateAllocator
*
* Description: Generic interface for post-compression
* rate allocator.
*
*
*
* COPYRIGHT:
*
* This software module was originally developed by Raphaël Grosbois and
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
* Centre France S.A) in the course of development of the JPEG2000
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
* software module is an implementation of a part of the JPEG 2000
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
* Partners) agree not to assert against ISO/IEC and users of the JPEG
* 2000 Standard (Users) any of their rights under the copyright, not
* including other intellectual property rights, for this software module
* with respect to the usage by ISO/IEC and Users of this software module
* or modifications thereof for use in hardware or software products
* claiming conformance to the JPEG 2000 Standard. Those intending to use
* this software module in hardware or software products are advised that
* their use may infringe existing patents. The original developers of
* this software module, JJ2000 Partners and ISO/IEC assume no liability
* for use of this software module or modifications thereof. No license
* or right to this software module is granted for non JPEG 2000 Standard
* conforming products. JJ2000 Partners have full right to use this
* software module for his/her own purpose, assign or donate this
* software module to any third party and to inhibit third parties from
* using this software module for non JPEG 2000 Standard conforming
* products. This copyright notice must be included in all copies or
* derivative works of this software module.
*
* Copyright (c) 1999/2000 JJ2000 Partners.
* */
using System;
using CSJ2K.j2k.codestream.writer;
using CSJ2K.j2k.wavelet.analysis;
using CSJ2K.j2k.entropy.encoder;
using CSJ2K.j2k.codestream;
using CSJ2K.j2k.entropy;
using CSJ2K.j2k.encoder;
using CSJ2K.j2k.image;
using CSJ2K.j2k.util;
namespace CSJ2K.j2k.entropy.encoder
{
/// This implements the EBCOT post compression rate allocation algorithm. This
/// algorithm finds the most suitable truncation points for the set of
/// code-blocks, for each layer target bitrate. It works by first collecting
/// the rate distortion info from all code-blocks, in all tiles and all
/// components, and then running the rate-allocation on the whole image at
/// once, for each layer.
///
/// This implementation also provides some timing features. They can be
/// enabled by setting the 'DO_TIMING' constant of this class to true and
/// recompiling. The timing uses the 'System.currentTimeMillis()' Java API
/// call, which returns wall clock time, not the actual CPU time used. The
/// timing results will be printed on the message output. Since the times
/// reported are wall clock times and not CPU usage times they can not be added
/// to find the total used time (i.e. some time might be counted in several
/// places). When timing is disabled ('DO_TIMING' is false) there is no penalty
/// if the compiler performs some basic optimizations. Even if not the penalty
/// should be negligeable.
///
///
///
///
///
///
///
///
///
public class EBCOTRateAllocator:PostCompRateAllocator
{
/// Whether to collect timing information or not: false. Used as a compile
/// time directive.
///
#if DO_TIMING
/// The wall time for the initialization.
//private long initTime;
/// The wall time for the building of layers.
//private long buildTime;
/// The wall time for the writing of layers.
//private long writeTime;
#endif
/// 5D Array containing all the coded code-blocks:
///
///
/// - 1st index: tile index
/// - 2nd index: component index
/// - 3rd index: resolution level index
/// - 4th index: subband index
/// - 5th index: code-block index
///
///
///
private CBlkRateDistStats[][][][][] cblks;
/// 6D Array containing the indices of the truncation points. It actually
/// contains the index of the element in CBlkRateDistStats.truncIdxs that
/// gives the real truncation point index.
///
///
/// - 1st index: tile index
/// - 2nd index: layer index
/// - 3rd index: component index
/// - 4th index: resolution level index
/// - 5th index: subband index
/// - 6th index: code-block index
///
///
///
private int[][][][][][] truncIdxs;
/// Number of precincts in each resolution level:
///
///
/// - 1st dim: tile index.
/// - 2nd dim: component index.
/// - 3nd dim: resolution level index.
///
///
///
private Coord[][][] numPrec;
/// Array containing the layers information.
private EBCOTLayer[] layers;
/// The log of 2, natural base
//UPGRADE_NOTE: Final was removed from the declaration of 'LOG2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private static readonly double LOG2 = System.Math.Log(2);
/// The normalization offset for the R-D summary table
private const int RD_SUMMARY_OFF = 24;
/// The size of the summary table
private const int RD_SUMMARY_SIZE = 64;
/// The relative precision for float data. This is the relative tolerance
/// up to which the layer slope thresholds are calculated.
///
private const float FLOAT_REL_PRECISION = 1e-4f;
/// The precision for float data type, in an absolute sense. Two float
/// numbers are considered "equal" if they are within this precision.
///
private const float FLOAT_ABS_PRECISION = 1e-10f;
/// Minimum average size of a packet. If layer has less bytes than the
/// this constant multiplied by number of packets in the layer, then the
/// layer is skipped.
///
private const int MIN_AVG_PACKET_SZ = 32;
/// The R-D summary information collected from the coding of all
/// code-blocks. For each entry it contains the accumulated length of all
/// truncation points that have a slope not less than
/// '2*(k-RD_SUMMARY_OFF)', where 'k' is the entry index.
///
/// Therefore, the length at entry 'k' is the total number of bytes of
/// code-block data that would be obtained if the truncation slope was
/// chosen as '2*(k-RD_SUMMARY_OFF)', without counting the overhead
/// associated with the packet heads.
///
/// This summary is used to estimate the relation of the R-D slope to
/// coded length, and to obtain absolute minimums on the slope given a
/// length.
///
private int[] RDSlopesRates;
/// Packet encoder.
private PktEncoder pktEnc;
/// The layer specifications
private LayersInfo lyrSpec;
/// The maximum slope accross all code-blocks and truncation points.
private float maxSlope;
/// The minimum slope accross all code-blocks and truncation points.
private float minSlope;
/// Initializes the EBCOT rate allocator of entropy coded data. The layout
/// of layers, and their bitrate constraints, is specified by the 'lyrs'
/// parameter.
///
///
/// The source of entropy coded data.
///
///
/// The layers layout specification.
///
///
/// The bit stream writer.
///
///
///
///
///
public EBCOTRateAllocator(CodedCBlkDataSrcEnc src, LayersInfo lyrs, CodestreamWriter writer, EncoderSpecs encSpec, ParameterList pl):base(src, lyrs.TotNumLayers, writer, encSpec)
{
int minsbi, maxsbi;
int i;
SubbandAn sb, sb2;
Coord ncblks = null;
// If we do timing create necessary structures
#if DO_TIMING
// If we are timing make sure that 'finalize' gets called.
//UPGRADE_ISSUE: Method 'java.lang.System.runFinalizersOnExit' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangSystem'"
// CONVERSION PROBLEM?
//System_Renamed.runFinalizersOnExit(true);
// The System.runFinalizersOnExit() method is deprecated in Java
// 1.2 since it can cause a deadlock in some cases. However, here
// we use it only for profiling purposes and is disabled in
// production code.
initTime = 0L;
buildTime = 0L;
writeTime = 0L;
#endif
// Save the layer specs
lyrSpec = lyrs;
//Initialize the size of the RD slope rates array
RDSlopesRates = new int[RD_SUMMARY_SIZE];
//Get number of tiles, components
int nt = src.getNumTiles();
int nc = NumComps;
//Allocate the coded code-blocks and truncation points indexes arrays
cblks = new CBlkRateDistStats[nt][][][][];
for (int i2 = 0; i2 < nt; i2++)
{
cblks[i2] = new CBlkRateDistStats[nc][][][];
}
truncIdxs = new int[nt][][][][][];
for (int i3 = 0; i3 < nt; i3++)
{
truncIdxs[i3] = new int[num_Layers][][][][];
for (int i4 = 0; i4 < num_Layers; i4++)
{
truncIdxs[i3][i4] = new int[nc][][][];
}
}
int cblkPerSubband; // Number of code-blocks per subband
int mrl; // Number of resolution levels
int l; // layer index
int s; //subband index
// Used to compute the maximum number of precincts for each resolution
// level
int tx0, ty0, tx1, ty1; // Current tile position in the reference grid
int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of
// the image component
int trx0, try0, trx1, try1; // Current tile position in the reduced
// resolution image domain
int xrsiz, yrsiz; // Component sub-sampling factors
Coord tileI = null;
Coord nTiles = null;
int xsiz, ysiz, x0siz, y0siz;
int xt0siz, yt0siz;
int xtsiz, ytsiz;
int cb0x = src.CbULX;
int cb0y = src.CbULY;
src.setTile(0, 0);
for (int t = 0; t < nt; t++)
{
// Loop on tiles
nTiles = src.getNumTiles(nTiles);
tileI = src.getTile(tileI);
x0siz = ImgULX;
y0siz = ImgULY;
xsiz = x0siz + ImgWidth;
ysiz = y0siz + ImgHeight;
xt0siz = src.TilePartULX;
yt0siz = src.TilePartULY;
xtsiz = src.NomTileWidth;
ytsiz = src.NomTileHeight;
// Tile's coordinates on the reference grid
tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz;
ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz;
tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz;
ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz;
for (int c = 0; c < nc; c++)
{
// loop on components
//Get the number of resolution levels
sb = src.getAnSubbandTree(t, c);
mrl = sb.resLvl + 1;
// Initialize maximum number of precincts per resolution array
if (numPrec == null)
{
Coord[][][] tmpArray = new Coord[nt][][];
for (int i5 = 0; i5 < nt; i5++)
{
tmpArray[i5] = new Coord[nc][];
}
numPrec = tmpArray;
}
if (numPrec[t][c] == null)
{
numPrec[t][c] = new Coord[mrl];
}
// Subsampling factors
xrsiz = src.getCompSubsX(c);
yrsiz = src.getCompSubsY(c);
// Tile's coordinates in the image component domain
//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'"
tcx0 = (int) System.Math.Ceiling(tx0 / (double) (xrsiz));
//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'"
tcy0 = (int) System.Math.Ceiling(ty0 / (double) (yrsiz));
//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'"
tcx1 = (int) System.Math.Ceiling(tx1 / (double) (xrsiz));
//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'"
tcy1 = (int) System.Math.Ceiling(ty1 / (double) (yrsiz));
cblks[t][c] = new CBlkRateDistStats[mrl][][];
for (l = 0; l < num_Layers; l++)
{
truncIdxs[t][l][c] = new int[mrl][][];
}
for (int r = 0; r < mrl; r++)
{
// loop on resolution levels
// Tile's coordinates in the reduced resolution image
// domain
//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'"
trx0 = (int) System.Math.Ceiling(tcx0 / (double) (1 << (mrl - 1 - r)));
//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'"
try0 = (int) System.Math.Ceiling(tcy0 / (double) (1 << (mrl - 1 - r)));
//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'"
trx1 = (int) System.Math.Ceiling(tcx1 / (double) (1 << (mrl - 1 - r)));
//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'"
try1 = (int) System.Math.Ceiling(tcy1 / (double) (1 << (mrl - 1 - r)));
// Calculate the maximum number of precincts for each
// resolution level taking into account tile specific
// options.
double twoppx = (double) encSpec.pss.getPPX(t, c, r);
double twoppy = (double) encSpec.pss.getPPY(t, c, r);
numPrec[t][c][r] = new Coord();
if (trx1 > trx0)
{
//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'"
numPrec[t][c][r].x = (int) System.Math.Ceiling((trx1 - cb0x) / twoppx) - (int) System.Math.Floor((trx0 - cb0x) / twoppx);
}
else
{
numPrec[t][c][r].x = 0;
}
if (try1 > try0)
{
//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'"
numPrec[t][c][r].y = (int) System.Math.Ceiling((try1 - cb0y) / twoppy) - (int) System.Math.Floor((try0 - cb0y) / (double) twoppy);
}
else
{
numPrec[t][c][r].y = 0;
}
minsbi = (r == 0)?0:1;
maxsbi = (r == 0)?1:4;
cblks[t][c][r] = new CBlkRateDistStats[maxsbi][];
for (l = 0; l < num_Layers; l++)
{
truncIdxs[t][l][c][r] = new int[maxsbi][];
}
for (s = minsbi; s < maxsbi; s++)
{
// loop on subbands
//Get the number of blocks in the current subband
sb2 = (SubbandAn) sb.getSubbandByIdx(r, s);
ncblks = sb2.numCb;
cblkPerSubband = ncblks.x * ncblks.y;
cblks[t][c][r][s] = new CBlkRateDistStats[cblkPerSubband];
for (l = 0; l < num_Layers; l++)
{
truncIdxs[t][l][c][r][s] = new int[cblkPerSubband];
for (i = 0; i < cblkPerSubband; i++)
{
truncIdxs[t][l][c][r][s][i] = - 1;
}
}
} // End loop on subbands
} // End lopp on resolution levels
} // End loop on components
if (t != nt - 1)
{
src.nextTile();
}
} // End loop on tiles
//Initialize the packet encoder
pktEnc = new PktEncoder(src, encSpec, numPrec, pl);
// The layers array has to be initialized after the constructor since
// it is needed that the bit stream header has been entirely written
}
#if DO_TIMING
/// Prints the timing information, if collected, and calls 'finalize' on
/// the super class.
///
///
~EBCOTRateAllocator()
{
System.Text.StringBuilder sb;
sb = new System.Text.StringBuilder("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(CSJ2K.j2k.util.MsgLogger_Fields.INFO, sb.ToString());
//UPGRADE_NOTE: Call to 'super.finalize()' was removed. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1124'"
}
#endif
/// Runs the rate allocation algorithm and writes the data to the bit
/// stream writer object provided to the constructor.
///
///
public override void runAndWrite()
{
//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 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.ApplicationException("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.ApplicationException("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
}
/// 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.
///
/// For each code-block, the valid slopes are computed and converted
/// into the mantissa-exponent representation.
///
///
private void getAllCodeBlocks()
{
int numComps, numTiles; // numBytes removed
int c, r, t, s, sidx, k;
//int slope;
SubbandAn subb;
CBlkRateDistStats ccb = null;
Coord ncblks = null;
int last_sidx;
float fslope;
#if DO_TIMING
long stime = 0L;
#endif
maxSlope = 0f;
minSlope = System.Single.MaxValue;
//Get the number of components and tiles
numComps = src.NumComps;
numTiles = src.getNumTiles();
SubbandAn root, sb;
int cblkToEncode = 0;
int nEncCblk = 0;
ProgressWatch pw = FacilityManager.ProgressWatch;
//Get all coded code-blocks Goto first tile
src.setTile(0, 0);
for (t = 0; t < numTiles; t++)
{
//loop on tiles
nEncCblk = 0;
cblkToEncode = 0;
for (c = 0; c < numComps; c++)
{
root = src.getAnSubbandTree(t, c);
for (r = 0; r <= root.resLvl; r++)
{
if (r == 0)
{
sb = (SubbandAn) root.getSubbandByIdx(0, 0);
if (sb != null)
cblkToEncode += sb.numCb.x * sb.numCb.y;
}
else
{
sb = (SubbandAn) root.getSubbandByIdx(r, 1);
if (sb != null)
cblkToEncode += sb.numCb.x * sb.numCb.y;
sb = (SubbandAn) root.getSubbandByIdx(r, 2);
if (sb != null)
cblkToEncode += sb.numCb.x * sb.numCb.y;
sb = (SubbandAn) root.getSubbandByIdx(r, 3);
if (sb != null)
cblkToEncode += sb.numCb.x * sb.numCb.y;
}
}
}
if (pw != null)
{
pw.initProgressWatch(0, cblkToEncode, "Encoding tile " + t + "...");
}
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.DateTime.Now.Ticks - 621355968000000000) / 10000;
#endif
if (pw != null)
{
nEncCblk++;
pw.updateProgressWatch(nEncCblk, null);
}
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 = subb.numCb;
// 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.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
#endif
}
}
if (pw != null)
{
pw.terminateProgressWatch();
}
//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()
{
int nPrec = 0;
int maxBytes, actualBytes;
float rdThreshold;
SubbandAn sb;
//float threshold;
BitOutputBuffer hBuff = null;
byte[] bBuff = null;
int[] tileLengths; // Length of each tile
int tmp;
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
int nc = src.NumComps;
int nt = src.getNumTiles();
int mrl;
#if DO_TIMING
long stime = 0L;
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
#endif
// Start with the maximum slope
rdThreshold = maxSlope;
tileLengths = new int[nt];
actualBytes = 0;
// +------------------------------+
// | First we build the layers |
// +------------------------------+
// Bitstream is simulated to know tile length
for (int l = 0; l < num_Layers; l++)
{
//loop on layers
maxBytes = layers[l].maxBytes;
if (layers[l].optimize)
{
rdThreshold = optimizeBitstreamLayer(l, rdThreshold, maxBytes, actualBytes);
}
else
{
if (l <= 0 || l >= num_Layers - 1)
{
throw new System.ArgumentException("The first and the" + " last layer " + "thresholds" + " must be optimized");
}
rdThreshold = estimateLayerThreshold(maxBytes, layers[l - 1]);
}
for (int t = 0; t < nt; t++)
{
//loop on tiles
if (l == 0)
{
// Tile header
headEnc.reset();
headEnc.encodeTilePartHeader(0, t);
tileLengths[t] += headEnc.Length;
}
for (int c = 0; c < nc; c++)
{
//loop on components
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper());
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper());
// Go to LL band
sb = src.getAnSubbandTree(t, c);
mrl = sb.resLvl + 1;
while (sb.subb_LL != null)
{
sb = sb.subb_LL;
}
for (int r = 0; r < mrl; r++)
{
// loop on resolution levels
nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
for (int p = 0; p < nPrec; p++)
{
// loop on precincts
findTruncIndices(l, c, r, t, sb, rdThreshold, p);
hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p);
if (pktEnc.PacketWritable)
{
tmp = bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed);
tmp += bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen);
actualBytes += tmp;
tileLengths[t] += tmp;
}
} // End loop on precincts
sb = sb.parentband;
} // End loop on resolution levels
} // End loop on components
} // end loop on tiles
layers[l].rdThreshold = rdThreshold;
layers[l].actualBytes = actualBytes;
} // end loop on layers
#if DO_TIMING
buildTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
#endif
// +--------------------------------------------------+
// | Write tiles according to their Progression order |
// +--------------------------------------------------+
// Reset the packet encoder before writing all packets
pktEnc.reset();
Progression[] prog; // Progression(s) in each tile
int cs, ce, rs, re, lye;
int[] mrlc = new int[nc];
for (int t = 0; t < nt; t++)
{
//loop on tiles
//int[][] lysA; // layer index start for each component and
// resolution level
int[][] lys = new int[nc][];
for (int c = 0; c < nc; c++)
{
mrlc[c] = src.getAnSubbandTree(t, c).resLvl;
lys[c] = new int[mrlc[c] + 1];
}
// Tile header
headEnc.reset();
headEnc.encodeTilePartHeader(tileLengths[t], t);
bsWriter.commitBitstreamHeader(headEnc);
prog = (Progression[]) encSpec.pocs.getTileDef(t);
for (int prg = 0; prg < prog.Length; prg++)
{
// Loop on progression
lye = prog[prg].lye;
cs = prog[prg].cs;
ce = prog[prg].ce;
rs = prog[prg].rs;
re = prog[prg].re;
switch (prog[prg].type)
{
case CSJ2K.j2k.codestream.ProgressionType.RES_LY_COMP_POS_PROG:
writeResLyCompPos(t, rs, re, cs, ce, lys, lye);
break;
case CSJ2K.j2k.codestream.ProgressionType.LY_RES_COMP_POS_PROG:
writeLyResCompPos(t, rs, re, cs, ce, lys, lye);
break;
case CSJ2K.j2k.codestream.ProgressionType.POS_COMP_RES_LY_PROG:
writePosCompResLy(t, rs, re, cs, ce, lys, lye);
break;
case CSJ2K.j2k.codestream.ProgressionType.COMP_POS_RES_LY_PROG:
writeCompPosResLy(t, rs, re, cs, ce, lys, lye);
break;
case CSJ2K.j2k.codestream.ProgressionType.RES_POS_COMP_LY_PROG:
writeResPosCompLy(t, rs, re, cs, ce, lys, lye);
break;
default:
throw new System.ApplicationException("Unsupported bit stream progression type");
} // switch on progression
// Update next first layer index
for (int c = cs; c < ce; c++)
for (int r = rs; r < re; r++)
{
if (r > mrlc[c])
continue;
lys[c][r] = lye;
}
} // End loop on progression
} // End loop on tiles
#if DO_TIMING
writeTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
#endif
}
/// Write a piece of bit stream according to the
/// RES_LY_COMP_POS_PROG progression mode and between given bounds
///
///
/// Tile index.
///
///
/// First resolution level index.
///
///
/// Last resolution level index.
///
///
/// First component index.
///
///
/// Last component index.
///
///
/// First layer index for each component and resolution.
///
///
/// Index of the last layer.
///
///
public virtual void writeResLyCompPos(int t, int rs, int re, int cs, int ce, int[][] lys, int lye)
{
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
int nc = src.NumComps;
int[] mrl = new int[nc];
SubbandAn sb;
float threshold;
BitOutputBuffer hBuff = null;
byte[] bBuff = null;
int nPrec = 0;
// Max number of resolution levels in the tile
int maxResLvl = 0;
for (int c = 0; c < nc; c++)
{
mrl[c] = src.getAnSubbandTree(t, c).resLvl;
if (mrl[c] > maxResLvl)
maxResLvl = mrl[c];
}
int minlys; // minimum layer start index of each component
for (int r = rs; r < re; r++)
{
//loop on resolution levels
if (r > maxResLvl)
continue;
minlys = 100000;
for (int c = cs; c < ce; c++)
{
if (r < lys[c].Length && lys[c][r] < minlys)
{
minlys = lys[c][r];
}
}
for (int l = minlys; l < lye; l++)
{
//loop on layers
for (int c = cs; c < ce; c++)
{
//loop on components
if (r >= lys[c].Length)
continue;
if (l < lys[c][r])
continue;
// If no more decomposition levels for this component
if (r > mrl[c])
continue;
nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
for (int p = 0; p < nPrec; p++)
{
// loop on precincts
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on");
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on");
sb = src.getAnSubbandTree(t, c);
for (int i = mrl[c]; i > r; i--)
{
sb = sb.subb_LL;
}
threshold = layers[l].rdThreshold;
findTruncIndices(l, c, r, t, sb, threshold, p);
hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p);
if (pktEnc.PacketWritable)
{
bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed);
bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen);
}
} // End loop on precincts
} // End loop on components
} // End loop on layers
} // End loop on resolution levels
}
/// Write a piece of bit stream according to the
/// LY_RES_COMP_POS_PROG progression mode and between given bounds
///
///
/// Tile index.
///
///
/// First resolution level index.
///
///
/// Last resolution level index.
///
///
/// First component index.
///
///
/// Last component index.
///
///
/// First layer index for each component and resolution.
///
///
/// Index of the last layer.
///
///
public virtual void writeLyResCompPos(int t, int rs, int re, int cs, int ce, int[][] lys, int lye)
{
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
int nc = src.NumComps;
int mrl;
SubbandAn sb;
float threshold;
BitOutputBuffer hBuff = null;
byte[] bBuff = null;
int nPrec = 0;
int minlys = 100000; // minimum layer start index of each component
for (int c = cs; c < ce; c++)
{
for (int r = 0; r < lys.Length; r++)
{
if (lys[c] != null && r < lys[c].Length && lys[c][r] < minlys)
{
minlys = lys[c][r];
}
}
}
for (int l = minlys; l < lye; l++)
{
// loop on layers
for (int r = rs; r < re; r++)
{
// loop on resolution level
for (int c = cs; c < ce; c++)
{
// loop on components
mrl = src.getAnSubbandTree(t, c).resLvl;
if (r > mrl)
continue;
if (r >= lys[c].Length)
continue;
if (l < lys[c][r])
continue;
nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
for (int p = 0; p < nPrec; p++)
{
// loop on precincts
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on");
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on");
sb = src.getAnSubbandTree(t, c);
for (int i = mrl; i > r; i--)
{
sb = sb.subb_LL;
}
threshold = layers[l].rdThreshold;
findTruncIndices(l, c, r, t, sb, threshold, p);
hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p);
if (pktEnc.PacketWritable)
{
bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed);
bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen);
}
} // end loop on precincts
} // end loop on components
} // end loop on resolution levels
} // end loop on layers
}
/// Write a piece of bit stream according to the
/// COMP_POS_RES_LY_PROG progression mode and between given bounds
///
///
/// Tile index.
///
///
/// First resolution level index.
///
///
/// Last resolution level index.
///
///
/// First component index.
///
///
/// Last component index.
///
///
/// First layer index for each component and resolution.
///
///
/// Index of the last layer.
///
///
public virtual void writePosCompResLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye)
{
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
int nc = src.NumComps;
int mrl;
SubbandAn sb;
float threshold;
BitOutputBuffer hBuff = null;
byte[] bBuff = null;
// Computes current tile offset in the reference grid
Coord nTiles = src.getNumTiles(null);
Coord tileI = src.getTile(null);
int x0siz = src.ImgULX;
int y0siz = src.ImgULY;
int xsiz = x0siz + src.ImgWidth;
int ysiz = y0siz + src.ImgHeight;
int xt0siz = src.TilePartULX;
int yt0siz = src.TilePartULY;
int xtsiz = src.NomTileWidth;
int ytsiz = src.NomTileHeight;
int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz;
int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz;
int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz;
int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz;
// Get precinct information (number,distance between two consecutive
// precincts in the reference grid) in each component and resolution
// level
PrecInfo prec; // temporary variable
int p; // Current precinct index
int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
int nPrec = 0; // Total number of found precincts
int[][] nextPrec = new int[ce][]; // Next precinct index in each
// component and resolution level
int minlys = 100000; // minimum layer start index of each component
int minx = tx1; // Horiz. offset of the second precinct in the
// reference grid
int miny = ty1; // Vert. offset of the second precinct in the
// reference grid.
int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
for (int c = cs; c < ce; c++)
{
mrl = src.getAnSubbandTree(t, c).resLvl;
nextPrec[c] = new int[mrl + 1];
for (int r = rs; r < re; r++)
{
if (r > mrl)
continue;
if (r < lys[c].Length && lys[c][r] < minlys)
{
minlys = lys[c][r];
}
p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
for (; p >= 0; p--)
{
prec = pktEnc.getPrecInfo(t, c, r, p);
if (prec.rgulx != tx0)
{
if (prec.rgulx < minx)
minx = prec.rgulx;
if (prec.rgulx > maxx)
maxx = prec.rgulx;
}
if (prec.rguly != ty0)
{
if (prec.rguly < miny)
miny = prec.rguly;
if (prec.rguly > maxy)
maxy = prec.rguly;
}
if (nPrec == 0)
{
gcd_x = prec.rgw;
gcd_y = prec.rgh;
}
else
{
gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
}
nPrec++;
} // precincts
} // resolution levels
} // components
if (nPrec == 0)
{
throw new System.ApplicationException("Image cannot have no precinct");
}
int pyend = (maxy - miny) / gcd_y + 1;
int pxend = (maxx - minx) / gcd_x + 1;
int y = ty0;
int x = tx0;
for (int py = 0; py <= pyend; py++)
{
// Vertical precincts
for (int px = 0; px <= pxend; px++)
{
// Horiz. precincts
for (int c = cs; c < ce; c++)
{
// Components
mrl = src.getAnSubbandTree(t, c).resLvl;
for (int r = rs; r < re; r++)
{
// Resolution levels
if (r > mrl)
continue;
if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y)
{
continue;
}
prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]);
if ((prec.rgulx != x) || (prec.rguly != y))
{
continue;
}
for (int l = minlys; l < lye; l++)
{
// Layers
if (r >= lys[c].Length)
continue;
if (l < lys[c][r])
continue;
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on");
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on");
sb = src.getAnSubbandTree(t, c);
for (int i = mrl; i > r; i--)
{
sb = sb.subb_LL;
}
threshold = layers[l].rdThreshold;
findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]);
hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]);
if (pktEnc.PacketWritable)
{
bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed);
bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen);
}
} // layers
nextPrec[c][r]++;
} // Resolution levels
} // Components
if (px != pxend)
{
x = minx + px * gcd_x;
}
else
{
x = tx0;
}
} // Horizontal precincts
if (py != pyend)
{
y = miny + py * gcd_y;
}
else
{
y = ty0;
}
} // Vertical precincts
// Check that all precincts have been written
for (int c = cs; c < ce; c++)
{
mrl = src.getAnSubbandTree(t, c).resLvl;
for (int r = rs; r < re; r++)
{
if (r > mrl)
continue;
if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1)
{
throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + ".");
}
}
}
}
/// Write a piece of bit stream according to the
/// COMP_POS_RES_LY_PROG progression mode and between given bounds
///
///
/// Tile index.
///
///
/// First resolution level index.
///
///
/// Last resolution level index.
///
///
/// First component index.
///
///
/// Last component index.
///
///
/// First layer index for each component and resolution.
///
///
/// Index of the last layer.
///
///
public virtual void writeCompPosResLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye)
{
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
int nc = src.NumComps;
int mrl;
SubbandAn sb;
float threshold;
BitOutputBuffer hBuff = null;
byte[] bBuff = null;
// Computes current tile offset in the reference grid
Coord nTiles = src.getNumTiles(null);
Coord tileI = src.getTile(null);
int x0siz = src.ImgULX;
int y0siz = src.ImgULY;
int xsiz = x0siz + src.ImgWidth;
int ysiz = y0siz + src.ImgHeight;
int xt0siz = src.TilePartULX;
int yt0siz = src.TilePartULY;
int xtsiz = src.NomTileWidth;
int ytsiz = src.NomTileHeight;
int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz;
int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz;
int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz;
int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz;
// Get precinct information (number,distance between two consecutive
// precincts in the reference grid) in each component and resolution
// level
PrecInfo prec; // temporary variable
int p; // Current precinct index
int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
int nPrec = 0; // Total number of found precincts
int[][] nextPrec = new int[ce][]; // Next precinct index in each
// component and resolution level
int minlys = 100000; // minimum layer start index of each component
int minx = tx1; // Horiz. offset of the second precinct in the
// reference grid
int miny = ty1; // Vert. offset of the second precinct in the
// reference grid.
int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
for (int c = cs; c < ce; c++)
{
mrl = src.getAnSubbandTree(t, c).resLvl;
for (int r = rs; r < re; r++)
{
if (r > mrl)
continue;
nextPrec[c] = new int[mrl + 1];
if (r < lys[c].Length && lys[c][r] < minlys)
{
minlys = lys[c][r];
}
p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
for (; p >= 0; p--)
{
prec = pktEnc.getPrecInfo(t, c, r, p);
if (prec.rgulx != tx0)
{
if (prec.rgulx < minx)
minx = prec.rgulx;
if (prec.rgulx > maxx)
maxx = prec.rgulx;
}
if (prec.rguly != ty0)
{
if (prec.rguly < miny)
miny = prec.rguly;
if (prec.rguly > maxy)
maxy = prec.rguly;
}
if (nPrec == 0)
{
gcd_x = prec.rgw;
gcd_y = prec.rgh;
}
else
{
gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
}
nPrec++;
} // precincts
} // resolution levels
} // components
if (nPrec == 0)
{
throw new System.ApplicationException("Image cannot have no precinct");
}
int pyend = (maxy - miny) / gcd_y + 1;
int pxend = (maxx - minx) / gcd_x + 1;
int y;
int x;
for (int c = cs; c < ce; c++)
{
// Loop on components
y = ty0;
x = tx0;
mrl = src.getAnSubbandTree(t, c).resLvl;
for (int py = 0; py <= pyend; py++)
{
// Vertical precincts
for (int px = 0; px <= pxend; px++)
{
// Horiz. precincts
for (int r = rs; r < re; r++)
{
// Resolution levels
if (r > mrl)
continue;
if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y)
{
continue;
}
prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]);
if ((prec.rgulx != x) || (prec.rguly != y))
{
continue;
}
for (int l = minlys; l < lye; l++)
{
// Layers
if (r >= lys[c].Length)
continue;
if (l < lys[c][r])
continue;
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on");
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on");
sb = src.getAnSubbandTree(t, c);
for (int i = mrl; i > r; i--)
{
sb = sb.subb_LL;
}
threshold = layers[l].rdThreshold;
findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]);
hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]);
if (pktEnc.PacketWritable)
{
bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed);
bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen);
}
} // Layers
nextPrec[c][r]++;
} // Resolution levels
if (px != pxend)
{
x = minx + px * gcd_x;
}
else
{
x = tx0;
}
} // Horizontal precincts
if (py != pyend)
{
y = miny + py * gcd_y;
}
else
{
y = ty0;
}
} // Vertical precincts
} // components
// Check that all precincts have been written
for (int c = cs; c < ce; c++)
{
mrl = src.getAnSubbandTree(t, c).resLvl;
for (int r = rs; r < re; r++)
{
if (r > mrl)
continue;
if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1)
{
throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + ".");
}
}
}
}
/// Write a piece of bit stream according to the
/// RES_POS_COMP_LY_PROG progression mode and between given bounds
///
///
/// Tile index.
///
///
/// First resolution level index.
///
///
/// Last resolution level index.
///
///
/// First component index.
///
///
/// Last component index.
///
///
/// First layer index for each component and resolution.
///
///
/// Last layer index.
///
///
public virtual void writeResPosCompLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye)
{
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
int nc = src.NumComps;
int mrl;
SubbandAn sb;
float threshold;
BitOutputBuffer hBuff = null;
byte[] bBuff = null;
// Computes current tile offset in the reference grid
Coord nTiles = src.getNumTiles(null);
Coord tileI = src.getTile(null);
int x0siz = src.ImgULX;
int y0siz = src.ImgULY;
int xsiz = x0siz + src.ImgWidth;
int ysiz = y0siz + src.ImgHeight;
int xt0siz = src.TilePartULX;
int yt0siz = src.TilePartULY;
int xtsiz = src.NomTileWidth;
int ytsiz = src.NomTileHeight;
int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz;
int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz;
int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz;
int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz;
// Get precinct information (number,distance between two consecutive
// precincts in the reference grid) in each component and resolution
// level
PrecInfo prec; // temporary variable
int p; // Current precinct index
int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
int nPrec = 0; // Total number of found precincts
int[][] nextPrec = new int[ce][]; // Next precinct index in each
// component and resolution level
int minlys = 100000; // minimum layer start index of each component
int minx = tx1; // Horiz. offset of the second precinct in the
// reference grid
int miny = ty1; // Vert. offset of the second precinct in the
// reference grid.
int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
for (int c = cs; c < ce; c++)
{
mrl = src.getAnSubbandTree(t, c).resLvl;
nextPrec[c] = new int[mrl + 1];
for (int r = rs; r < re; r++)
{
if (r > mrl)
continue;
if (r < lys[c].Length && lys[c][r] < minlys)
{
minlys = lys[c][r];
}
p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
for (; p >= 0; p--)
{
prec = pktEnc.getPrecInfo(t, c, r, p);
if (prec.rgulx != tx0)
{
if (prec.rgulx < minx)
minx = prec.rgulx;
if (prec.rgulx > maxx)
maxx = prec.rgulx;
}
if (prec.rguly != ty0)
{
if (prec.rguly < miny)
miny = prec.rguly;
if (prec.rguly > maxy)
maxy = prec.rguly;
}
if (nPrec == 0)
{
gcd_x = prec.rgw;
gcd_y = prec.rgh;
}
else
{
gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
}
nPrec++;
} // precincts
} // resolution levels
} // components
if (nPrec == 0)
{
throw new System.ApplicationException("Image cannot have no precinct");
}
int pyend = (maxy - miny) / gcd_y + 1;
int pxend = (maxx - minx) / gcd_x + 1;
int x, y;
for (int r = rs; r < re; r++)
{
// Resolution levels
y = ty0;
x = tx0;
for (int py = 0; py <= pyend; py++)
{
// Vertical precincts
for (int px = 0; px <= pxend; px++)
{
// Horiz. precincts
for (int c = cs; c < ce; c++)
{
// Components
mrl = src.getAnSubbandTree(t, c).resLvl;
if (r > mrl)
continue;
if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y)
{
continue;
}
prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]);
if ((prec.rgulx != x) || (prec.rguly != y))
{
continue;
}
for (int l = minlys; l < lye; l++)
{
if (r >= lys[c].Length)
continue;
if (l < lys[c][r])
continue;
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on");
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on");
sb = src.getAnSubbandTree(t, c);
for (int i = mrl; i > r; i--)
{
sb = sb.subb_LL;
}
threshold = layers[l].rdThreshold;
findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]);
hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]);
if (pktEnc.PacketWritable)
{
bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed);
bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen);
}
} // layers
nextPrec[c][r]++;
} // Components
if (px != pxend)
{
x = minx + px * gcd_x;
}
else
{
x = tx0;
}
} // Horizontal precincts
if (py != pyend)
{
y = miny + py * gcd_y;
}
else
{
y = ty0;
}
} // Vertical precincts
} // Resolution levels
// Check that all precincts have been written
for (int c = cs; c < ce; c++)
{
mrl = src.getAnSubbandTree(t, c).resLvl;
for (int r = rs; r < re; r++)
{
if (r > mrl)
continue;
if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1)
{
throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + ".");
}
}
}
}
/// This function implements the rate-distortion optimization algorithm.
/// It saves the state of any previously generated bit-stream layers and
/// then simulate the formation of a new layer in the bit stream as often
/// as necessary to find the smallest rate-distortion threshold such that
/// the total number of bytes required to represent the layer does not
/// exceed `maxBytes' minus `prevBytes'. It then restores the state of any
/// previously generated bit-stream layers and returns the threshold.
///
///
/// The index of the current layer
///
///
/// The maximum admissible slope value. Normally the threshold
/// slope of the previous layer.
///
///
/// The maximum number of bytes that can be written. It
/// includes the length of the current layer bistream length and all the
/// previous layers bit streams.
///
///
/// The number of bytes of all the previous layers.
///
///
/// The value of the slope threshold.
///
///
private float optimizeBitstreamLayer(int layerIdx, float fmaxt, int maxBytes, int prevBytes)
{
int nt; // The total number of tiles
int nc; // The total number of components
int numLvls; // The total number of resolution levels
int actualBytes; // Actual number of bytes for a layer
float fmint; // Minimum of the current threshold interval
float ft; // Current threshold
SubbandAn sb; // Current subband
BitOutputBuffer hBuff; // The packet head buffer
byte[] bBuff; // The packet body buffer
int sidx; // The index in the summary table
bool sopUsed; // Should SOP markers be used ?
bool ephUsed; // Should EPH markers be used ?
//int precinctIdx; // Precinct index for current packet
int nPrec; // Number of precincts in the current resolution level
// Save the packet encoder state
pktEnc.save();
nt = src.getNumTiles();
nc = src.NumComps;
hBuff = null;
bBuff = null;
// Estimate the minimum slope to start with from the summary
// information in 'RDSlopesRates'. This is a real minimum since it
// does not include the packet head overhead, which is always
// non-zero.
// Look for the summary entry that gives 'maxBytes' or more data
for (sidx = RD_SUMMARY_SIZE - 1; sidx > 0; sidx--)
{
if (RDSlopesRates[sidx] >= maxBytes)
{
break;
}
}
// Get the corresponding minimum slope
fmint = getSlopeFromSIndex(sidx);
// Ensure that it is smaller the maximum slope
if (fmint >= fmaxt)
{
sidx--;
fmint = getSlopeFromSIndex(sidx);
}
// If we are using the last entry of the summary, then that
// corresponds to all the data, Thus, set the minimum slope to 0.
if (sidx <= 0)
fmint = 0;
// We look for the best threshold 'ft', which is the lowest threshold
// that generates no more than 'maxBytes' code bytes.
// The search is done iteratively using a binary split algorithm. We
// start with 'fmaxt' as the maximum possible threshold, and 'fmint'
// as the minimum threshold. The threshold 'ft' is calculated as the
// middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint'
// bounds are moved according to the number of bytes obtained from a
// simulation, where 'ft' is used as the threshold.
// We stop whenever the interval is sufficiently small, and thus
// enough precision is achieved.
// Initialize threshold as the middle point of the interval.
ft = (fmaxt + fmint) / 2f;
// If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so
// close that the average is 'fmint', due to rounding. Force it to
// 'fmaxt' instead, since 'fmint' is normally an exclusive lower
// bound.
if (ft <= fmint)
ft = fmaxt;
do
{
// Get the number of bytes used by this layer, if 'ft' is the
// threshold, by simulation.
actualBytes = prevBytes;
src.setTile(0, 0);
for (int t = 0; t < nt; t++)
{
for (int c = 0; c < nc; c++)
{
// set boolean sopUsed here (SOP markers)
sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper());
// set boolean ephUsed here (EPH markers)
ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper());
// Get LL subband
sb = (SubbandAn) src.getAnSubbandTree(t, c);
numLvls = sb.resLvl + 1;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
//loop on resolution levels
for (int r = 0; r < numLvls; r++)
{
nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
for (int p = 0; p < nPrec; p++)
{
findTruncIndices(layerIdx, c, r, t, sb, ft, p);
hBuff = pktEnc.encodePacket(layerIdx + 1, c, r, t, cblks[t][c][r], truncIdxs[t][layerIdx][c][r], hBuff, bBuff, p);
if (pktEnc.PacketWritable)
{
bBuff = pktEnc.LastBodyBuf;
actualBytes += bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed);
actualBytes += bsWriter.writePacketBody(bBuff, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen);
}
} // end loop on precincts
sb = sb.parentband;
} // End loop on resolution levels
} // End loop on components
} // End loop on tiles
// Move the interval bounds according to simulation result
if (actualBytes > maxBytes)
{
// 'ft' is too low and generates too many bytes, make it the
// new minimum.
fmint = ft;
}
else
{
// 'ft' is too high and does not generate as many bytes as we
// are allowed too, make it the new maximum.
fmaxt = ft;
}
// Update 'ft' for the new iteration as the middle point of the
// new interval.
ft = (fmaxt + fmint) / 2f;
// If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are
// so close that the average is 'fmint', due to rounding. Force it
// to 'fmaxt' instead, since 'fmint' is normally an exclusive
// lower bound.
if (ft <= fmint)
ft = fmaxt;
// Restore previous packet encoder state
pktEnc.restore();
// We continue to iterate, until the threshold reaches the upper
// limit of the interval, within a FLOAT_REL_PRECISION relative
// tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is
// the sign that the interval is sufficiently small.
}
while (ft < fmaxt * (1f - FLOAT_REL_PRECISION) && ft < (fmaxt - FLOAT_ABS_PRECISION));
// If we have a threshold which is close to 0, set it to 0 so that
// everything is taken into the layer. This is to avoid not sending
// some least significant bit-planes in the lossless case. We use the
// FLOAT_ABS_PRECISION value as a measure of "close" to 0.
if (ft <= FLOAT_ABS_PRECISION)
{
ft = 0f;
}
else
{
// Otherwise make the threshold 'fmaxt', just to be sure that we
// will not send more bytes than allowed.
ft = fmaxt;
}
return ft;
}
/// This function attempts to estimate a rate-distortion slope threshold
/// which will achieve a target number of code bytes close the
/// `targetBytes' value.
///
///
/// The target number of bytes for the current layer
///
///
/// The previous layer information.
///
///
/// The value of the slope threshold for the estimated layer
///
///
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;
}
/// This function finds the new truncation points indices for a packet. It
/// does so by including the data from the code-blocks in the component,
/// resolution level and tile, associated with a R-D slope which is larger
/// than or equal to 'fthresh'.
///
///
/// The index of the current layer
///
///
/// The index of the current component
///
///
/// The index of the current resolution level
///
///
/// The index of the current tile
///
///
/// The LL subband in the resolution level lvlIdx, which is
/// parent of all the subbands in the packet. Except for resolution level 0
/// this subband is always a node.
///
///
/// The value of the rate-distortion threshold
///
///
private void findTruncIndices(int layerIdx, int compIdx, int lvlIdx, int tileIdx, SubbandAn subb, float fthresh, int precinctIdx)
{
int minsbi, maxsbi, b, n; // bIdx removed
//Coord ncblks = null;
SubbandAn sb;
CBlkRateDistStats cur_cblk;
PrecInfo prec = pktEnc.getPrecInfo(tileIdx, compIdx, lvlIdx, precinctIdx);
Coord cbCoord;
sb = subb;
while (sb.subb_HH != null)
{
sb = sb.subb_HH;
}
minsbi = (lvlIdx == 0)?0:1;
maxsbi = (lvlIdx == 0)?1:4;
int yend, xend;
sb = (SubbandAn) subb.getSubbandByIdx(lvlIdx, minsbi);
for (int s = minsbi; s < maxsbi; s++)
{
//loop on subbands
yend = (prec.cblk[s] != null)?prec.cblk[s].Length:0;
for (int y = 0; y < yend; y++)
{
xend = (prec.cblk[s][y] != null)?prec.cblk[s][y].Length:0;
for (int x = 0; x < xend; x++)
{
cbCoord = prec.cblk[s][y][x].idx;
b = cbCoord.x + cbCoord.y * sb.numCb.x;
//Get the current code-block
cur_cblk = cblks[tileIdx][compIdx][lvlIdx][s][b];
for (n = 0; n < cur_cblk.nVldTrunc; n++)
{
if (cur_cblk.truncSlopes[n] < fthresh)
{
break;
}
else
{
continue;
}
}
// Store the index in the code-block truncIdxs that gives
// the real truncation index.
truncIdxs[tileIdx][layerIdx][compIdx][lvlIdx][s][b] = n - 1;
} // End loop on horizontal code-blocks
} // End loop on vertical code-blocks
sb = (SubbandAn) sb.nextSubband();
} // End loop on subbands
}
/// Returns the index of a slope for the summary table, limiting to the
/// admissible values. The index is calculated as RD_SUMMARY_OFF plus the
/// maximum exponent, base 2, that yields a value not larger than the slope
/// itself.
///
/// If the value to return is lower than 0, 0 is returned. If it is
/// larger than the maximum table index, then the maximum is returned.
///
///
/// The slope value
///
///
/// The index for the summary table of the slope.
///
///
private static int getLimitedSIndexFromSlope(float slope)
{
int idx;
//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'"
idx = (int) System.Math.Floor(System.Math.Log(slope) / LOG2) + RD_SUMMARY_OFF;
if (idx < 0)
{
return 0;
}
else if (idx >= RD_SUMMARY_SIZE)
{
return RD_SUMMARY_SIZE - 1;
}
else
{
return idx;
}
}
/// Returns the minimum slope value associated with a summary table
/// index. This minimum slope is just 2^(index-RD_SUMMARY_OFF).
///
///
/// The summary index value.
///
///
/// The minimum slope value associated with a summary table index.
///
///
private static float getSlopeFromSIndex(int index)
{
//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'"
return (float) System.Math.Pow(2, (index - RD_SUMMARY_OFF));
}
}
}