CSJ2K.j2k.entropy.encoder.MQCoder.terminate C# (CSharp) Method

terminate() public method

This function flushes the remaining encoded bits and makes sure that enough information is written to the bit stream to be able to finish decoding, and then it reinitializes the internal state of the MQ coder but without modifying the context states.

After calling this method the 'finishLengthCalculation()' method should be called, after compensating the returned length for the length of previous coded segments, so that the length calculation is finalized.

The type of termination used depends on the one specified at the constructor.

public terminate ( ) : int
return int
        public virtual int terminate()
        {
            switch (ttype)
            {

                case TERM_FULL:
                    //sets the remaining bits of the last byte of the coded bits.
                    int tempc = c + a;
                    c = c | 0xFFFF;
                    if (c >= tempc)
                    {
                        c = c - 0x8000;
                    }

                    int remainingBits = 27 - cT;

                    // Flushes remainingBits
                    do
                    {
                        c <<= cT;
                        if (b != 0xFF)
                        {
                            remainingBits -= 8;
                        }
                        else
                        {
                            remainingBits -= 7;
                        }
                        byteOut();
                    }
                    while (remainingBits > 0);

                    b |= (1 << (- remainingBits)) - 1;
                    if (b == 0xFF)
                    {
                        // Delay 0xFF bytes
                        delFF = true;
                    }
                    else
                    {
                        // Write delayed 0xFF bytes
                        if (delFF)
                        {
                            out_Renamed.write(0xFF);
                            delFF = false;
                            nrOfWrittenBytes++;
                        }
                        out_Renamed.write(b);
                        nrOfWrittenBytes++;
                    }
                    break;

                case TERM_PRED_ER:
                case TERM_EASY:
                    // The predictable error resilient and easy termination are the
                    // same, except for the fact that the easy one can modify the
                    // spare bits in the last byte to maximize the likelihood of
                    // having a 0xFF, while the error resilient one can not touch
                    // these bits.

                    // In the predictable error resilient case the spare bits will be
                    // recalculated by the decoder and it will check if they are the
                    // same as as in the codestream and then deduce an error
                    // probability from there.

                    int k; // number of bits to push out

                    k = (11 - cT) + 1;

                    c <<= cT;
                    for (; k > 0; k -= cT, c <<= cT)
                    {
                        byteOut();
                    }

                    // Make any spare bits 1s if in easy termination
                    if (k < 0 && ttype == TERM_EASY)
                    {
                        // At this stage there is never a carry bit in C, so we can
                        // freely modify the (-k) least significant bits.
                        b |= (1 << (- k)) - 1;
                    }

                    byteOut(); // Push contents of byte buffer
                    break;

                case TERM_NEAR_OPT:

                    // This algorithm terminates in the shortest possible way, besides
                    // the fact any previous 0xFF 0x7F sequences are not
                    // eliminated. The probabalility of having those sequences is
                    // extremely low.

                    // The calculation of the length is based on the fact that the
                    // decoder will pad the codestream with an endless string of
                    // (binary) 1s. If the codestream, padded with 1s, is within the
                    // bounds of the current interval then correct decoding is
                    // guaranteed. The lower inclusive bound of the current interval
                    // is the value of C (i.e. if only lower intervals would be coded
                    // in the future). The upper exclusive bound of the current
                    // interval is C+A (i.e. if only upper intervals would be coded in
                    // the future). We therefore calculate the minimum length that
                    // would be needed so that padding with 1s gives a codestream
                    // within the interval.

                    // In general, such a calculation needs the value of the next byte
                    // that appears in the codestream. Here, since we are terminating,
                    // the next value can be anything we want that lies within the
                    // interval, we use the lower bound since this minimizes the
                    // length. To calculate the necessary length at any other place
                    // than the termination it is necessary to know the next bytes
                    // that will appear in the codestream, which involves storing the
                    // codestream and the sate of the MQCoder at various points (a
                    // worst case approach can be used, but it is much more
                    // complicated and the calculated length would be only marginally
                    // better than much simple calculations, if not the same).

                    int cLow;
                    int cUp;
                    int bLow;
                    int bUp;

                    // Initialize the upper (exclusive) and lower bound (inclusive) of
                    // the valid interval (the actual interval is the concatenation of
                    // bUp and cUp, and bLow and cLow).
                    cLow = c;
                    cUp = c + a;
                    bLow = bUp = b;

                    // We start by normalizing the C register to the sate cT = 0
                    // (i.e., just before byteOut() is called)
                    cLow <<= cT;
                    cUp <<= cT;
                    // Progate eventual carry bits and reset them in Clow, Cup NOTE:
                    // carry bit can never be set if the byte buffer was empty so no
                    // problem with propagating a carry into an empty byte buffer.
                    if ((cLow & (1 << 27)) != 0)
                    {
                        // Carry bit in cLow
                        if (bLow == 0xFF)
                        {
                            // We can not propagate carry bit, do bit stuffing
                            delFF = true; // delay 0xFF
                            // Get next byte buffer
                            bLow = SupportClass.URShift(cLow, 20);
                            bUp = SupportClass.URShift(cUp, 20);
                            cLow &= 0xFFFFF;
                            cUp &= 0xFFFFF;
                            // Normalize to cT = 0
                            cLow <<= 7;
                            cUp <<= 7;
                        }
                        else
                        {
                            // we can propagate carry bit
                            bLow++; // propagate
                            cLow &= ~ (1 << 27); // reset carry in cLow
                        }
                    }
                    if ((cUp & (1 << 27)) != 0)
                    {
                        bUp++; // propagate
                        cUp &= ~ (1 << 27); // reset carry
                    }

                    // From now on there can never be a carry bit on cLow, since we
                    // always output bLow.

                    // Loop testing for the condition and doing byte output if they
                    // are not met.
                    while (true)
                    {
                        // If decoder's codestream is within interval stop
                        // If preceding byte is 0xFF only values [0,127] are valid
                        if (delFF)
                        {
                            // If delayed 0xFF
                            if (bLow <= 127 && bUp > 127)
                                break;
                            // We will write more bytes so output delayed 0xFF now
                            out_Renamed.write(0xFF);
                            nrOfWrittenBytes++;
                            delFF = false;
                        }
                        else
                        {
                            // No delayed 0xFF
                            if (bLow <= 255 && bUp > 255)
                                break;
                        }

                        // Output next byte
                        // We could output anything within the interval, but using
                        // bLow simplifies things a lot.

                        // We should not have any carry bit here

                        // Output bLow
                        if (bLow < 255)
                        {
                            // Transfer byte bits from C to B
                            // (if the byte buffer was empty output nothing)
                            if (nrOfWrittenBytes >= 0)
                                out_Renamed.write(bLow);
                            nrOfWrittenBytes++;
                            bUp -= bLow;
                            bUp <<= 8;
                            // Here bLow would be 0
                            bUp |= (SupportClass.URShift(cUp, 19)) & 0xFF;
                            bLow = (SupportClass.URShift(cLow, 19)) & 0xFF;
                            // Clear upper bits (just pushed out) from cUp Clow.
                            cLow &= 0x7FFFF;
                            cUp &= 0x7FFFF;
                            // Goto next state where CT is 0
                            cLow <<= 8;
                            cUp <<= 8;
                            // Here there can be no carry on Cup, Clow
                        }
                        else
                        {
                            // bLow = 0xFF
                            // Transfer byte bits from C to B
                            // Since the byte to output is 0xFF we can delay it
                            delFF = true;
                            bUp -= bLow;
                            bUp <<= 7;
                            // Here bLow would be 0
                            bUp |= (cUp >> 20) & 0x7F;
                            bLow = (cLow >> 20) & 0x7F;
                            // Clear upper bits (just pushed out) from cUp Clow.
                            cLow &= 0xFFFFF;
                            cUp &= 0xFFFFF;
                            // Goto next state where CT is 0
                            cLow <<= 7;
                            cUp <<= 7;
                            // Here there can be no carry on Cup, Clow
                        }
                    }
                    break;

                default:
                    throw new System.InvalidOperationException("Illegal termination type code");

            }

            // Reinitialize the state (without modifying the contexts)
            int len;

            len = nrOfWrittenBytes;
            a = 0x8000;
            c = 0;
            b = 0;
            cT = 12;
            delFF = false;
            nrOfWrittenBytes = - 1;

            // Return the terminated length
            return len;
        }

