/// <summary> Instantiates a new MQ-decoder, with the specified number of contexts /// and initial states. The compressed bytestream is read from the /// 'iStream' object. /// /// </summary> /// <param name="iStream">the stream that contains the coded bits /// /// </param> /// <param name="nrOfContexts">The number of contexts used /// /// </param> /// <param name="initStates">The initial state for each context. A reference is /// kept to this array to reinitialize the contexts whenever 'reset()' or /// 'resetCtxts()' is called. /// /// </param> public MQDecoder(ByteInputBuffer iStream, int nrOfContexts, int[] initStates) { in_Renamed = iStream; // Default initialization of the statistics bins is MPS=0 and // I=0 I = new int[nrOfContexts]; mPS = new int[nrOfContexts]; // Save the initial states this.initStates = initStates; // Initialize init(); // Set the contexts resetCtxts(); }
/// <summary> Instantiates a new 'ByteToBitInput' object that uses 'in' as the /// underlying byte based input. /// /// </summary> /// <param name="in">The underlying byte based input. /// /// </param> public ByteToBitInput(ByteInputBuffer in_Renamed) { this.in_Renamed = in_Renamed; }
/// <summary> Returns the specified code-block in the current tile for the specified /// component, as a copy (see below). /// /// <P>The returned code-block may be progressive, which is indicated by /// the 'progressive' variable of the returned 'DataBlk' object. If a /// code-block is progressive it means that in a later request to this /// method for the same code-block it is possible to retrieve data which is /// a better approximation, since meanwhile more data to decode for the /// code-block could have been received. If the code-block is not /// progressive then later calls to this method for the same code-block /// will return the exact same data values. /// /// <P>The data returned by this method is always a copy of the internal /// data of this object, if any, and it can be modified "in place" without /// any problems after being returned. The 'offset' of the returned data is /// 0, and the 'scanw' is the same as the code-block width. See the /// 'DataBlk' class. /// /// <P>The 'ulx' and 'uly' members of the returned 'DataBlk' object /// contain the coordinates of the top-left corner of the block, with /// respect to the tile, not the subband. /// /// </summary> /// <param name="c">The component for which to return the next code-block. /// /// </param> /// <param name="m">The vertical index of the code-block to return, in the /// specified subband. /// /// </param> /// <param name="n">The horizontal index of the code-block to return, in the /// specified subband. /// /// </param> /// <param name="sb">The subband in which the code-block to return is. /// /// </param> /// <param name="cblk">If non-null this object will be used to return the new /// code-block. If null a new one will be allocated and returned. If the /// "data" array of the object is non-null it will be reused, if possible, /// to return the data. /// /// </param> /// <returns> The next code-block in the current tile for component 'n', or /// null if all code-blocks for the current tile have been returned. /// /// </returns> /// <seealso cref="DataBlk"> /// /// </seealso> public override DataBlk getCodeBlock(int c, int m, int n, SubbandSyn sb, DataBlk cblk) { //long stime = 0L; // Start time for timed sections int[] zc_lut; // The ZC lookup table to use int[] out_data; // The outupt data buffer int npasses; // The number of coding passes to perform int curbp; // The current magnitude bit-plane (starts at 30) bool error; // Error indicator int tslen; // Length of first terminated segment int tsidx; // Index of current terminated segment ByteInputBuffer in_Renamed = null; bool isterm; // Get the code-block to decode srcblk = src.getCodeBlock(c, m, n, sb, 1, - 1, srcblk); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // Retrieve options from decSpec options = ((System.Int32) decSpec.ecopts.getTileCompVal(tIdx, c)); // Reset state ArrayUtil.intArraySet(state, 0); // Initialize output code-block if (cblk == null) cblk = new DataBlkInt(); cblk.progressive = srcblk.prog; cblk.ulx = srcblk.ulx; cblk.uly = srcblk.uly; cblk.w = srcblk.w; cblk.h = srcblk.h; cblk.offset = 0; cblk.scanw = cblk.w; out_data = (int[]) cblk.Data; if (out_data == null || out_data.Length < srcblk.w * srcblk.h) { out_data = new int[srcblk.w * srcblk.h]; cblk.Data = out_data; } else { // Set data values to 0 ArrayUtil.intArraySet(out_data, 0); } if (srcblk.nl <= 0 || srcblk.nTrunc <= 0) { // 0 layers => no data to decode => return all 0s return cblk; } // Get the length of the first terminated segment tslen = (srcblk.tsLengths == null)?srcblk.dl:srcblk.tsLengths[0]; tsidx = 0; // Initialize for decoding npasses = srcblk.nTrunc; if (mq == null) { in_Renamed = new ByteInputBuffer(srcblk.data, 0, tslen); mq = new MQDecoder(in_Renamed, NUM_CTXTS, MQ_INIT); } else { // We always start by an MQ segment mq.nextSegment(srcblk.data, 0, tslen); mq.resetCtxts(); } error = false; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0) { if (bin == null) { if (in_Renamed == null) in_Renamed = mq.ByteInputBuffer; bin = new ByteToBitInput(in_Renamed); } } // Choose correct ZC lookup table for global orientation switch (sb.orientation) { case Subband.WT_ORIENT_HL: zc_lut = ZC_LUT_HL; break; case Subband.WT_ORIENT_LH: case Subband.WT_ORIENT_LL: zc_lut = ZC_LUT_LH; break; case Subband.WT_ORIENT_HH: zc_lut = ZC_LUT_HH; break; default: throw new System.ApplicationException("JJ2000 internal error"); } // NOTE: we don't currently detect which is the last magnitude // bit-plane so that 'isterm' is true for the last pass of it. Doing // so would aid marginally in error detection with the predictable // error resilient MQ termination. However, determining which is the // last magnitude bit-plane is quite hard (due to ROI, quantization, // etc.) and in any case the predictable error resilient termination // used without the arithmetic coding bypass and/or regular // termination modes is almost useless. // Loop on bit-planes and passes curbp = 30 - srcblk.skipMSBP; // Check for maximum number of bitplanes quit condition if (mQuit != - 1 && (mQuit * 3 - 2) < npasses) { npasses = mQuit * 3 - 2; } // First bit-plane has only the cleanup pass if (curbp >= 0 && npasses > 0) { isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP) >= curbp); error = cleanuppass(cblk, mq, curbp, state, zc_lut, isterm); npasses--; if (!error || !doer) curbp--; } // Other bit-planes have the three coding passes if (!error || !doer) { while (curbp >= 0 && npasses > 0) { if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (curbp < 31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP)) { // Use bypass decoding mode (only all bit-planes // after the first 4 bit-planes). // Here starts a new raw segment bin.setByteArray(null, - 1, srcblk.tsLengths[++tsidx]); isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0; error = rawSigProgPass(cblk, bin, curbp, state, isterm); npasses--; if (npasses <= 0 || (error && doer)) break; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Start a new raw segment bin.setByteArray(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP > curbp)); error = rawMagRefPass(cblk, bin, curbp, state, isterm); } else { // Do not use bypass decoding mode if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Here starts a new MQ segment mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0; error = sigProgPass(cblk, mq, curbp, state, zc_lut, isterm); npasses--; if (npasses <= 0 || (error && doer)) break; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Here starts a new MQ segment mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP > curbp)); error = magRefPass(cblk, mq, curbp, state, isterm); } npasses--; if (npasses <= 0 || (error && doer)) break; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (curbp < 31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP))) { // Here starts a new MQ segment mq.nextSegment(null, - 1, srcblk.tsLengths[++tsidx]); } isterm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - srcblk.skipMSBP) >= curbp); error = cleanuppass(cblk, mq, curbp, state, zc_lut, isterm); npasses--; if (error && doer) break; // Goto next bit-plane curbp--; } } // If an error ocurred conceal it if (error && doer) { if (verber) { FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Error detected at bit-plane " + curbp + " in code-block (" + m + "," + n + "), sb_idx " + sb.sbandIdx + ", res. level " + sb.resLvl + ". Concealing..."); } conceal(cblk, curbp); } #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif // Return decoded block return cblk; }