/// <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); } } }