Usage Example

示例#1
0
		/// <summary> Performs the magnitude refinement pass on the specified data and
		/// bit-plane. It codes the samples which are significant and which do not
		/// have the "visited" state bit turned on, using the MR primitive. The
		/// "visited" state bit is not mofified for any samples.
		/// 
		/// </summary>
		/// <param name="srcblk">The code-block data to code
		/// 
		/// </param>
		/// <param name="mq">The MQ-coder to use
		/// 
		/// </param>
		/// <param name="doterm">If true it performs an MQ-coder termination after the end
		/// of the pass
		/// 
		/// </param>
		/// <param name="bp">The bit-plane to code
		/// 
		/// </param>
		/// <param name="state">The state information for the code-block
		/// 
		/// </param>
		/// <param name="fm">The distortion estimation lookup table for MR
		/// 
		/// </param>
		/// <param name="symbuf">The buffer to hold symbols to send to the MQ coder
		/// 
		/// </param>
		/// <param name="ctxtbuf">A buffer to hold the contexts to use in sending the
		/// buffered symbols to the MQ coder.
		/// 
		/// </param>
		/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at 
		/// the end of this coding pass.
		/// 
		/// </param>
		/// <param name="pidx">The coding pass index. Is the index in the 'ratebuf' array
		/// where to store the coded length after this coding pass.
		/// 
		/// </param>
		/// <param name="ltpidx">The index of the last pass that was terminated, or
		/// negative if none.
		/// 
		/// </param>
		/// <param name="options">The bitmask of entropy coding options to apply to the
		/// code-block
		/// 
		/// </param>
		/// <returns> The decrease in distortion for this pass, in the fixed-point
		/// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables.
		/// 
		/// </returns>
		static private int magRefPass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fm, int[] symbuf, int[] ctxtbuf, int[] ratebuf, int pidx, int ltpidx, int options)
		{
			int j, sj; // The state index for line and stripe
			int k, sk; // The data index for line and stripe
			int nsym = 0; // Symbol counter for symbol and context buffers
			int dscanw; // The data scan-width
			int sscanw; // The state scan-width
			int jstep; // Stripe to stripe step for 'sj'
			int kstep; // Stripe to stripe step for 'sk'
			int stopsk; // The loop limit on the variable sk
			int csj; // Local copy (i.e. cached) of 'state[j]'
			int mask; // The mask for the current bit-plane
			int[] data; // The data buffer
			int dist; // The distortion reduction for this pass
			int shift; // Shift amount for distortion
			int upshift; // Shift left amount for distortion
			int downshift; // Shift right amount for distortion
			int normval; // The normalized sample magnitude value
			int s; // The stripe index
			int nstripes; // The number of stripes in the code-block
			int sheight; // Height of the current stripe
			
			// Initialize local variables
			dscanw = srcblk.scanw;
			sscanw = srcblk.w + 2;
			jstep = sscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT / 2 - srcblk.w;
			kstep = dscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - srcblk.w;
			mask = 1 << bp;
			data = (int[]) srcblk.Data;
			nstripes = (srcblk.h + CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - 1) / CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
			dist = 0;
			// We use the bit just coded plus MSE_LKP_BITS-1 bits below the bit
			// just coded for distortion estimation.
			shift = bp - (MSE_LKP_BITS - 1);
			upshift = (shift >= 0)?0:- shift;
			downshift = (shift <= 0)?0:shift;
			
			// Code stripe by stripe
			sk = srcblk.offset;
			sj = sscanw + 1;
			for (s = nstripes - 1; s >= 0; s--, sk += kstep, sj += jstep)
			{
				sheight = (s != 0)?CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT:srcblk.h - (nstripes - 1) * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
				stopsk = sk + srcblk.w;
				// Scan by set of 1 stripe column at a time
				for (nsym = 0; sk < stopsk; sk++, sj++)
				{
					// Do half top of column
					j = sj;
					csj = state[j];
					// If any of the two samples is significant and not yet
					// visited in the current bit-plane we can not skip them
					if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
					{
						k = sk;
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
						{
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[csj & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R1;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						if (sheight < 2)
						{
							state[j] = csj;
							continue;
						}
						// Scan second row
						if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
						{
							k += dscanw;
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[(SupportClass.URShift(csj, STATE_SEP)) & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R2;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						state[j] = csj;
					}
					// Do half bottom of column
					if (sheight < 3)
						continue;
					j += sscanw;
					csj = state[j];
					// If any of the two samples is significant and not yet
					// visited in the current bit-plane we can not skip them
					if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
					{
						k = sk + (dscanw << 1);
						// Scan first row
						if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
						{
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[csj & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R1;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						if (sheight < 4)
						{
							state[j] = csj;
							continue;
						}
						// Scan second row
						if ((state[j] & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
						{
							k += dscanw;
							// Apply MR primitive
							symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
							ctxtbuf[nsym++] = MR_LUT[(SupportClass.URShift(csj, STATE_SEP)) & MR_MASK];
							// Update the STATE_PREV_MR bit
							csj |= STATE_PREV_MR_R2;
							// Update distortion
							normval = (data[k] >> downshift) << upshift;
							dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
						}
						state[j] = csj;
					}
				}
				// Code all buffered symbols, if any
				if (nsym > 0)
					mq.codeSymbols(symbuf, ctxtbuf, nsym);
			}
			
			// Reset the MQ context states if we need to
			if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ) != 0)
			{
				mq.resetCtxts();
			}
			
			// Terminate the MQ bit stream if we need to
			if (doterm)
			{
				ratebuf[pidx] = mq.terminate(); // Termination has special length
			}
			else
			{
				// Use normal length calculation
				ratebuf[pidx] = mq.NumCodedBytes;
			}
			// Add length of previous segments, if any
			if (ltpidx >= 0)
			{
				ratebuf[pidx] += ratebuf[ltpidx];
			}
			// Finish length calculation if needed
			if (doterm)
			{
				mq.finishLengthCalculation(ratebuf, pidx);
			}
			
			// Return the reduction in distortion
			return dist;
		}
All Usage Examples Of CSJ2K.j2k.entropy.encoder.MQCoder::terminate