/// <summary> Reads all tiles headers and keep offset of their first
/// packet. Finally it calls the rate allocation method.
///
/// </summary>
/// <param name="hd">HeaderDecoder of the codestream.
///
/// </param>
/// <param name="ehs">The input stream where to read bit-stream.
///
/// </param>
/// <param name="decSpec">The decoder specifications
///
/// </param>
/// <param name="pl">The ParameterList instance created from the
/// command-line arguments.
///
/// </param>
/// <param name="cdstrInfo">Whether or not to print information found in
/// codestream.
///
/// </param>
/// <seealso cref="allocateRate">
///
/// </seealso>
public FileBitstreamReaderAgent(HeaderDecoder hd, RandomAccessIO ehs, DecoderSpecs decSpec, ParameterList pl, bool cdstrInfo, HeaderInfo hi):base(hd, decSpec)
{
this.pl = pl;
this.printInfo = cdstrInfo;
this.hi = hi;
// Check whether quit conditiosn used
usePOCQuit = pl.getBooleanParameter("poc_quit");
// Get decoding rate
bool rateInBytes;
bool parsing = pl.getBooleanParameter("parsing");
try
{
trate = pl.getFloatParameter("rate");
if (trate == - 1)
{
trate = System.Single.MaxValue;
}
}
catch (System.FormatException)
{
throw new System.ApplicationException("Invalid value in 'rate' option: " + pl.getParameter("rate"));
}
catch (System.ArgumentException)
{
throw new System.ApplicationException("'rate' option is missing");
}
try
{
tnbytes = pl.getIntParameter("nbytes");
}
catch (System.FormatException)
{
throw new System.ApplicationException("Invalid value in 'nbytes' option: " + pl.getParameter("nbytes"));
}
catch (System.ArgumentException)
{
throw new System.ApplicationException("'nbytes' option is missing");
}
// Check that '-rate' and '-nbytes' are not used at the same time
ParameterList defaults = pl.DefaultParameterList;
if (tnbytes != defaults.getFloatParameter("nbytes"))
{
rateInBytes = true;
}
else
{
rateInBytes = false;
}
if (rateInBytes)
{
trate = tnbytes * 8f / hd.MaxCompImgWidth / hd.MaxCompImgHeight;
}
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'"
tnbytes = (int) (trate * hd.MaxCompImgWidth * hd.MaxCompImgHeight) / 8;
if (tnbytes < 0) tnbytes = int.MaxValue;
}
isTruncMode = !pl.getBooleanParameter("parsing");
// Check if quit conditions are being used
int ncbQuit;
try
{
ncbQuit = pl.getIntParameter("ncb_quit");
}
catch (System.FormatException)
{
throw new System.ApplicationException("Invalid value in 'ncb_quit' option: " + pl.getParameter("ncb_quit"));
}
catch (System.ArgumentException)
{
throw new System.ApplicationException("'ncb_quit' option is missing");
}
if (ncbQuit != - 1 && !isTruncMode)
{
throw new System.ApplicationException("Cannot use -parsing and -ncb_quit condition at " + "the same time.");
}
try
{
lQuit = pl.getIntParameter("l_quit");
}
catch (System.FormatException)
{
throw new System.ApplicationException("Invalid value in 'l_quit' option: " + pl.getParameter("l_quit"));
}
catch (System.ArgumentException)
{
throw new System.ApplicationException("'l_quit' option is missing");
}
// initializations
in_Renamed = ehs;
pktDec = new PktDecoder(decSpec, hd, ehs, this, isTruncMode, ncbQuit);
tileParts = new int[nt];
totTileLen = new int[nt];
tilePartLen = new int[nt][];
tilePartNum = new int[nt][];
firstPackOff = new int[nt][];
tilePartsRead = new int[nt];
totTileHeadLen = new int[nt];
tilePartHeadLen = new int[nt][];
nBytes = new int[nt];
baknBytes = new int[nt];
hd.nTileParts = new int[nt];
// CONVERSION PROBLEM?
//this.isTruncMode = isTruncMode;
int t = 0, pos, tp = 0, tptot = 0;
// Keeps main header's length, takes file format overhead into account
int cdstreamStart = hd.mainHeadOff; // Codestream offset in the file
mainHeadLen = in_Renamed.Pos - cdstreamStart;
headLen = mainHeadLen;
// If ncb and lbody quit conditions are used, headers are not counted
if (ncbQuit == - 1)
{
anbytes = mainHeadLen;
}
else
{
anbytes = 0;
}
// If cannot even read the first tile-part
if (anbytes > tnbytes)
{
throw new System.ApplicationException("Requested bitrate is too small.");
}
// Read all tile-part headers from all tiles.
int tilePartStart;
bool rateReached = false;
int mdl;
//int numtp = 0;
totAllTileLen = 0;
remainingTileParts = nt; // at least as many tile-parts as tiles
int maxTP = nt; // If maximum 1 tile part per tile specified
try
{
while (remainingTileParts != 0)
{
tilePartStart = in_Renamed.Pos;
// Read tile-part header
try
{
t = readTilePartHeader();
if (isEOCFound)
{
// Some tiles are missing but the
// codestream is OK
break;
}
tp = tilePartsRead[t];
if (isPsotEqualsZero)
{
// Psot may equals zero for the
// last tile-part: it is assumed that this tile-part
// contain all data until EOC
tilePartLen[t][tp] = in_Renamed.length() - 2 - tilePartStart;
}
}
catch (System.IO.EndOfStreamException e)
{
firstPackOff[t][tp] = in_Renamed.length();
throw e;
}
pos = in_Renamed.Pos;
// In truncation mode, if target decoding rate is reached in
// tile-part header, skips the tile-part and stop reading
// unless the ncb and lbody quit condition is in use
if (isTruncMode && ncbQuit == - 1)
{
if ((pos - cdstreamStart) > tnbytes)
{
firstPackOff[t][tp] = in_Renamed.length();
rateReached = true;
break;
}
}
// Set tile part position and header length
firstPackOff[t][tp] = pos;
tilePartHeadLen[t][tp] = (pos - tilePartStart);
// Update length counters
totTileLen[t] += tilePartLen[t][tp];
totTileHeadLen[t] += tilePartHeadLen[t][tp];
totAllTileLen += tilePartLen[t][tp];
if (isTruncMode)
{
if (anbytes + tilePartLen[t][tp] > tnbytes)
{
anbytes += tilePartHeadLen[t][tp];
headLen += tilePartHeadLen[t][tp];
rateReached = true;
nBytes[t] += (tnbytes - anbytes);
break;
}
else
{
anbytes += tilePartHeadLen[t][tp];
headLen += tilePartHeadLen[t][tp];
nBytes[t] += (tilePartLen[t][tp] - tilePartHeadLen[t][tp]);
}
}
else
{
if (anbytes + tilePartHeadLen[t][tp] > tnbytes)
{
break;
}
else
{
anbytes += tilePartHeadLen[t][tp];
headLen += tilePartHeadLen[t][tp];
}
}
// If this is first tile-part, remember header length
if (tptot == 0)
firstTilePartHeadLen = tilePartHeadLen[t][tp];
// Go to the beginning of next tile part
tilePartsRead[t]++;
in_Renamed.seek(tilePartStart + tilePartLen[t][tp]);
remainingTileParts--;
maxTP--;
tptot++;
// If Psot of the current tile-part was equal to zero, it is
// assumed that it contains all data until the EOC marker
if (isPsotEqualsZero)
{
if (remainingTileParts != 0)
{
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Some tile-parts have not " + "been found. The codestream may be corrupted.");
}
break;
}
}
}
catch (System.IO.EndOfStreamException)
{
if (printInfo)
{
}
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Codestream truncated in tile " + t);
// Set specified rate to end of file if valid
int fileLen = in_Renamed.length();
if (fileLen < tnbytes)
{
tnbytes = fileLen;
trate = tnbytes * 8f / hd.MaxCompImgWidth / hd.MaxCompImgHeight;
}
// Bit-rate allocation
if (!isTruncMode)
{
allocateRate();
}
// Update 'res' value once all tile-part headers are read
if (pl.getParameter("res") == null)
{
targetRes = decSpec.dls.Min;
}
else
{
try
{
targetRes = pl.getIntParameter("res");
if (targetRes < 0)
{
throw new System.ArgumentException("Specified negative " + "resolution level " + "index: " + targetRes);
}
}
catch (System.FormatException)
{
throw new System.ArgumentException("Invalid resolution level " + "index ('-res' option) " + pl.getParameter("res"));
}
}
// Verify reduction in resolution level
mdl = decSpec.dls.Min;
if (targetRes > mdl)
{
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Specified resolution level (" + targetRes + ") is larger" + " than the maximum value. Setting it to " + mdl + " (maximum value)");
targetRes = mdl;
}
// Backup nBytes
for (int tIdx = 0; tIdx < nt; tIdx++)
{
baknBytes[tIdx] = nBytes[tIdx];
}
return ;
}
remainingTileParts = 0;
// Update 'res' value once all tile-part headers are read
if (pl.getParameter("res") == null)
{
targetRes = decSpec.dls.Min;
}
else
{
try
{
targetRes = pl.getIntParameter("res");
if (targetRes < 0)
{
throw new System.ArgumentException("Specified negative " + "resolution level index: " + targetRes);
}
}
catch (System.FormatException)
{
throw new System.ArgumentException("Invalid resolution level " + "index ('-res' option) " + pl.getParameter("res"));
}
}
// Verify reduction in resolution level
mdl = decSpec.dls.Min;
if (targetRes > mdl)
{
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Specified resolution level (" + targetRes + ") is larger" + " than the maximum possible. Setting it to " + mdl + " (maximum possible)");
targetRes = mdl;
}
if (printInfo)
{
}
// Check presence of EOC marker is decoding rate not reached or if
// this marker has not been found yet
if (!isEOCFound && !isPsotEqualsZero)
{
try
{
short eocCheck = 0;
if (in_Renamed.Pos + sizeof(short) <= in_Renamed.length())
eocCheck = in_Renamed.readShort();
if (!rateReached && !isPsotEqualsZero && eocCheck != CSJ2K.j2k.codestream.Markers.EOC)
{
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "EOC marker not found. " + "Codestream is corrupted.");
}
}
catch (System.IO.EndOfStreamException)
{
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "EOC marker is missing");
}
}
// Bit-rate allocation
if (!isTruncMode)
{
allocateRate();
}
else
{
// Take EOC into account if rate is not reached
if (in_Renamed.Pos >= tnbytes)
anbytes += 2;
}
// Backup nBytes
for (int tIdx = 0; tIdx < nt; tIdx++)
{
baknBytes[tIdx] = nBytes[tIdx];
if (printInfo)
{
FacilityManager.getMsgLogger().println("" + hi.toStringTileHeader(tIdx, tilePartLen[tIdx].Length), 2, 2);
}
}
}