* Fixed a typo in OpenJPEG.J2KLayerInfo (only affected debug display) git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@3118 52acb1d6-8a22-11de-b505-999d5b087335
3752 lines
148 KiB
C#
3752 lines
148 KiB
C#
/*
|
|
* CVS identifier:
|
|
*
|
|
* $Id: StdEntropyCoder.java,v 1.41 2002/07/04 15:53:32 grosbois Exp $
|
|
*
|
|
* Class: StdEntropyCoder
|
|
*
|
|
* Description: Entropy coding engine of stripes in code-blocks
|
|
*
|
|
*
|
|
*
|
|
* 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.quantization.quantizer;
|
|
using CSJ2K.j2k.wavelet.analysis;
|
|
using CSJ2K.j2k.codestream;
|
|
using CSJ2K.j2k.wavelet;
|
|
using CSJ2K.j2k.encoder;
|
|
using CSJ2K.j2k.entropy;
|
|
using CSJ2K.j2k.image;
|
|
using CSJ2K.j2k.util;
|
|
using CSJ2K.j2k.io;
|
|
using CSJ2K.j2k;
|
|
namespace CSJ2K.j2k.entropy.encoder
|
|
{
|
|
|
|
/// <summary> This class implements the JPEG 2000 entropy coder, which codes stripes in
|
|
/// code-blocks. This entropy coding engine can function in a single-threaded
|
|
/// mode where one code-block is encoded at a time, or in a multi-threaded mode
|
|
/// where multiple code-blocks are entropy coded in parallel. The interface
|
|
/// presented by this class is the same in both modes.
|
|
///
|
|
/// <p>The number of threads used by this entropy coder is specified by the
|
|
/// "jj2000.j2k.entropy.encoder.StdEntropyCoder.nthreads" Java system
|
|
/// property. If set to "0" the single threaded implementation is used. If set
|
|
/// to 'n' ('n' larger than 0) then 'n' extra threads are started by this class
|
|
/// which are used to encode the code-blocks in parallel (i.e. ideally 'n'
|
|
/// code-blocks will be encoded in parallel at a time). On multiprocessor
|
|
/// machines under a "native threads" Java Virtual Machine implementation each
|
|
/// one of these threads can run on a separate processor speeding up the
|
|
/// encoding time. By default the single-threaded implementation is used. The
|
|
/// multi-threaded implementation currently assumes that the vast majority of
|
|
/// consecutive calls to 'getNextCodeBlock()' will be done on the same
|
|
/// component. If this is not the case, the speed-up that can be expected on
|
|
/// multiprocessor machines might be significantly decreased.</p>
|
|
///
|
|
/// <p>The code-blocks are rectangular, with dimensions which must be powers of
|
|
/// 2. Each dimension has to be no smaller than 4 and no larger than 256. The
|
|
/// product of the two dimensions (i.e. area of the code-block) may not exceed
|
|
/// 4096.</p>
|
|
///
|
|
/// <p>Context 0 of the MQ-coder is used as the uniform one (uniform,
|
|
/// non-adaptive probability distribution). Context 1 is used for RLC
|
|
/// coding. Contexts 2-10 are used for zero-coding (ZC), contexts 11-15 are
|
|
/// used for sign-coding (SC) and contexts 16-18 are used for
|
|
/// magnitude-refinement (MR).</p>
|
|
///
|
|
/// <p>This implementation buffers the symbols and calls the MQ coder only once
|
|
/// per stripe and per coding pass, to reduce the method call overhead.</p>
|
|
///
|
|
/// <p>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.</p>
|
|
///
|
|
/// <p>The source module must implement the CBlkQuantDataSrcEnc interface and
|
|
/// code-block's data is received in a CBlkWTData instance. This modules sends
|
|
/// code-block's information in a CBlkRateDistStats instance.</p>
|
|
///
|
|
/// </summary>
|
|
/// <seealso cref="CBlkQuantDataSrcEnc">
|
|
/// </seealso>
|
|
/// <seealso cref="CBlkWTData">
|
|
/// </seealso>
|
|
/// <seealso cref="CBlkRateDistStats">
|
|
///
|
|
/// </seealso>
|
|
public class StdEntropyCoder:EntropyCoder
|
|
{
|
|
|
|
/// <summary>Whether to collect timing information or not: false. Used as a compile
|
|
/// time directive.
|
|
/// </summary>
|
|
private const bool DO_TIMING = false;
|
|
|
|
/// <summary>The cumulative wall time for the entropy coding engine, for each
|
|
/// component. In the single-threaded implementation it is the total time,
|
|
/// in the multi-threaded implementation it is the time spent managing the
|
|
/// compressor threads only.
|
|
/// </summary>
|
|
//private long[] time;
|
|
|
|
/// <summary>The Java system property name for the number of threads to use:
|
|
/// jj2000.j2k.entropy.encoder.StdEntropyCoder.nthreads
|
|
/// </summary>
|
|
public const System.String THREADS_PROP_NAME = "jj2000.j2k.entropy.encoder.StdEntropyCoder.nthreads";
|
|
|
|
/// <summary>The default value for the property in THREADS_PROP_NAME: 0 </summary>
|
|
public const System.String DEF_THREADS_NUM = "0";
|
|
|
|
/// <summary>The increase in priority for the compressor threads, currently 3. The
|
|
/// compressor threads will have a priority of THREADS_PRIORITY_INC more
|
|
/// than the priority of the thread calling this class constructor. Used
|
|
/// only in the multi-threaded implementation.
|
|
/// </summary>
|
|
public const int THREADS_PRIORITY_INC = 0;
|
|
|
|
/// <summary>The pool of threads, for the threaded implementation. It is null, if
|
|
/// non threaded implementation is used
|
|
/// </summary>
|
|
private ThreadPool tPool;
|
|
|
|
/// <summary>The queue of idle compressors. Used in multithreaded
|
|
/// implementation only
|
|
/// </summary>
|
|
private System.Collections.ArrayList idleComps;
|
|
|
|
/// <summary>The queue of completed compressors, for each component. Used
|
|
/// in multithreaded implementation only.
|
|
/// </summary>
|
|
private System.Collections.ArrayList[] completedComps;
|
|
|
|
/// <summary>The number of busy compressors, for each component. Used in
|
|
/// multithreaded implementation only.
|
|
/// </summary>
|
|
private int[] nBusyComps;
|
|
|
|
/// <summary>A flag indicating for each component if all the code-blocks of the *
|
|
/// current tile have been returned. Used in multithreaded implementation
|
|
/// only.
|
|
/// </summary>
|
|
private bool[] finishedTileComponent;
|
|
|
|
/// <summary>The MQ coder used, for each thread </summary>
|
|
private MQCoder[] mqT;
|
|
|
|
/// <summary>The raw bit output used, for each thread </summary>
|
|
private BitToByteOutput[] boutT;
|
|
|
|
/// <summary>The output stream used, for each thread </summary>
|
|
private ByteOutputBuffer[] outT;
|
|
|
|
/// <summary>The code-block size specifications </summary>
|
|
private CBlkSizeSpec cblks;
|
|
|
|
/// <summary>The precinct partition specifications </summary>
|
|
private PrecinctSizeSpec pss;
|
|
|
|
/// <summary>By-pass mode specifications </summary>
|
|
public StringSpec bms;
|
|
|
|
/// <summary>MQ reset specifications </summary>
|
|
public StringSpec mqrs;
|
|
|
|
/// <summary>Regular termination specifications </summary>
|
|
public StringSpec rts;
|
|
|
|
/// <summary>Causal stripes specifications </summary>
|
|
public StringSpec css;
|
|
|
|
/// <summary>Error resilience segment symbol use specifications </summary>
|
|
public StringSpec sss;
|
|
|
|
/// <summary>The length calculation specifications </summary>
|
|
public StringSpec lcs;
|
|
|
|
/// <summary>The termination type specifications </summary>
|
|
public StringSpec tts;
|
|
|
|
/// <summary>The options that are turned on, as flag bits. One element for each
|
|
/// tile-component. The options are 'OPT_TERM_PASS', 'OPT_RESET_MQ',
|
|
/// 'OPT_VERT_STR_CAUSAL', 'OPT_BYPASS' and 'OPT_SEG_SYMBOLS' as defined in
|
|
/// the StdEntropyCoderOptions interface
|
|
///
|
|
/// </summary>
|
|
/// <seealso cref="StdEntropyCoderOptions">
|
|
///
|
|
/// </seealso>
|
|
private int[][] opts = null;
|
|
|
|
/// <summary>The length calculation type for each tile-component </summary>
|
|
private int[][] lenCalc = null;
|
|
|
|
/// <summary>The termination type for each tile-component </summary>
|
|
private int[][] tType = null;
|
|
|
|
/// <summary>Number of bits used for the Zero Coding lookup table </summary>
|
|
private const int ZC_LUT_BITS = 8;
|
|
|
|
/// <summary>Zero Coding context lookup tables for the LH global orientation </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'ZC_LUT_LH '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] ZC_LUT_LH = new int[1 << ZC_LUT_BITS];
|
|
|
|
/// <summary>Zero Coding context lookup tables for the HL global orientation </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'ZC_LUT_HL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] ZC_LUT_HL = new int[1 << ZC_LUT_BITS];
|
|
|
|
/// <summary>Zero Coding context lookup tables for the HH global orientation </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'ZC_LUT_HH '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] ZC_LUT_HH = new int[1 << ZC_LUT_BITS];
|
|
|
|
/// <summary>Number of bits used for the Sign Coding lookup table </summary>
|
|
private const int SC_LUT_BITS = 9;
|
|
|
|
/// <summary>Sign Coding context lookup table. The index into the table is a 9 bit
|
|
/// index, which correspond the the value in the 'state' array shifted by
|
|
/// 'SC_SHIFT'. Bits 8-5 are the signs of the horizontal-left,
|
|
/// horizontal-right, vertical-up and vertical-down neighbors,
|
|
/// respectively. Bit 4 is not used (0 or 1 makes no difference). Bits 3-0
|
|
/// are the significance of the horizontal-left, horizontal-right,
|
|
/// vertical-up and vertical-down neighbors, respectively. The least 4 bits
|
|
/// of the value in the lookup table define the context number and the sign
|
|
/// bit defines the "sign predictor".
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'SC_LUT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] SC_LUT = new int[1 << SC_LUT_BITS];
|
|
|
|
/// <summary>The mask to obtain the context index from the 'SC_LUT' </summary>
|
|
private const int SC_LUT_MASK = (1 << 4) - 1;
|
|
|
|
/// <summary>The shift to obtain the sign predictor from the 'SC_LUT'. It must be
|
|
/// an unsigned shift.
|
|
/// </summary>
|
|
private const int SC_SPRED_SHIFT = 31;
|
|
|
|
/// <summary>The sign bit for int data </summary>
|
|
private const int INT_SIGN_BIT = 1 << 31;
|
|
|
|
/// <summary>The number of bits used for the Magnitude Refinement lookup table </summary>
|
|
private const int MR_LUT_BITS = 9;
|
|
|
|
/// <summary>Magnitude Refinement context lookup table </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'MR_LUT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] MR_LUT = new int[1 << MR_LUT_BITS];
|
|
|
|
/// <summary>The number of contexts used </summary>
|
|
private const int NUM_CTXTS = 19;
|
|
|
|
/// <summary>The RLC context </summary>
|
|
private const int RLC_CTXT = 1;
|
|
|
|
/// <summary>The UNIFORM context (with a uniform probability distribution which
|
|
/// does not adapt)
|
|
/// </summary>
|
|
private const int UNIF_CTXT = 0;
|
|
|
|
/// <summary>The initial states for the MQ coder </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'MQ_INIT'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] MQ_INIT = new int[]{46, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
/// <summary>The 4 bits of the error resilience segmentation symbol (1010) </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'SEG_SYMBOLS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] SEG_SYMBOLS = new int[]{1, 0, 1, 0};
|
|
|
|
/// <summary>The 4 contexts for the error resilience segmentation symbol (always
|
|
/// the UNIFORM context, UNIF_CTXT)
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'SEG_SYMB_CTXTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] SEG_SYMB_CTXTS = new int[]{UNIF_CTXT, UNIF_CTXT, UNIF_CTXT, UNIF_CTXT};
|
|
|
|
/// <summary> The state array for each thread. Each element of the state array stores
|
|
/// the state of two coefficients. The lower 16 bits store the state of a
|
|
/// coefficient in row 'i' and column 'j', while the upper 16 bits store
|
|
/// the state of a coefficient in row 'i+1' and column 'j'. The 'i' row is
|
|
/// either the first or the third row of a stripe. This packing of the
|
|
/// states into 32 bit words allows a faster scan of all coefficients on
|
|
/// each coding pass and diminished the amount of data transferred. The
|
|
/// size of the state array is increased by 1 on each side (top, bottom,
|
|
/// left, right) to handle boundary conditions without any special logic.
|
|
///
|
|
/// <p>The state of a coefficient is stored in the following way in the
|
|
/// lower 16 bits, where bit 0 is the least significant bit. Bit 15 is the
|
|
/// significance of a coefficient (0 if non-significant, 1 otherwise). Bit
|
|
/// 14 is the visited state (i.e. if a coefficient has been coded in the
|
|
/// significance propagation pass of the current bit-plane). Bit 13 is the
|
|
/// "non zero-context" state (i.e. if one of the eight immediate neighbors
|
|
/// is significant it is 1, otherwise is 0). Bits 12 to 9 store the sign of
|
|
/// the already significant left, right, up and down neighbors (1 for
|
|
/// negative, 0 for positive or not yet significant). Bit 8 indicates if
|
|
/// the magnitude refinement has already been applied to the
|
|
/// coefficient. Bits 7 to 4 store the significance of the left, right, up
|
|
/// and down neighbors (1 for significant, 0 for non significant). Bits 3
|
|
/// to 0 store the significance of the diagonal coefficients (up-left,
|
|
/// up-right, down-left and down-right; 1 for significant, 0 for non
|
|
/// significant).</p>
|
|
///
|
|
/// <p>The upper 16 bits the state is stored as in the lower 16 bits, but
|
|
/// with the bits shifted up by 16.</p>
|
|
///
|
|
/// <p>The lower 16 bits are referred to as "row 1" ("R1") while the upper
|
|
/// 16 bits are referred to as "row 2" ("R2").</p>
|
|
///
|
|
/// </summary>
|
|
private int[][] stateT;
|
|
|
|
/* The separation between the upper and lower bits in the state array: 16
|
|
* */
|
|
private const int STATE_SEP = 16;
|
|
|
|
/// <summary>The flag bit for the significance in the state array, for row 1. </summary>
|
|
private const int STATE_SIG_R1 = 1 << 15;
|
|
|
|
/// <summary>The flag bit for the "visited" bit in the state array, for row 1. </summary>
|
|
private const int STATE_VISITED_R1 = 1 << 14;
|
|
|
|
/// <summary>The flag bit for the "not zero context" bit in the state array, for
|
|
/// row 1. This bit is always the OR of bits STATE_H_L_R1, STATE_H_R_R1,
|
|
/// STATE_V_U_R1, STATE_V_D_R1, STATE_D_UL_R1, STATE_D_UR_R1, STATE_D_DL_R1
|
|
/// and STATE_D_DR_R1.
|
|
/// </summary>
|
|
private const int STATE_NZ_CTXT_R1 = 1 << 13;
|
|
|
|
/// <summary>The flag bit for the horizontal-left sign in the state array, for row
|
|
/// 1. This bit can only be set if the STATE_H_L_R1 is also set.
|
|
/// </summary>
|
|
private const int STATE_H_L_SIGN_R1 = 1 << 12;
|
|
|
|
/// <summary>The flag bit for the horizontal-right sign in the state array, for
|
|
/// row 1. This bit can only be set if the STATE_H_R_R1 is also set.
|
|
/// </summary>
|
|
private const int STATE_H_R_SIGN_R1 = 1 << 11;
|
|
|
|
/// <summary>The flag bit for the vertical-up sign in the state array, for row
|
|
/// 1. This bit can only be set if the STATE_V_U_R1 is also set.
|
|
/// </summary>
|
|
private const int STATE_V_U_SIGN_R1 = 1 << 10;
|
|
|
|
/// <summary>The flag bit for the vertical-down sign in the state array, for row
|
|
/// 1. This bit can only be set if the STATE_V_D_R1 is also set.
|
|
/// </summary>
|
|
private const int STATE_V_D_SIGN_R1 = 1 << 9;
|
|
|
|
/// <summary>The flag bit for the previous MR primitive applied in the state array,
|
|
/// for row 1.
|
|
/// </summary>
|
|
private const int STATE_PREV_MR_R1 = 1 << 8;
|
|
|
|
/// <summary>The flag bit for the horizontal-left significance in the state array,
|
|
/// for row 1.
|
|
/// </summary>
|
|
private const int STATE_H_L_R1 = 1 << 7;
|
|
|
|
/// <summary>The flag bit for the horizontal-right significance in the state array,
|
|
/// for row 1.
|
|
/// </summary>
|
|
private const int STATE_H_R_R1 = 1 << 6;
|
|
|
|
/// <summary>The flag bit for the vertical-up significance in the state array, for
|
|
/// row 1.
|
|
/// </summary>
|
|
private const int STATE_V_U_R1 = 1 << 5;
|
|
|
|
/// <summary>The flag bit for the vertical-down significance in the state array,
|
|
/// for row 1.
|
|
/// </summary>
|
|
private const int STATE_V_D_R1 = 1 << 4;
|
|
|
|
/// <summary>The flag bit for the diagonal up-left significance in the state array,
|
|
/// for row 1.
|
|
/// </summary>
|
|
private const int STATE_D_UL_R1 = 1 << 3;
|
|
|
|
/// <summary>The flag bit for the diagonal up-right significance in the state
|
|
/// array, for row 1.
|
|
/// </summary>
|
|
private const int STATE_D_UR_R1 = 1 << 2;
|
|
|
|
/// <summary>The flag bit for the diagonal down-left significance in the state
|
|
/// array, for row 1.
|
|
/// </summary>
|
|
private const int STATE_D_DL_R1 = 1 << 1;
|
|
|
|
/// <summary>The flag bit for the diagonal down-right significance in the state
|
|
/// array , for row 1.
|
|
/// </summary>
|
|
private const int STATE_D_DR_R1 = 1;
|
|
|
|
/// <summary>The flag bit for the significance in the state array, for row 2. </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_SIG_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_SIG_R2 = STATE_SIG_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the "visited" bit in the state array, for row 2. </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_VISITED_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_VISITED_R2 = STATE_VISITED_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the "not zero context" bit in the state array, for
|
|
/// row 2. This bit is always the OR of bits STATE_H_L_R2, STATE_H_R_R2,
|
|
/// STATE_V_U_R2, STATE_V_D_R2, STATE_D_UL_R2, STATE_D_UR_R2, STATE_D_DL_R2
|
|
/// and STATE_D_DR_R2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_NZ_CTXT_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_NZ_CTXT_R2 = STATE_NZ_CTXT_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the horizontal-left sign in the state array, for row
|
|
/// 2. This bit can only be set if the STATE_H_L_R2 is also set.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_H_L_SIGN_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_H_L_SIGN_R2 = STATE_H_L_SIGN_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the horizontal-right sign in the state array, for
|
|
/// row 2. This bit can only be set if the STATE_H_R_R2 is also set.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_H_R_SIGN_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_H_R_SIGN_R2 = STATE_H_R_SIGN_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the vertical-up sign in the state array, for row
|
|
/// 2. This bit can only be set if the STATE_V_U_R2 is also set.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_V_U_SIGN_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_V_U_SIGN_R2 = STATE_V_U_SIGN_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the vertical-down sign in the state array, for row
|
|
/// 2. This bit can only be set if the STATE_V_D_R2 is also set.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_V_D_SIGN_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_V_D_SIGN_R2 = STATE_V_D_SIGN_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the previous MR primitive applied in the state array,
|
|
/// for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_PREV_MR_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_PREV_MR_R2 = STATE_PREV_MR_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the horizontal-left significance in the state array,
|
|
/// for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_H_L_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_H_L_R2 = STATE_H_L_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the horizontal-right significance in the state array,
|
|
/// for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_H_R_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_H_R_R2 = STATE_H_R_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the vertical-up significance in the state array, for
|
|
/// row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_V_U_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_V_U_R2 = STATE_V_U_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the vertical-down significance in the state array,
|
|
/// for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_V_D_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_V_D_R2 = STATE_V_D_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the diagonal up-left significance in the state array,
|
|
/// for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_D_UL_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_D_UL_R2 = STATE_D_UL_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the diagonal up-right significance in the state
|
|
/// array, for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_D_UR_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_D_UR_R2 = STATE_D_UR_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the diagonal down-left significance in the state
|
|
/// array, for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_D_DL_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_D_DL_R2 = STATE_D_DL_R1 << STATE_SEP;
|
|
|
|
/// <summary>The flag bit for the diagonal down-right significance in the state
|
|
/// array , for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'STATE_D_DR_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int STATE_D_DR_R2 = STATE_D_DR_R1 << STATE_SEP;
|
|
|
|
/// <summary>The mask to isolate the significance bits for row 1 and 2 of the state
|
|
/// array.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'SIG_MASK_R1R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int SIG_MASK_R1R2 = STATE_SIG_R1 | STATE_SIG_R2;
|
|
|
|
/// <summary>The mask to isolate the visited bits for row 1 and 2 of the state
|
|
/// array.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'VSTD_MASK_R1R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int VSTD_MASK_R1R2 = STATE_VISITED_R1 | STATE_VISITED_R2;
|
|
|
|
/// <summary>The mask to isolate the bits necessary to identify RLC coding state
|
|
/// (significant, visited and non-zero context, for row 1 and 2).
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'RLC_MASK_R1R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int RLC_MASK_R1R2 = STATE_SIG_R1 | STATE_SIG_R2 | STATE_VISITED_R1 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2;
|
|
|
|
/// <summary>The mask to obtain the ZC_LUT index from the state information </summary>
|
|
// This is needed because of the STATE_V_D_SIGN_R1, STATE_V_U_SIGN_R1,
|
|
// STATE_H_R_SIGN_R1, and STATE_H_L_SIGN_R1 bits.
|
|
private const int ZC_MASK = (1 << 8) - 1;
|
|
|
|
/// <summary>The shift to obtain the SC index to 'SC_LUT' from the state
|
|
/// information, for row 1.
|
|
/// </summary>
|
|
private const int SC_SHIFT_R1 = 4;
|
|
|
|
/// <summary>The shift to obtain the SC index to 'SC_LUT' from the state
|
|
/// information, for row 2.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'SC_SHIFT_R2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int SC_SHIFT_R2 = SC_SHIFT_R1 + STATE_SEP;
|
|
|
|
/// <summary>The bit mask to isolate the state bits relative to the sign coding
|
|
/// lookup table ('SC_LUT').
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'SC_MASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int SC_MASK = (1 << SC_LUT_BITS) - 1;
|
|
|
|
/// <summary>The mask to obtain the MR index to 'MR_LUT' from the 'state'
|
|
/// information. It is to be applied after the 'MR_SHIFT'.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'MR_MASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int MR_MASK = (1 << MR_LUT_BITS) - 1;
|
|
|
|
/// <summary>The number of bits used to index in the 'fm' lookup table, 7. The 'fs'
|
|
/// table is indexed with one less bit.
|
|
/// </summary>
|
|
private const int MSE_LKP_BITS = 7;
|
|
|
|
/// <summary>The number of fractional bits used to store data in the 'fm' and 'fs'
|
|
/// lookup tables.
|
|
/// </summary>
|
|
private const int MSE_LKP_FRAC_BITS = 13;
|
|
|
|
/// <summary>Distortion estimation lookup table for bits coded using the sign-code
|
|
/// (SC) primative, for lossy coding (i.e. normal).
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'FS_LOSSY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] FS_LOSSY = new int[1 << (MSE_LKP_BITS - 1)];
|
|
|
|
/// <summary>Distortion estimation lookup table for bits coded using the
|
|
/// magnitude-refinement (MR) primative, for lossy coding (i.e. normal)
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'FM_LOSSY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] FM_LOSSY = new int[1 << MSE_LKP_BITS];
|
|
|
|
/// <summary>Distortion estimation lookup table for bits coded using the sign-code
|
|
/// (SC) primative, for lossless coding and last bit-plane. This table is
|
|
/// different from 'fs_lossy' since when doing lossless coding the residual
|
|
/// distortion after the last bit-plane is coded is strictly 0.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'FS_LOSSLESS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] FS_LOSSLESS = new int[1 << (MSE_LKP_BITS - 1)];
|
|
|
|
/// <summary>Distortion estimation lookup table for bits coded using the
|
|
/// magnitude-refinement (MR) primative, for lossless coding and last
|
|
/// bit-plane. This table is different from 'fs_lossless' since when doing
|
|
/// lossless coding the residual distortion after the last bit-plane is
|
|
/// coded is strictly 0.
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'FM_LOSSLESS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private static readonly int[] FM_LOSSLESS = new int[1 << MSE_LKP_BITS];
|
|
|
|
/// <summary>The buffer for distortion values (avoids reallocation for each
|
|
/// code-block), for each thread.
|
|
/// </summary>
|
|
private double[][] distbufT;
|
|
|
|
/// <summary>The buffer for rate values (avoids reallocation for each
|
|
/// code-block), for each thread.
|
|
/// </summary>
|
|
private int[][] ratebufT;
|
|
|
|
/// <summary>The buffer for indicating terminated passes (avoids reallocation for
|
|
/// each code-block), for each thread.
|
|
/// </summary>
|
|
private bool[][] istermbufT;
|
|
|
|
/// <summary>The source code-block to entropy code (avoids reallocation for each
|
|
/// code-block), for each thread.
|
|
/// </summary>
|
|
private CBlkWTData[] srcblkT;
|
|
|
|
/// <summary>Buffer for symbols to send to the MQ-coder, for each thread. Used to
|
|
/// reduce the number of calls to the MQ coder.
|
|
/// </summary>
|
|
// NOTE: The symbol buffer has not prooved to be of any great improvement
|
|
// in encoding time, but it does not hurt. It's performance should be
|
|
// better studied under different JVMs.
|
|
private int[][] symbufT;
|
|
|
|
/// <summary>Buffer for the contexts to use when sending buffered symbols to the
|
|
/// MQ-coder, for each thread. Used to reduce the number of calls to the MQ
|
|
/// coder.
|
|
/// </summary>
|
|
private int[][] ctxtbufT;
|
|
|
|
/// <summary>boolean used to signal if the precinct partition is used for
|
|
/// each component and each tile.
|
|
/// </summary>
|
|
private bool[][] precinctPartition;
|
|
|
|
//UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'Compressor' to access its enclosing instance. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1019'"
|
|
/// <summary> Class that takes care of running the 'compressCodeBlock()' method with
|
|
/// thread local arguments. Used only in multithreaded implementation.
|
|
///
|
|
/// </summary>
|
|
private class Compressor : IThreadRunnable
|
|
{
|
|
private void InitBlock(StdEntropyCoder enclosingInstance)
|
|
{
|
|
this.enclosingInstance = enclosingInstance;
|
|
}
|
|
private StdEntropyCoder enclosingInstance;
|
|
/// <summary> Returns the index of this compressor.
|
|
///
|
|
/// </summary>
|
|
/// <returns> The index of this compressor.
|
|
///
|
|
/// </returns>
|
|
virtual public int Idx
|
|
{
|
|
get
|
|
{
|
|
return idx;
|
|
}
|
|
|
|
}
|
|
public StdEntropyCoder Enclosing_Instance
|
|
{
|
|
get
|
|
{
|
|
return enclosingInstance;
|
|
}
|
|
|
|
}
|
|
/// <summary>The index of this compressor. Used to access thread local
|
|
/// variables
|
|
/// </summary>
|
|
//UPGRADE_NOTE: Final was removed from the declaration of 'idx '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
|
private int idx;
|
|
|
|
/// <summary>The object where to store the compressed code-block </summary>
|
|
// Should be private, but some buggy JDK 1.1 compilers complain
|
|
internal CBlkRateDistStats ccb;
|
|
|
|
/// <summary>The component on which to compress </summary>
|
|
// Should be private, but some buggy JDK 1.1 compilers complain
|
|
internal int c;
|
|
|
|
/// <summary>The options bitmask to use in compression </summary>
|
|
// Should be private, but some buggy JDK 1.1 compilers complain
|
|
internal int options;
|
|
|
|
/// <summary>The reversible flag to use in compression </summary>
|
|
// Should be private, but some buggy JDK 1.1 compilers complain
|
|
internal bool rev;
|
|
|
|
/// <summary>The length calculation type to use in compression </summary>
|
|
// Should be private, but some buggy JDK 1.1 compilers complain
|
|
internal int lcType;
|
|
|
|
/// <summary>The MQ termination type to use in compression </summary>
|
|
// Should be private, but some buggy JDK 1.1 compilers complain
|
|
internal int tType;
|
|
|
|
/// <summary>The cumulative wall time for this compressor, for each
|
|
/// component.
|
|
/// </summary>
|
|
//private long[] time;
|
|
|
|
/// <summary> Creates a new compressor object with the given index.
|
|
///
|
|
/// </summary>
|
|
/// <param name="idx">The index of this compressor.
|
|
///
|
|
/// </param>
|
|
internal Compressor(StdEntropyCoder enclosingInstance, int idx)
|
|
{
|
|
InitBlock(enclosingInstance);
|
|
this.idx = idx;
|
|
#if DO_TIMING
|
|
time = new long[Enclosing_Instance.src.NumComps];
|
|
#endif
|
|
}
|
|
|
|
/// <summary> Calls the 'compressCodeBlock()' method with thread local
|
|
/// arguments. Once completed it adds itself to the 'completedComps[c]'
|
|
/// stack, where 'c' is the component for which this compressor is
|
|
/// running. This last step occurs even if exceptions are thrown by the
|
|
/// 'compressCodeBlock()' method.
|
|
///
|
|
/// </summary>
|
|
public virtual void Run()
|
|
{
|
|
// Start the code-block compression
|
|
try
|
|
{
|
|
#if DO_TIMING
|
|
long stime = 0L;
|
|
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
|
|
#endif
|
|
CSJ2K.j2k.entropy.encoder.StdEntropyCoder.compressCodeBlock(c, ccb, Enclosing_Instance.srcblkT[idx], Enclosing_Instance.mqT[idx], Enclosing_Instance.boutT[idx], Enclosing_Instance.outT[idx], Enclosing_Instance.stateT[idx], Enclosing_Instance.distbufT[idx], Enclosing_Instance.ratebufT[idx], Enclosing_Instance.istermbufT[idx], Enclosing_Instance.symbufT[idx], Enclosing_Instance.ctxtbufT[idx], options, rev, lcType, tType);
|
|
#if DO_TIMING
|
|
time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
|
|
#endif
|
|
}
|
|
finally
|
|
{
|
|
// Join the queue of completed compression, even if exceptions
|
|
// occurred.
|
|
Enclosing_Instance.completedComps[c].Add(this);
|
|
}
|
|
}
|
|
|
|
/// <summary> Returns the wall time spent by this compressor for component 'c'
|
|
/// since the last call to this method (or the creation of this
|
|
/// compressor if not yet called). If DO_TIMING is false 0 is returned.
|
|
///
|
|
/// </summary>
|
|
/// <returns> The wall time in milliseconds spent by this compressor
|
|
/// since the last call to this method.
|
|
///
|
|
/// </returns>
|
|
//UPGRADE_NOTE: Synchronized keyword was removed from method 'getTiming'. Lock expression was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1027'"
|
|
internal virtual long getTiming(int c)
|
|
{
|
|
#if DO_TIMING
|
|
lock (this)
|
|
{
|
|
long t = time[c];
|
|
time[c] = 0L;
|
|
return t;
|
|
}
|
|
#else
|
|
return 0L;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// <summary> Instantiates a new entropy coder engine, with the specified source of
|
|
/// data, nominal block width and height.
|
|
///
|
|
/// <p>If the 'OPT_PRED_TERM' option is given then the MQ termination must
|
|
/// be 'TERM_PRED_ER' or an exception is thrown.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="src">The source of data
|
|
///
|
|
/// </param>
|
|
/// <param name="cbks">Code-block size specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="pss">Precinct partition specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="bms">By-pass mode specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="mqrs">MQ-reset specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="rts">Regular termination specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="css">Causal stripes specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="sss">Error resolution segment symbol use specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="lcs">Length computation specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="tts">Termination type specifications
|
|
///
|
|
/// </param>
|
|
/// <seealso cref="MQCoder">
|
|
///
|
|
/// </seealso>
|
|
public StdEntropyCoder(CBlkQuantDataSrcEnc src, CBlkSizeSpec cblks, PrecinctSizeSpec pss, StringSpec bms, StringSpec mqrs, StringSpec rts, StringSpec css, StringSpec sss, StringSpec lcs, StringSpec tts):base(src)
|
|
{
|
|
this.cblks = cblks;
|
|
this.pss = pss;
|
|
this.bms = bms;
|
|
this.mqrs = mqrs;
|
|
this.rts = rts;
|
|
this.css = css;
|
|
this.sss = sss;
|
|
this.lcs = lcs;
|
|
this.tts = tts;
|
|
int maxCBlkWidth, maxCBlkHeight;
|
|
int i; // Counter
|
|
int nt; // The number of threads
|
|
int tsl; // Size for thread structures
|
|
|
|
// Get the biggest width/height for the code-blocks
|
|
maxCBlkWidth = cblks.MaxCBlkWidth;
|
|
maxCBlkHeight = cblks.MaxCBlkHeight;
|
|
|
|
nt = Environment.ProcessorCount;
|
|
/*
|
|
// Get the number of threads to use, or default to one
|
|
try
|
|
{
|
|
//UPGRADE_ISSUE: Method 'java.lang.System.getProperty' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangSystem'"
|
|
nt = System.Int32.Parse(System_Renamed.getProperty(THREADS_PROP_NAME, DEF_THREADS_NUM));
|
|
if (nt < 0)
|
|
throw new System.FormatException();
|
|
}
|
|
catch (System.FormatException e)
|
|
{
|
|
throw new System.ArgumentException("Invalid number of threads " + "for " + "entropy coding in property " + THREADS_PROP_NAME);
|
|
}
|
|
*/
|
|
|
|
// If we do timing create necessary structures
|
|
#if DO_TIMING
|
|
time = new long[src.NumComps];
|
|
// 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);
|
|
#endif
|
|
// If using multithreaded implementation get necessasry objects
|
|
if (nt > 0)
|
|
{
|
|
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.INFO, "Using multithreaded entropy coder " + "with " + nt + " compressor threads.");
|
|
tsl = nt;
|
|
tPool = new ThreadPool(nt, (System.Int32) SupportClass.ThreadClass.Current().Priority + THREADS_PRIORITY_INC, "StdEntropyCoder");
|
|
idleComps = new System.Collections.ArrayList();
|
|
completedComps = new System.Collections.ArrayList[src.NumComps];
|
|
nBusyComps = new int[src.NumComps];
|
|
finishedTileComponent = new bool[src.NumComps];
|
|
for (i = src.NumComps - 1; i >= 0; i--)
|
|
{
|
|
completedComps[i] = new System.Collections.ArrayList();
|
|
}
|
|
for (i = 0; i < nt; i++)
|
|
{
|
|
idleComps.Add(new StdEntropyCoder.Compressor(this, i));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tsl = 1;
|
|
tPool = null;
|
|
idleComps = null;
|
|
completedComps = null;
|
|
nBusyComps = null;
|
|
finishedTileComponent = null;
|
|
}
|
|
|
|
// Allocate data structures
|
|
outT = new ByteOutputBuffer[tsl];
|
|
mqT = new MQCoder[tsl];
|
|
boutT = new BitToByteOutput[tsl];
|
|
stateT = new int[tsl][];
|
|
for (int i2 = 0; i2 < tsl; i2++)
|
|
{
|
|
stateT[i2] = new int[(maxCBlkWidth + 2) * ((maxCBlkHeight + 1) / 2 + 2)];
|
|
}
|
|
symbufT = new int[tsl][];
|
|
for (int i3 = 0; i3 < tsl; i3++)
|
|
{
|
|
symbufT[i3] = new int[maxCBlkWidth * (CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT * 2 + 2)];
|
|
}
|
|
ctxtbufT = new int[tsl][];
|
|
for (int i4 = 0; i4 < tsl; i4++)
|
|
{
|
|
ctxtbufT[i4] = new int[maxCBlkWidth * (CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT * 2 + 2)];
|
|
}
|
|
distbufT = new double[tsl][];
|
|
for (int i5 = 0; i5 < tsl; i5++)
|
|
{
|
|
distbufT[i5] = new double[32 * CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES];
|
|
}
|
|
ratebufT = new int[tsl][];
|
|
for (int i6 = 0; i6 < tsl; i6++)
|
|
{
|
|
ratebufT[i6] = new int[32 * CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES];
|
|
}
|
|
istermbufT = new bool[tsl][];
|
|
for (int i7 = 0; i7 < tsl; i7++)
|
|
{
|
|
istermbufT[i7] = new bool[32 * CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES];
|
|
}
|
|
srcblkT = new CBlkWTData[tsl];
|
|
for (i = 0; i < tsl; i++)
|
|
{
|
|
outT[i] = new ByteOutputBuffer();
|
|
mqT[i] = new MQCoder(outT[i], NUM_CTXTS, MQ_INIT);
|
|
}
|
|
precinctPartition = new bool[src.NumComps][];
|
|
for (int i8 = 0; i8 < src.NumComps; i8++)
|
|
{
|
|
precinctPartition[i8] = new bool[src.getNumTiles()];
|
|
}
|
|
|
|
// Create the subband description for each component and each tile
|
|
//Subband sb = null;
|
|
Coord numTiles = null;
|
|
int nc = NumComps;
|
|
numTiles = src.getNumTiles(numTiles);
|
|
initTileComp(getNumTiles(), nc);
|
|
|
|
for (int c = 0; c < nc; c++)
|
|
{
|
|
for (int tY = 0; tY < numTiles.y; tY++)
|
|
{
|
|
for (int tX = 0; tX < numTiles.x; tX++)
|
|
{
|
|
precinctPartition[c][tIdx] = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DO_TIMING
|
|
/// <summary> Prints the timing information, if collected, and calls 'finalize' on
|
|
/// the super class.
|
|
///
|
|
/// </summary>
|
|
~StdEntropyCoder()
|
|
{
|
|
|
|
int c;
|
|
System.Text.StringBuilder sb;
|
|
|
|
if (tPool == null)
|
|
{
|
|
// Single threaded implementation
|
|
sb = new System.Text.StringBuilder("StdEntropyCoder compression wall " + "clock time:");
|
|
for (c = 0; c < time.Length; c++)
|
|
{
|
|
sb.Append("\n component ");
|
|
sb.Append(c);
|
|
sb.Append(": ");
|
|
sb.Append(time[c]);
|
|
sb.Append(" ms");
|
|
}
|
|
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.INFO, sb.ToString());
|
|
}
|
|
else
|
|
{
|
|
// Multithreaded implementation
|
|
Compressor compr;
|
|
MsgLogger msglog = FacilityManager.getMsgLogger();
|
|
|
|
sb = new System.Text.StringBuilder("StdEntropyCoder manager thread " + "wall clock time:");
|
|
for (c = 0; c < time.Length; c++)
|
|
{
|
|
sb.Append("\n component ");
|
|
sb.Append(c);
|
|
sb.Append(": ");
|
|
sb.Append(time[c]);
|
|
sb.Append(" ms");
|
|
}
|
|
System.Collections.IEnumerator Enum = idleComps.GetEnumerator();
|
|
sb.Append("\nStdEntropyCoder compressor threads wall clock " + "time:");
|
|
//UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
|
|
while (Enum.MoveNext())
|
|
{
|
|
//UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
|
|
compr = (Compressor)(Enum.Current);
|
|
for (c = 0; c < time.Length; c++)
|
|
{
|
|
sb.Append("\n compressor ");
|
|
sb.Append(compr.Idx);
|
|
sb.Append(", component ");
|
|
sb.Append(c);
|
|
sb.Append(": ");
|
|
sb.Append(compr.getTiming(c));
|
|
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
|
|
|
|
/// <summary> Returns the code-block width for the specified tile and component.
|
|
///
|
|
/// </summary>
|
|
/// <param name="t">The tile index
|
|
///
|
|
/// </param>
|
|
/// <param name="c">the component index
|
|
///
|
|
/// </param>
|
|
/// <returns> The code-block width for the specified tile and component
|
|
///
|
|
/// </returns>
|
|
public override int getCBlkWidth(int t, int c)
|
|
{
|
|
return cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, t, c);
|
|
}
|
|
|
|
/// <summary> Returns the code-block height for the specified tile and component.
|
|
///
|
|
/// </summary>
|
|
/// <param name="t">The tile index
|
|
///
|
|
/// </param>
|
|
/// <param name="c">The component index
|
|
///
|
|
/// </param>
|
|
/// <returns> The code-block height for the specified tile and component.
|
|
///
|
|
/// </returns>
|
|
public override int getCBlkHeight(int t, int c)
|
|
{
|
|
return cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, t, c);
|
|
}
|
|
|
|
/// <summary> Returns the next coded code-block in the current tile for the specified
|
|
/// component, as a copy (see below). The order in which code-blocks are
|
|
/// returned is not specified. However each code-block is returned only
|
|
/// once and all code-blocks will be returned if the method is called 'N'
|
|
/// times, where 'N' is the number of code-blocks in the tile. After all
|
|
/// the code-blocks have been returned for the current tile calls to this
|
|
/// method will return 'null'.
|
|
///
|
|
/// <p>When changing the current tile (through 'setTile()' or 'nextTile()')
|
|
/// this method will always return the first code-block, as if this method
|
|
/// was never called before for the new current tile.</p>
|
|
///
|
|
/// <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.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="c">The component for which to return the next code-block.
|
|
///
|
|
/// </param>
|
|
/// <param name="ccb">If non-null this object might be used in returning the coded
|
|
/// code-block in this or any subsequent call to this method. If null a new
|
|
/// one is created and returned. If the 'data' array of 'cbb' is not null
|
|
/// it may be reused to return the compressed data.
|
|
///
|
|
/// </param>
|
|
/// <returns> The next coded 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="CBlkRateDistStats">
|
|
///
|
|
/// </seealso>
|
|
public override CBlkRateDistStats getNextCodeBlock(int c, CBlkRateDistStats ccb)
|
|
{
|
|
#if DO_TIMING
|
|
long stime = 0L; // Start time for timed sections
|
|
#endif
|
|
if (tPool == null)
|
|
{
|
|
// Use single threaded implementation
|
|
// Get code-block data from source
|
|
srcblkT[0] = src.getNextInternCodeBlock(c, srcblkT[0]);
|
|
|
|
#if DO_TIMING
|
|
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
|
|
#endif
|
|
|
|
if (srcblkT[0] == null)
|
|
{
|
|
// We got all code-blocks
|
|
return null;
|
|
}
|
|
// Initialize thread local variables
|
|
if ((opts[tIdx][c] & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && boutT[0] == null)
|
|
{
|
|
boutT[0] = new BitToByteOutput(outT[0]);
|
|
}
|
|
// Initialize output code-block
|
|
if (ccb == null)
|
|
{
|
|
ccb = new CBlkRateDistStats();
|
|
}
|
|
// Compress code-block
|
|
compressCodeBlock(c, ccb, srcblkT[0], mqT[0], boutT[0], outT[0], stateT[0], distbufT[0], ratebufT[0], istermbufT[0], symbufT[0], ctxtbufT[0], opts[tIdx][c], isReversible(tIdx, c), lenCalc[tIdx][c], tType[tIdx][c]);
|
|
|
|
#if DO_TIMING
|
|
time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
|
|
#endif
|
|
|
|
// Return result
|
|
return ccb;
|
|
}
|
|
else
|
|
{
|
|
// Use multiple threaded implementation
|
|
int cIdx; // Compressor idx
|
|
Compressor compr; // Compressor
|
|
|
|
#if DO_TIMING
|
|
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
|
|
#endif
|
|
// Give data to all free compressors, using the current component
|
|
while (!finishedTileComponent[c] && !(idleComps.Count == 0))
|
|
{
|
|
// Get an idle compressor
|
|
compr = (Compressor) SupportClass.StackSupport.Pop(idleComps);
|
|
cIdx = compr.Idx;
|
|
// Get data for the compressor and wake it up
|
|
#if DO_TIMING
|
|
time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
|
|
#endif
|
|
srcblkT[cIdx] = src.getNextInternCodeBlock(c, srcblkT[cIdx]);
|
|
#if DO_TIMING
|
|
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
|
|
#endif
|
|
if (srcblkT[cIdx] != null)
|
|
{
|
|
// Initialize thread local variables
|
|
if ((opts[tIdx][c] & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && boutT[cIdx] == null)
|
|
{
|
|
boutT[cIdx] = new BitToByteOutput(outT[cIdx]);
|
|
}
|
|
// Initialize output code-block and compressor thread
|
|
if (ccb == null)
|
|
ccb = new CBlkRateDistStats();
|
|
compr.ccb = ccb;
|
|
compr.c = c;
|
|
compr.options = opts[tIdx][c];
|
|
compr.rev = isReversible(tIdx, c);
|
|
compr.lcType = lenCalc[tIdx][c];
|
|
compr.tType = tType[tIdx][c];
|
|
nBusyComps[c]++;
|
|
ccb = null;
|
|
// Send compressor to execution in thread pool
|
|
tPool.runTarget(compr, completedComps[c]);
|
|
}
|
|
else
|
|
{
|
|
// We finished with all the code-blocks in the current
|
|
// tile component
|
|
idleComps.Add(compr);
|
|
finishedTileComponent[c] = true;
|
|
}
|
|
}
|
|
// If there are threads for this component which result has not
|
|
// been returned yet, get it
|
|
if (nBusyComps[c] > 0)
|
|
{
|
|
lock (completedComps[c])
|
|
{
|
|
// If no compressor is done, wait until one is
|
|
if ((completedComps[c].Count == 0))
|
|
{
|
|
try
|
|
{
|
|
#if DO_TIMING
|
|
time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
|
|
#endif
|
|
System.Threading.Monitor.Wait(completedComps[c]);
|
|
#if DO_TIMING
|
|
stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
|
|
#endif
|
|
}
|
|
catch (System.Threading.ThreadInterruptedException e)
|
|
{
|
|
}
|
|
}
|
|
// Remove the thread from the completed queue and put it
|
|
// on the idle queue
|
|
compr = (Compressor) SupportClass.StackSupport.Pop(completedComps[c]);
|
|
cIdx = compr.Idx;
|
|
nBusyComps[c]--;
|
|
idleComps.Add(compr);
|
|
// Check targets error condition
|
|
tPool.checkTargetErrors();
|
|
// Get the result of compression and return that.
|
|
#if DO_TIMING
|
|
time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
|
|
#endif
|
|
return compr.ccb;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check targets error condition
|
|
tPool.checkTargetErrors();
|
|
// Printing timing info if necessary
|
|
#if DO_TIMING
|
|
time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime;
|
|
#endif
|
|
// Nothing is running => no more code-blocks
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> Changes the current tile, given the new indexes. An
|
|
/// IllegalArgumentException is thrown if the indexes do not correspond to
|
|
/// a valid tile.
|
|
///
|
|
/// <p>This default implementation just changes the tile in the source.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="x">The horizontal index of the tile.
|
|
///
|
|
/// </param>
|
|
/// <param name="y">The vertical index of the new tile.
|
|
///
|
|
/// </param>
|
|
public override void setTile(int x, int y)
|
|
{
|
|
base.setTile(x, y);
|
|
// Reset the tile specific variables
|
|
if (finishedTileComponent != null)
|
|
{
|
|
for (int c = src.NumComps - 1; c >= 0; c--)
|
|
{
|
|
finishedTileComponent[c] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> Advances to the next tile, in standard scan-line order (by rows then
|
|
/// columns). An NoNextElementException is thrown if the current tile is
|
|
/// the last one (i.e. there is no next tile).
|
|
///
|
|
/// <p>This default implementation just advances to the next tile in the
|
|
/// source.</p>
|
|
///
|
|
/// </summary>
|
|
public override void nextTile()
|
|
{
|
|
// Reset the tilespecific variables
|
|
if (finishedTileComponent != null)
|
|
{
|
|
for (int c = src.NumComps - 1; c >= 0; c--)
|
|
{
|
|
finishedTileComponent[c] = false;
|
|
}
|
|
}
|
|
base.nextTile();
|
|
}
|
|
|
|
|
|
/// <summary> Compresses the code-block in 'srcblk' and puts the results in 'ccb',
|
|
/// using the specified options and temporary storage.
|
|
///
|
|
/// </summary>
|
|
/// <param name="c">The component for which to return the next code-block.
|
|
///
|
|
/// </param>
|
|
/// <param name="ccb">The object where the compressed data will be stored. If the
|
|
/// 'data' array of 'cbb' is not null it may be reused to return the
|
|
/// compressed data.
|
|
///
|
|
/// </param>
|
|
/// <param name="srcblk">The code-block data to code
|
|
///
|
|
/// </param>
|
|
/// <param name="mq">The MQ-coder to use
|
|
///
|
|
/// </param>
|
|
/// <param name="bout">The bit level output to use. Used only if 'OPT_BYPASS' is
|
|
/// turned on in the 'options' argument.
|
|
///
|
|
/// </param>
|
|
/// <param name="out">The byte buffer trough which the compressed data is stored.
|
|
///
|
|
/// </param>
|
|
/// <param name="state">The state information for the code-block
|
|
///
|
|
/// </param>
|
|
/// <param name="distbuf">The buffer where to store the distortion at
|
|
/// the end of each coding pass.
|
|
///
|
|
/// </param>
|
|
/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at
|
|
/// the end of each coding pass.
|
|
///
|
|
/// </param>
|
|
/// <param name="istermbuf">The buffer where to store the terminated flag for each
|
|
/// coding pass.
|
|
///
|
|
/// </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="options">The options to use when coding this code-block
|
|
///
|
|
/// </param>
|
|
/// <param name="rev">The reversible flag. Should be true if the source of this
|
|
/// code-block's data is reversible.
|
|
///
|
|
/// </param>
|
|
/// <param name="lcType">The type of length calculation to use with the MQ coder.
|
|
///
|
|
/// </param>
|
|
/// <param name="tType">The type of termination to use with the MQ coder.
|
|
///
|
|
/// </param>
|
|
/// <seealso cref="getNextCodeBlock">
|
|
///
|
|
/// </seealso>
|
|
static private void compressCodeBlock(int c, CBlkRateDistStats ccb, CBlkWTData srcblk, MQCoder mq, BitToByteOutput bout, ByteOutputBuffer out_Renamed, int[] state, double[] distbuf, int[] ratebuf, bool[] istermbuf, int[] symbuf, int[] ctxtbuf, int options, bool rev, int lcType, int tType)
|
|
{
|
|
// NOTE: This method should not access any non-final instance or
|
|
// static variables, either directly or indirectly through other
|
|
// methods in order to be sure that the method is thread safe.
|
|
|
|
int[] zc_lut; // The ZC lookup table to use
|
|
int skipbp; // The number of non-significant bit-planes to skip
|
|
int curbp; // The current magnitude bit-plane (starts at 30)
|
|
int[] fm; // The distortion estimation lookup table for MR
|
|
int[] fs; // The distortion estimation lookup table for SC
|
|
int lmb; // The least significant magnitude bit
|
|
int npass; // The number of coding passes, for R-D statistics
|
|
double msew; // The distortion (MSE weight) for the current bit-plane
|
|
double totdist; // The total cumulative distortion decrease
|
|
int ltpidx; // The index of the last pass which is terminated
|
|
|
|
// Check error-resilient termination
|
|
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0 && tType != MQCoder.TERM_PRED_ER)
|
|
{
|
|
throw new System.ArgumentException("Embedded error-resilient info " + "in MQ termination option " + "specified but incorrect MQ " + "termination " + "policy specified");
|
|
}
|
|
// Set MQ flags
|
|
mq.LenCalcType = lcType;
|
|
mq.TermType = tType;
|
|
|
|
lmb = 30 - srcblk.magbits + 1;
|
|
// If there are more bit-planes to code than the implementation
|
|
// bit-depth set lmb to 0
|
|
lmb = (lmb < 0)?0:lmb;
|
|
|
|
// Reset state
|
|
ArrayUtil.intArraySet(state, 0);
|
|
|
|
// Find the most significant bit-plane
|
|
skipbp = calcSkipMSBP(srcblk, lmb);
|
|
|
|
// Initialize output code-block
|
|
ccb.m = srcblk.m;
|
|
ccb.n = srcblk.n;
|
|
ccb.sb = srcblk.sb;
|
|
ccb.nROIcoeff = srcblk.nROIcoeff;
|
|
ccb.skipMSBP = skipbp;
|
|
if (ccb.nROIcoeff != 0)
|
|
{
|
|
ccb.nROIcp = 3 * (srcblk.nROIbp - skipbp - 1) + 1;
|
|
}
|
|
else
|
|
{
|
|
ccb.nROIcp = 0;
|
|
}
|
|
|
|
// Choose correct ZC lookup table for global orientation
|
|
switch (srcblk.sb.orientation)
|
|
{
|
|
|
|
case Subband.WT_ORIENT_HL:
|
|
zc_lut = ZC_LUT_HL;
|
|
break;
|
|
|
|
case Subband.WT_ORIENT_LL:
|
|
case Subband.WT_ORIENT_LH:
|
|
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");
|
|
|
|
}
|
|
|
|
// Loop on significant magnitude bit-planes doing the 3 passes
|
|
curbp = 30 - skipbp;
|
|
fs = FS_LOSSY;
|
|
fm = FM_LOSSY;
|
|
msew = System.Math.Pow(2, ((curbp - lmb) << 1) - MSE_LKP_FRAC_BITS) * srcblk.sb.stepWMSE * srcblk.wmseScaling;
|
|
totdist = 0f;
|
|
npass = 0;
|
|
ltpidx = - 1;
|
|
|
|
// First significant bit-plane has only the pass pass
|
|
if (curbp >= lmb)
|
|
{
|
|
// Do we need the "lossless" 'fs' table ?
|
|
if (rev && curbp == lmb)
|
|
{
|
|
fs = FM_LOSSLESS;
|
|
}
|
|
// We terminate if regular termination, last bit-plane, or next
|
|
// bit-plane is "raw".
|
|
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || curbp == lmb || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp) >= curbp);
|
|
totdist += cleanuppass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
|
|
distbuf[npass] = totdist;
|
|
if (istermbuf[npass])
|
|
ltpidx = npass;
|
|
npass++;
|
|
msew *= 0.25;
|
|
curbp--;
|
|
}
|
|
// Other bit-planes have all passes
|
|
while (curbp >= lmb)
|
|
{
|
|
// Do we need the "lossless" 'fs' and 'fm' tables ?
|
|
if (rev && curbp == lmb)
|
|
{
|
|
fs = FS_LOSSLESS;
|
|
fm = FM_LOSSLESS;
|
|
}
|
|
|
|
// Do the significance propagation pass
|
|
// We terminate if regular termination only
|
|
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0;
|
|
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) == 0 || (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp <= curbp))
|
|
{
|
|
// No bypass coding
|
|
totdist += sigProgPass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
|
|
}
|
|
else
|
|
{
|
|
// Bypass ("raw") coding
|
|
bout.PredTerm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0;
|
|
totdist += rawSigProgPass(srcblk, bout, istermbuf[npass], curbp, state, fs, ratebuf, npass, ltpidx, options) * msew;
|
|
}
|
|
distbuf[npass] = totdist;
|
|
if (istermbuf[npass])
|
|
ltpidx = npass;
|
|
npass++;
|
|
|
|
// Do the magnitude refinement pass
|
|
// We terminate if regular termination or bypass ("raw") coding
|
|
istermbuf[npass] = (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 - skipbp > curbp));
|
|
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) == 0 || (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp <= curbp))
|
|
{
|
|
// No bypass coding
|
|
totdist += magRefPass(srcblk, mq, istermbuf[npass], curbp, state, fm, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
|
|
}
|
|
else
|
|
{
|
|
// Bypass ("raw") coding
|
|
bout.PredTerm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0;
|
|
totdist += rawMagRefPass(srcblk, bout, istermbuf[npass], curbp, state, fm, ratebuf, npass, ltpidx, options) * msew;
|
|
}
|
|
distbuf[npass] = totdist;
|
|
if (istermbuf[npass])
|
|
ltpidx = npass;
|
|
npass++;
|
|
|
|
// Do the clenup pass
|
|
// We terminate if regular termination, last bit-plane, or next
|
|
// bit-plane is "raw".
|
|
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || curbp == lmb || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp) >= curbp);
|
|
totdist += cleanuppass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
|
|
distbuf[npass] = totdist;
|
|
|
|
if (istermbuf[npass])
|
|
ltpidx = npass;
|
|
npass++;
|
|
|
|
// Goto next bit-plane
|
|
msew *= 0.25;
|
|
curbp--;
|
|
}
|
|
|
|
// Copy compressed data and rate-distortion statistics to output
|
|
ccb.data = new byte[out_Renamed.size()];
|
|
out_Renamed.toByteArray(0, out_Renamed.size(), ccb.data, 0);
|
|
checkEndOfPassFF(ccb.data, ratebuf, istermbuf, npass);
|
|
ccb.selectConvexHull(ratebuf, distbuf, (options & (CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS | CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS)) != 0?istermbuf:null, npass, rev);
|
|
|
|
// Reset MQ coder and bit output for next code-block
|
|
mq.reset();
|
|
if (bout != null)
|
|
bout.reset();
|
|
}
|
|
|
|
/// <summary> Calculates the number of magnitude bit-planes that are to be skipped,
|
|
/// because they are non-significant. The algorithm looks for the largest
|
|
/// magnitude and calculates the most significant bit-plane of it.
|
|
///
|
|
/// </summary>
|
|
/// <param name="cblk">The code-block of data to scan
|
|
///
|
|
/// </param>
|
|
/// <param name="lmb">The least significant magnitude bit in the data
|
|
///
|
|
/// </param>
|
|
/// <returns> The number of magnitude bit-planes to skip (i.e. all zero most
|
|
/// significant bit-planes).
|
|
///
|
|
/// </returns>
|
|
static private int calcSkipMSBP(CBlkWTData cblk, int lmb)
|
|
{
|
|
int k, kmax, mask;
|
|
int[] data;
|
|
int maxmag;
|
|
int mag;
|
|
int w, h;
|
|
int msbp;
|
|
int l;
|
|
|
|
data = (int[]) cblk.Data;
|
|
w = cblk.w;
|
|
h = cblk.h;
|
|
|
|
// First look for the maximum magnitude in the code-block
|
|
maxmag = 0;
|
|
// Consider only magnitude bits that are in non-fractional bit-planes.
|
|
mask = 0x7FFFFFFF & (~ ((1 << lmb) - 1));
|
|
for (l = h - 1, k = cblk.offset; l >= 0; l--)
|
|
{
|
|
for (kmax = k + w; k < kmax; k++)
|
|
{
|
|
mag = data[k] & mask;
|
|
if (mag > maxmag)
|
|
maxmag = mag;
|
|
}
|
|
k += cblk.scanw - w;
|
|
}
|
|
// Now calculate the number of all zero most significant
|
|
// bit-planes for the maximum magnitude.
|
|
msbp = 30;
|
|
do
|
|
{
|
|
if (((1 << msbp) & maxmag) != 0)
|
|
break;
|
|
msbp--;
|
|
}
|
|
while (msbp >= lmb);
|
|
|
|
// Return the number of non-significant bit-planes to skip
|
|
return 30 - msbp;
|
|
}
|
|
|
|
/// <summary> Performs the significance propagation pass on the specified data and
|
|
/// bit-plane. It codes all insignificant samples which have, at least, one
|
|
/// of its immediate eight neighbors already significant, using the ZC and
|
|
/// SC primitives as needed. It toggles the "visited" state bit to 1 for
|
|
/// all those 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="fs">The distortion estimation lookup table for SC
|
|
///
|
|
/// </param>
|
|
/// <param name="zc_lut">The ZC lookup table to use in ZC.
|
|
///
|
|
/// </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 sigProgPass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fs, int[] zc_lut, 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 and packed 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 sym; // The symbol to code
|
|
int ctxt; // The context to use
|
|
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
|
|
bool causal; // Flag to indicate if stripe-causal context
|
|
// formation is to be used
|
|
int nstripes; // The number of stripes in the code-block
|
|
int sheight; // Height of the current stripe
|
|
int off_ul, off_ur, off_dr, off_dl; // offsets
|
|
|
|
// 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 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;
|
|
causal = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL) != 0;
|
|
|
|
// Pre-calculate offsets in 'state' for diagonal neighbors
|
|
off_ul = - sscanw - 1; // up-left
|
|
off_ur = - sscanw + 1; // up-right
|
|
off_dr = sscanw + 1; // down-right
|
|
off_dl = sscanw - 1; // down-left
|
|
|
|
// 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 not significant and has a
|
|
// non-zero context (i.e. some neighbor is significant) we can
|
|
// not skip them
|
|
if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0)
|
|
{
|
|
k = sk;
|
|
// Scan first row
|
|
if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1)
|
|
{
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change contexts of
|
|
// previous stripe.
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
}
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R1;
|
|
}
|
|
}
|
|
if (sheight < 2)
|
|
{
|
|
state[j] = csj;
|
|
continue;
|
|
}
|
|
// Scan second row
|
|
if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2)
|
|
{
|
|
k += dscanw;
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R2;
|
|
}
|
|
}
|
|
state[j] = csj;
|
|
}
|
|
// Do half bottom of column
|
|
if (sheight < 3)
|
|
continue;
|
|
j += sscanw;
|
|
csj = state[j];
|
|
// If any of the two samples is not significant and has a
|
|
// non-zero context (i.e. some neighbor is significant) we can
|
|
// not skip them
|
|
if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0)
|
|
{
|
|
k = sk + (dscanw << 1);
|
|
// Scan first row
|
|
if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1)
|
|
{
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R1;
|
|
}
|
|
}
|
|
if (sheight < 4)
|
|
{
|
|
state[j] = csj;
|
|
continue;
|
|
}
|
|
// Scan second row
|
|
if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2)
|
|
{
|
|
k += dscanw;
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R2;
|
|
}
|
|
}
|
|
state[j] = csj;
|
|
}
|
|
}
|
|
// Code all buffered symbols
|
|
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;
|
|
}
|
|
|
|
/// <summary> Performs the significance propagation pass on the specified data and
|
|
/// bit-plane, without using the arithmetic coder. It codes all
|
|
/// insignificant samples which have, at least, one of its immediate eight
|
|
/// neighbors already significant, using the ZC and SC primitives as
|
|
/// needed. It toggles the "visited" state bit to 1 for all those samples.
|
|
///
|
|
/// <p>In this method, the arithmetic coder is bypassed, and raw bits are
|
|
/// directly written in the bit stream (useful when distribution are close
|
|
/// to uniform, for intance, at high bit-rates and at lossless
|
|
/// compression).</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="srcblk">The code-block data to code
|
|
///
|
|
/// </param>
|
|
/// <param name="bout">The bit based output
|
|
///
|
|
/// </param>
|
|
/// <param name="doterm">If true the bit based output is byte aligned 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="fs">The distortion estimation lookup table for SC
|
|
///
|
|
/// </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 rawSigProgPass(CBlkWTData srcblk, BitToByteOutput bout, bool doterm, int bp, int[] state, int[] fs, 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 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 nsym = 0; // Number of symbol
|
|
int sym; // The symbol to code
|
|
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
|
|
bool causal; // Flag to indicate if stripe-causal context
|
|
// formation is to be used
|
|
int nstripes; // The number of stripes in the code-block
|
|
int sheight; // Height of the current stripe
|
|
int off_ul, off_ur, off_dr, off_dl; // offsets
|
|
|
|
// 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 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;
|
|
causal = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL) != 0;
|
|
|
|
// Pre-calculate offsets in 'state' for neighbors
|
|
off_ul = - sscanw - 1; // up-left
|
|
off_ur = - sscanw + 1; // up-right
|
|
off_dr = sscanw + 1; // down-right
|
|
off_dl = sscanw - 1; // down-left
|
|
|
|
// 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 (; sk < stopsk; sk++, sj++)
|
|
{
|
|
// Do half top of column
|
|
j = sj;
|
|
csj = state[j];
|
|
// If any of the two samples is not significant and has a
|
|
// non-zero context (i.e. some neighbor is significant) we can
|
|
// not skip them
|
|
if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0)
|
|
{
|
|
k = sk;
|
|
// Scan first row
|
|
if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1)
|
|
{
|
|
// Apply zero coding
|
|
sym = SupportClass.URShift((data[k] & mask), bp);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
if (sym != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change contexts of
|
|
// previous stripe.
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
}
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R1;
|
|
}
|
|
}
|
|
if (sheight < 2)
|
|
{
|
|
state[j] = csj;
|
|
continue;
|
|
}
|
|
// Scan second row
|
|
if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2)
|
|
{
|
|
k += dscanw;
|
|
// Apply zero coding
|
|
sym = SupportClass.URShift((data[k] & mask), bp);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
if (sym != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R2;
|
|
}
|
|
}
|
|
state[j] = csj;
|
|
}
|
|
// Do half bottom of column
|
|
if (sheight < 3)
|
|
continue;
|
|
j += sscanw;
|
|
csj = state[j];
|
|
// If any of the two samples is not significant and has a
|
|
// non-zero context (i.e. some neighbor is significant) we can
|
|
// not skip them
|
|
if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0)
|
|
{
|
|
k = sk + (dscanw << 1);
|
|
// Scan first row
|
|
if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1)
|
|
{
|
|
sym = SupportClass.URShift((data[k] & mask), bp);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
if (sym != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R1;
|
|
}
|
|
}
|
|
if (sheight < 4)
|
|
{
|
|
state[j] = csj;
|
|
continue;
|
|
}
|
|
if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2)
|
|
{
|
|
k += dscanw;
|
|
// Apply zero coding
|
|
sym = SupportClass.URShift((data[k] & mask), bp);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
if (sym != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
bout.writeBit(sym);
|
|
nsym++;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_VISITED_R2;
|
|
}
|
|
}
|
|
state[j] = csj;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get length and terminate if needed
|
|
if (doterm)
|
|
{
|
|
ratebuf[pidx] = bout.terminate();
|
|
}
|
|
else
|
|
{
|
|
ratebuf[pidx] = bout.length();
|
|
}
|
|
// Add length of previous segments, if any
|
|
if (ltpidx >= 0)
|
|
{
|
|
ratebuf[pidx] += ratebuf[ltpidx];
|
|
}
|
|
|
|
// Return the reduction in distortion
|
|
return dist;
|
|
}
|
|
|
|
/// <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;
|
|
}
|
|
|
|
/// <summary> Performs the magnitude refinement pass on the specified data and
|
|
/// bit-plane, without using the arithmetic coder. 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.
|
|
///
|
|
/// <p>In this method, the arithmetic coder is bypassed, and raw bits are
|
|
/// directly written in the bit stream (useful when distribution are close
|
|
/// to uniform, for intance, at high bit-rates and at lossless
|
|
/// compression). The 'STATE_PREV_MR_R1' and 'STATE_PREV_MR_R2' bits are
|
|
/// not set because they are used only when the arithmetic coder is not
|
|
/// bypassed.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="srcblk">The code-block data to code
|
|
///
|
|
/// </param>
|
|
/// <param name="bout">The bit based output
|
|
///
|
|
/// </param>
|
|
/// <param name="doterm">If true the bit based output is byte aligned 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="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 rawMagRefPass(CBlkWTData srcblk, BitToByteOutput bout, bool doterm, int bp, int[] state, int[] fm, 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 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
|
|
int nsym = 0;
|
|
|
|
// 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 (; 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)
|
|
{
|
|
// Code bit "raw"
|
|
bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
|
|
nsym++;
|
|
// No need to set STATE_PREV_MR_R1 since all magnitude
|
|
// refinement passes to follow are "raw"
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
|
|
}
|
|
if (sheight < 2)
|
|
continue;
|
|
// Scan second row
|
|
if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
|
|
{
|
|
k += dscanw;
|
|
// Code bit "raw"
|
|
bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
|
|
nsym++;
|
|
// No need to set STATE_PREV_MR_R2 since all magnitude
|
|
// refinement passes to follow are "raw"
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
|
|
}
|
|
}
|
|
// 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)
|
|
{
|
|
// Code bit "raw"
|
|
bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
|
|
nsym++;
|
|
// No need to set STATE_PREV_MR_R1 since all magnitude
|
|
// refinement passes to follow are "raw"
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
|
|
}
|
|
if (sheight < 4)
|
|
continue;
|
|
// Scan second row
|
|
if ((state[j] & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
|
|
{
|
|
k += dscanw;
|
|
// Code bit "raw"
|
|
bout.writeBit(SupportClass.URShift((data[k] & mask), bp));
|
|
nsym++;
|
|
// No need to set STATE_PREV_MR_R2 since all magnitude
|
|
// refinement passes to follow are "raw"
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get length and terminate if needed
|
|
if (doterm)
|
|
{
|
|
ratebuf[pidx] = bout.terminate();
|
|
}
|
|
else
|
|
{
|
|
ratebuf[pidx] = bout.length();
|
|
}
|
|
|
|
// Add length of previous segments, if any
|
|
if (ltpidx >= 0)
|
|
{
|
|
ratebuf[pidx] += ratebuf[ltpidx];
|
|
}
|
|
|
|
// Return the reduction in distortion
|
|
return dist;
|
|
}
|
|
|
|
/// <summary> Performs the cleanup pass on the specified data and bit-plane. It codes
|
|
/// all insignificant samples which have its "visited" state bit off, using
|
|
/// the ZC, SC, and RLC primitives. It toggles the "visited" state bit to 0
|
|
/// (off) for all samples in the code-block.
|
|
///
|
|
/// </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="fs">The distortion estimation lookup table for SC
|
|
///
|
|
/// </param>
|
|
/// <param name="zc_lut">The ZC lookup table to use in ZC.
|
|
///
|
|
/// </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 cleanuppass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fs, int[] zc_lut, int[] symbuf, int[] ctxtbuf, int[] ratebuf, int pidx, int ltpidx, int options)
|
|
{
|
|
// NOTE: The speedup mode of the MQ coder has been briefly tried to
|
|
// speed up the coding of insignificants RLCs, without any success
|
|
// (i.e. no speedup whatsoever). The use of the speedup mode should be
|
|
// revisisted more in depth and the implementationn of it in MQCoder
|
|
// should be reviewed for optimization opportunities.
|
|
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 sym; // The symbol to code
|
|
int rlclen; // Length of RLC
|
|
int ctxt; // The context to use
|
|
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
|
|
bool causal; // Flag to indicate if stripe-causal context
|
|
// formation is to be used
|
|
int nstripes; // The number of stripes in the code-block
|
|
int sheight; // Height of the current stripe
|
|
int off_ul, off_ur, off_dr, off_dl; // offsets
|
|
|
|
// 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 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;
|
|
causal = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL) != 0;
|
|
|
|
// Pre-calculate offsets in 'state' for diagonal neighbors
|
|
off_ul = - sscanw - 1; // up-left
|
|
off_ur = - sscanw + 1; // up-right
|
|
off_dr = sscanw + 1; // down-right
|
|
off_dl = sscanw - 1; // down-left
|
|
|
|
// 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++)
|
|
{
|
|
// Start column
|
|
j = sj;
|
|
csj = state[j];
|
|
{
|
|
// Check for RLC: if all samples are not significant, not
|
|
// visited and do not have a non-zero context, and column
|
|
// is full height, we do RLC.
|
|
if (csj == 0 && state[j + sscanw] == 0 && sheight == CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT)
|
|
{
|
|
k = sk;
|
|
if ((data[k] & mask) != 0)
|
|
{
|
|
rlclen = 0;
|
|
}
|
|
else if ((data[k += dscanw] & mask) != 0)
|
|
{
|
|
rlclen = 1;
|
|
}
|
|
else if ((data[k += dscanw] & mask) != 0)
|
|
{
|
|
rlclen = 2;
|
|
j += sscanw;
|
|
csj = state[j];
|
|
}
|
|
else if ((data[k += dscanw] & mask) != 0)
|
|
{
|
|
rlclen = 3;
|
|
j += sscanw;
|
|
csj = state[j];
|
|
}
|
|
else
|
|
{
|
|
// Code insignificant RLC
|
|
symbuf[nsym] = 0;
|
|
ctxtbuf[nsym++] = RLC_CTXT;
|
|
// Goto next column
|
|
continue;
|
|
}
|
|
// Code significant RLC
|
|
symbuf[nsym] = 1;
|
|
ctxtbuf[nsym++] = RLC_CTXT;
|
|
// Send MSB bit index
|
|
symbuf[nsym] = rlclen >> 1;
|
|
ctxtbuf[nsym++] = UNIF_CTXT;
|
|
// Send LSB bit index
|
|
symbuf[nsym] = rlclen & 0x01;
|
|
ctxtbuf[nsym++] = UNIF_CTXT;
|
|
// Code sign of sample that became significant
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
if ((rlclen & 0x01) == 0)
|
|
{
|
|
// Sample that became significant is first row of
|
|
// its column half
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors, sign
|
|
// of neighbors)
|
|
if (rlclen != 0 || !causal)
|
|
{
|
|
// If in causal mode do not change contexts of
|
|
// previous stripe.
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
}
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
if (rlclen != 0 || !causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
if (rlclen != 0 || !causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Changes to csj are saved later
|
|
if ((rlclen >> 1) != 0)
|
|
{
|
|
// Sample that became significant is in bottom
|
|
// half of column => jump to bottom half
|
|
//UPGRADE_NOTE: Labeled break statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1012'"
|
|
goto top_half_brk;
|
|
}
|
|
// Otherwise sample that became significant is in
|
|
// top half of column => continue on top half
|
|
}
|
|
else
|
|
{
|
|
// Sample that became significant is second row of
|
|
// its column half
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// neighbor significant bit of neighbors, non zero
|
|
// context of neighbors, sign of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Save changes to csj
|
|
state[j] = csj;
|
|
if ((rlclen >> 1) != 0)
|
|
{
|
|
// Sample that became significant is in bottom
|
|
// half of column => we're done with this
|
|
// column
|
|
continue;
|
|
}
|
|
// Otherwise sample that became significant is in
|
|
// top half of column => we're done with top
|
|
// column
|
|
j += sscanw;
|
|
csj = state[j];
|
|
//UPGRADE_NOTE: Labeled break statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1012'"
|
|
goto top_half_brk;
|
|
}
|
|
}
|
|
// Do half top of column
|
|
// If any of the two samples is not significant and has
|
|
// not been visited in the current bit-plane we can not
|
|
// skip them
|
|
if ((((csj >> 1) | csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2)
|
|
{
|
|
k = sk;
|
|
// Scan first row
|
|
if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == 0)
|
|
{
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors,
|
|
// sign of neighbors)
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
}
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
if (!causal)
|
|
{
|
|
// If in causal mode do not change
|
|
// contexts of previous stripe.
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
}
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
}
|
|
if (sheight < 2)
|
|
{
|
|
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
|
|
state[j] = csj;
|
|
continue;
|
|
}
|
|
// Scan second row
|
|
if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == 0)
|
|
{
|
|
k += dscanw;
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors,
|
|
// sign of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
}
|
|
}
|
|
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
|
|
state[j] = csj;
|
|
// Do half bottom of column
|
|
if (sheight < 3)
|
|
continue;
|
|
j += sscanw;
|
|
csj = state[j];
|
|
}
|
|
//UPGRADE_NOTE: Label 'top_half_brk' was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1011'"
|
|
|
|
top_half_brk: ;
|
|
// end of 'top_half' block
|
|
// If any of the two samples is not significant and has
|
|
// not been visited in the current bit-plane we can not
|
|
// skip them
|
|
if ((((csj >> 1) | csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2)
|
|
{
|
|
k = sk + (dscanw << 1);
|
|
// Scan first row
|
|
if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == 0)
|
|
{
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors,
|
|
// sign of neighbors)
|
|
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
|
|
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
|
|
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
}
|
|
if (sheight < 4)
|
|
{
|
|
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
|
|
state[j] = csj;
|
|
continue;
|
|
}
|
|
// Scan second row
|
|
if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == 0)
|
|
{
|
|
k += dscanw;
|
|
// Apply zero coding
|
|
ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
|
|
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
|
|
{
|
|
// Became significant
|
|
// Apply sign coding
|
|
sym = SupportClass.URShift(data[k], 31);
|
|
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
|
|
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
|
|
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
|
|
// Update state information (significant bit,
|
|
// visited bit, neighbor significant bit of
|
|
// neighbors, non zero context of neighbors,
|
|
// sign of neighbors)
|
|
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
|
|
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
|
|
// Update sign state information of neighbors
|
|
if (sym != 0)
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
|
|
}
|
|
else
|
|
{
|
|
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
|
|
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
|
|
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
|
|
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
|
|
}
|
|
// Update distortion
|
|
normval = (data[k] >> downshift) << upshift;
|
|
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
|
|
}
|
|
}
|
|
}
|
|
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
|
|
state[j] = csj;
|
|
}
|
|
// Code all buffered symbols, if any
|
|
if (nsym > 0)
|
|
mq.codeSymbols(symbuf, ctxtbuf, nsym);
|
|
}
|
|
|
|
// Insert a segment marker if we need to
|
|
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS) != 0)
|
|
{
|
|
mq.codeSymbols(SEG_SYMBOLS, SEG_SYMB_CTXTS, SEG_SYMBOLS.Length);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
/// <summary> Ensures that at the end of a non-terminated coding pass there is not a
|
|
/// 0xFF byte, modifying the stored rates if necessary.
|
|
///
|
|
/// <p>Due to error resiliance reasons, a coding pass should never have its
|
|
/// last byte be a 0xFF, since that can lead to the emulation of a resync
|
|
/// marker. This method checks if that is the case, and reduces the rate
|
|
/// for a given pass if necessary. The ommitted 0xFF will be synthetized by
|
|
/// the decoder if necessary, as required by JPEG 2000. This method should
|
|
/// only be called once that the entire code-block is coded.</p>
|
|
///
|
|
/// <p>Passes that are terminated are not checked for the 0xFF byte, since
|
|
/// it is assumed that the termination procedure does not output any
|
|
/// trailing 0xFF. Checking the terminated segments would involve much more
|
|
/// than just modifying the stored rates.</p>
|
|
///
|
|
/// <p>NOTE: It is assumed by this method that the coded data does not
|
|
/// contain consecutive 0xFF bytes, as is the case with the MQ and
|
|
/// 'arithemetic coding bypass' bit stuffing policy. However, the
|
|
/// termination policies used should also respect this requirement.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="data">The coded data for the code-block
|
|
///
|
|
/// </param>
|
|
/// <param name="rates">The rate (i.e. accumulated number of bytes) for each
|
|
/// coding pass
|
|
///
|
|
/// </param>
|
|
/// <param name="isterm">An array of flags indicating, for each pass, if it is
|
|
/// terminated or not. If null it is assumed that no pass is terminated,
|
|
/// except the last one.
|
|
///
|
|
/// </param>
|
|
/// <param name="n">The number of coding passes
|
|
///
|
|
/// </param>
|
|
static private void checkEndOfPassFF(byte[] data, int[] rates, bool[] isterm, int n)
|
|
{
|
|
int dp; // the position to test in 'data'
|
|
|
|
// If a pass ends in 0xFF we need to reduce the number of bytes in it,
|
|
// so that it does not end in 0xFF. We only need to go back one byte
|
|
// since there can be no consecutive 0xFF bytes.
|
|
|
|
// If there are no terminated passes avoid the test on 'isterm'
|
|
if (isterm == null)
|
|
{
|
|
for (n--; n >= 0; n--)
|
|
{
|
|
dp = rates[n] - 1;
|
|
if (dp >= 0 && (data[dp] == (byte)0xFF))
|
|
{
|
|
rates[n]--;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (n--; n >= 0; n--)
|
|
{
|
|
if (!isterm[n])
|
|
{
|
|
dp = rates[n] - 1;
|
|
if (dp >= 0 && (data[dp] == (byte)0xFF))
|
|
{
|
|
rates[n]--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> Load options, length calculation type and termination type for each
|
|
/// tile-component.
|
|
///
|
|
/// </summary>
|
|
/// <param name="nt">The number of tiles
|
|
///
|
|
/// </param>
|
|
/// <param name="nc">The number of components
|
|
///
|
|
/// </param>
|
|
public virtual void initTileComp(int nt, int nc)
|
|
{
|
|
|
|
opts = new int[nt][];
|
|
for (int i2 = 0; i2 < nt; i2++)
|
|
{
|
|
opts[i2] = new int[nc];
|
|
}
|
|
lenCalc = new int[nt][];
|
|
for (int i3 = 0; i3 < nt; i3++)
|
|
{
|
|
lenCalc[i3] = new int[nc];
|
|
}
|
|
tType = new int[nt][];
|
|
for (int i4 = 0; i4 < nt; i4++)
|
|
{
|
|
tType[i4] = new int[nc];
|
|
}
|
|
|
|
for (int t = 0; t < nt; t++)
|
|
{
|
|
for (int c = 0; c < nc; c++)
|
|
{
|
|
opts[t][c] = 0;
|
|
|
|
// Bypass coding mode ?
|
|
if (((System.String) bms.getTileCompVal(t, c)).ToUpper().Equals("on".ToUpper()))
|
|
{
|
|
opts[t][c] |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS;
|
|
}
|
|
// MQ reset after each coding pass ?
|
|
if (((System.String) mqrs.getTileCompVal(t, c)).ToUpper().Equals("on".ToUpper()))
|
|
{
|
|
opts[t][c] |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ;
|
|
}
|
|
// MQ termination after each arithmetically coded coding pass ?
|
|
if (((System.String) rts.getTileCompVal(t, c)).ToUpper().Equals("on".ToUpper()))
|
|
{
|
|
opts[t][c] |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS;
|
|
}
|
|
// Vertically stripe-causal context mode ?
|
|
if (((System.String) css.getTileCompVal(t, c)).ToUpper().Equals("on".ToUpper()))
|
|
{
|
|
opts[t][c] |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL;
|
|
}
|
|
// Error resilience segmentation symbol insertion ?
|
|
if (((System.String) sss.getTileCompVal(t, c)).ToUpper().Equals("on".ToUpper()))
|
|
{
|
|
opts[t][c] |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS;
|
|
}
|
|
|
|
// Set length calculation type of the MQ coder
|
|
System.String lCalcType = (System.String) lcs.getTileCompVal(t, c);
|
|
if (lCalcType.Equals("near_opt"))
|
|
{
|
|
lenCalc[t][c] = MQCoder.LENGTH_NEAR_OPT;
|
|
}
|
|
else if (lCalcType.Equals("lazy_good"))
|
|
{
|
|
lenCalc[t][c] = MQCoder.LENGTH_LAZY_GOOD;
|
|
}
|
|
else if (lCalcType.Equals("lazy"))
|
|
{
|
|
lenCalc[t][c] = MQCoder.LENGTH_LAZY;
|
|
}
|
|
else
|
|
{
|
|
throw new System.ArgumentException("Unrecognized or " + "unsupported MQ " + "length calculation.");
|
|
}
|
|
|
|
// Set termination type of MQ coder
|
|
System.String termType = (System.String) tts.getTileCompVal(t, c);
|
|
if (termType.ToUpper().Equals("easy".ToUpper()))
|
|
{
|
|
tType[t][c] = MQCoder.TERM_EASY;
|
|
}
|
|
else if (termType.ToUpper().Equals("full".ToUpper()))
|
|
{
|
|
tType[t][c] = MQCoder.TERM_FULL;
|
|
}
|
|
else if (termType.ToUpper().Equals("near_opt".ToUpper()))
|
|
{
|
|
tType[t][c] = MQCoder.TERM_NEAR_OPT;
|
|
}
|
|
else if (termType.ToUpper().Equals("predict".ToUpper()))
|
|
{
|
|
tType[t][c] = MQCoder.TERM_PRED_ER;
|
|
opts[t][c] |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM;
|
|
if ((opts[t][c] & (CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS | CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS)) == 0)
|
|
{
|
|
FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.INFO, "Using error resilient MQ" + " termination, but terminating only at " + "the end of code-blocks. The error " + "protection offered by this option will" + " be very weak. Specify the " + "'Cterminate' " + "and/or 'Cbypass' option for " + "increased error resilience.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new System.ArgumentException("Unrecognized or " + "unsupported " + "MQ coder " + "termination.");
|
|
}
|
|
} // End loop on components
|
|
} // End loop on tiles
|
|
}
|
|
|
|
/// <summary> Returns the precinct partition width for the specified component, tile
|
|
/// and resolution level.
|
|
///
|
|
/// </summary>
|
|
/// <param name="t">the tile index
|
|
///
|
|
/// </param>
|
|
/// <param name="c">the component
|
|
///
|
|
/// </param>
|
|
/// <param name="rl">the resolution level
|
|
///
|
|
/// </param>
|
|
/// <returns> The precinct partition width for the specified component, tile
|
|
/// and resolution level
|
|
///
|
|
/// </returns>
|
|
public override int getPPX(int t, int c, int rl)
|
|
{
|
|
return pss.getPPX(t, c, rl);
|
|
}
|
|
|
|
/// <summary> Returns the precinct partition height for the specified component, tile
|
|
/// and resolution level.
|
|
///
|
|
/// </summary>
|
|
/// <param name="t">the tile index
|
|
///
|
|
/// </param>
|
|
/// <param name="c">the component
|
|
///
|
|
/// </param>
|
|
/// <param name="rl">the resolution level
|
|
///
|
|
/// </param>
|
|
/// <returns> The precinct partition height for the specified component, tile
|
|
/// and resolution level
|
|
///
|
|
/// </returns>
|
|
public override int getPPY(int t, int c, int rl)
|
|
{
|
|
return pss.getPPY(t, c, rl);
|
|
}
|
|
|
|
/// <summary> Returns true if precinct partition is used for the specified component
|
|
/// and tile, returns false otherwise.
|
|
///
|
|
/// </summary>
|
|
/// <param name="c">The component
|
|
///
|
|
/// </param>
|
|
/// <param name="t">The tile
|
|
///
|
|
/// </param>
|
|
/// <returns> True if precinct partition is used for the specified component
|
|
/// and tile, returns false otherwise.
|
|
///
|
|
/// </returns>
|
|
public override bool precinctPartitionUsed(int c, int t)
|
|
{
|
|
return precinctPartition[c][t];
|
|
}
|
|
/// <summary>Static initializer: initializes all the lookup tables. </summary>
|
|
static StdEntropyCoder()
|
|
{
|
|
{
|
|
int i, j;
|
|
double val, deltaMSE;
|
|
int[] inter_sc_lut;
|
|
int ds, us, rs, ls;
|
|
int dsgn, usgn, rsgn, lsgn;
|
|
int h, v;
|
|
|
|
// Initialize the zero coding lookup tables
|
|
|
|
// LH
|
|
|
|
// - No neighbors significant
|
|
ZC_LUT_LH[0] = 2;
|
|
|
|
// - No horizontal or vertical neighbors significant
|
|
for (i = 1; i < 16; i++)
|
|
{
|
|
// Two or more diagonal coeffs significant
|
|
ZC_LUT_LH[i] = 4;
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
// Only one diagonal coeff significant
|
|
ZC_LUT_LH[1 << i] = 3;
|
|
}
|
|
// - No horizontal neighbors significant, diagonal irrelevant
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
// Only one vertical coeff significant
|
|
ZC_LUT_LH[STATE_V_U_R1 | i] = 5;
|
|
ZC_LUT_LH[STATE_V_D_R1 | i] = 5;
|
|
// The two vertical coeffs significant
|
|
ZC_LUT_LH[STATE_V_U_R1 | STATE_V_D_R1 | i] = 6;
|
|
}
|
|
// - One horiz. neighbor significant, diagonal/vertical non-significant
|
|
ZC_LUT_LH[STATE_H_L_R1] = 7;
|
|
ZC_LUT_LH[STATE_H_R_R1] = 7;
|
|
// - One horiz. significant, no vertical significant, one or more
|
|
// diagonal significant
|
|
for (i = 1; i < 16; i++)
|
|
{
|
|
ZC_LUT_LH[STATE_H_L_R1 | i] = 8;
|
|
ZC_LUT_LH[STATE_H_R_R1 | i] = 8;
|
|
}
|
|
// - One horiz. significant, one or more vertical significant,
|
|
// diagonal irrelevant
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
ZC_LUT_LH[STATE_H_L_R1 | (i << 4) | j] = 9;
|
|
ZC_LUT_LH[STATE_H_R_R1 | (i << 4) | j] = 9;
|
|
}
|
|
}
|
|
// - Two horiz. significant, others irrelevant
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
ZC_LUT_LH[STATE_H_L_R1 | STATE_H_R_R1 | i] = 10;
|
|
}
|
|
|
|
// HL
|
|
|
|
// - No neighbors significant
|
|
ZC_LUT_HL[0] = 2;
|
|
// - No horizontal or vertical neighbors significant
|
|
for (i = 1; i < 16; i++)
|
|
{
|
|
// Two or more diagonal coeffs significant
|
|
ZC_LUT_HL[i] = 4;
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
// Only one diagonal coeff significant
|
|
ZC_LUT_HL[1 << i] = 3;
|
|
}
|
|
// - No vertical significant, diagonal irrelevant
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
// One horiz. significant
|
|
ZC_LUT_HL[STATE_H_L_R1 | i] = 5;
|
|
ZC_LUT_HL[STATE_H_R_R1 | i] = 5;
|
|
// Two horiz. significant
|
|
ZC_LUT_HL[STATE_H_L_R1 | STATE_H_R_R1 | i] = 6;
|
|
}
|
|
// - One vert. significant, diagonal/horizontal non-significant
|
|
ZC_LUT_HL[STATE_V_U_R1] = 7;
|
|
ZC_LUT_HL[STATE_V_D_R1] = 7;
|
|
// - One vert. significant, horizontal non-significant, one or more
|
|
// diag. significant
|
|
for (i = 1; i < 16; i++)
|
|
{
|
|
ZC_LUT_HL[STATE_V_U_R1 | i] = 8;
|
|
ZC_LUT_HL[STATE_V_D_R1 | i] = 8;
|
|
}
|
|
// - One vertical significant, one or more horizontal significant,
|
|
// diagonal irrelevant
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
ZC_LUT_HL[(i << 6) | STATE_V_U_R1 | j] = 9;
|
|
ZC_LUT_HL[(i << 6) | STATE_V_D_R1 | j] = 9;
|
|
}
|
|
}
|
|
// - Two vertical significant, others irrelevant
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
ZC_LUT_HL[(i << 6) | STATE_V_U_R1 | STATE_V_D_R1 | j] = 10;
|
|
}
|
|
}
|
|
|
|
// HH
|
|
int[] twoBits = new int[]{3, 5, 6, 9, 10, 12}; // Figures (between 0 and 15)
|
|
// countaning 2 and only 2 bits on in its binary representation.
|
|
|
|
int[] oneBit = new int[]{1, 2, 4, 8}; // Figures (between 0 and 15)
|
|
// countaning 1 and only 1 bit on in its binary representation.
|
|
|
|
int[] twoLeast = new int[]{3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}; // Figures
|
|
// (between 0 and 15) countaining, at least, 2 bits on in its
|
|
// binary representation.
|
|
|
|
int[] threeLeast = new int[]{7, 11, 13, 14, 15}; // Figures
|
|
// (between 0 and 15) countaining, at least, 3 bits on in its
|
|
// binary representation.
|
|
|
|
// - None significant
|
|
ZC_LUT_HH[0] = 2;
|
|
|
|
// - One horizontal+vertical significant, none diagonal
|
|
for (i = 0; i < oneBit.Length; i++)
|
|
ZC_LUT_HH[oneBit[i] << 4] = 3;
|
|
|
|
// - Two or more horizontal+vertical significant, diagonal non-signif
|
|
for (i = 0; i < twoLeast.Length; i++)
|
|
ZC_LUT_HH[twoLeast[i] << 4] = 4;
|
|
|
|
// - One diagonal significant, horiz./vert. non-significant
|
|
for (i = 0; i < oneBit.Length; i++)
|
|
ZC_LUT_HH[oneBit[i]] = 5;
|
|
|
|
// - One diagonal significant, one horiz.+vert. significant
|
|
for (i = 0; i < oneBit.Length; i++)
|
|
for (j = 0; j < oneBit.Length; j++)
|
|
ZC_LUT_HH[(oneBit[i] << 4) | oneBit[j]] = 6;
|
|
|
|
// - One diag signif, two or more horiz+vert signif
|
|
for (i = 0; i < twoLeast.Length; i++)
|
|
for (j = 0; j < oneBit.Length; j++)
|
|
ZC_LUT_HH[(twoLeast[i] << 4) | oneBit[j]] = 7;
|
|
|
|
// - Two diagonal significant, none horiz+vert significant
|
|
for (i = 0; i < twoBits.Length; i++)
|
|
ZC_LUT_HH[twoBits[i]] = 8;
|
|
|
|
// - Two diagonal significant, one or more horiz+vert significant
|
|
for (j = 0; j < twoBits.Length; j++)
|
|
for (i = 1; i < 16; i++)
|
|
ZC_LUT_HH[(i << 4) | twoBits[j]] = 9;
|
|
|
|
// - Three or more diagonal significant, horiz+vert irrelevant
|
|
for (i = 0; i < 16; i++)
|
|
for (j = 0; j < threeLeast.Length; j++)
|
|
ZC_LUT_HH[(i << 4) | threeLeast[j]] = 10;
|
|
|
|
// Initialize the SC lookup tables
|
|
|
|
// Use an intermediate sign code lookup table that is similar to the
|
|
// one in the VM text, in that it depends on the 'h' and 'v'
|
|
// quantities. The index into this table is a 6 bit index, the top 3
|
|
// bits are (h+1) and the low 3 bits (v+1).
|
|
inter_sc_lut = new int[36];
|
|
inter_sc_lut[(2 << 3) | 2] = 15;
|
|
inter_sc_lut[(2 << 3) | 1] = 14;
|
|
inter_sc_lut[(2 << 3) | 0] = 13;
|
|
inter_sc_lut[(1 << 3) | 2] = 12;
|
|
inter_sc_lut[(1 << 3) | 1] = 11;
|
|
inter_sc_lut[(1 << 3) | 0] = 12 | INT_SIGN_BIT;
|
|
inter_sc_lut[(0 << 3) | 2] = 13 | INT_SIGN_BIT;
|
|
inter_sc_lut[(0 << 3) | 1] = 14 | INT_SIGN_BIT;
|
|
inter_sc_lut[(0 << 3) | 0] = 15 | INT_SIGN_BIT;
|
|
|
|
// Using the intermediate sign code lookup table create the final
|
|
// one. The index into this table is a 9 bit index, the low 4 bits are
|
|
// the significance of the 4 horizontal/vertical neighbors, while the
|
|
// top 4 bits are the signs of those neighbors. The bit in the middle
|
|
// is ignored. This index arrangement matches the state bits in the
|
|
// 'state' array, thus direct addressing of the table can be done from
|
|
// the sate information.
|
|
for (i = 0; i < (1 << SC_LUT_BITS) - 1; i++)
|
|
{
|
|
ds = i & 0x01; // significance of down neighbor
|
|
us = (i >> 1) & 0x01; // significance of up neighbor
|
|
rs = (i >> 2) & 0x01; // significance of right neighbor
|
|
ls = (i >> 3) & 0x01; // significance of left neighbor
|
|
dsgn = (i >> 5) & 0x01; // sign of down neighbor
|
|
usgn = (i >> 6) & 0x01; // sign of up neighbor
|
|
rsgn = (i >> 7) & 0x01; // sign of right neighbor
|
|
lsgn = (i >> 8) & 0x01; // sign of left neighbor
|
|
// Calculate 'h' and 'v' as in VM text
|
|
h = ls * (1 - 2 * lsgn) + rs * (1 - 2 * rsgn);
|
|
h = (h >= - 1)?h:- 1;
|
|
h = (h <= 1)?h:1;
|
|
v = us * (1 - 2 * usgn) + ds * (1 - 2 * dsgn);
|
|
v = (v >= - 1)?v:- 1;
|
|
v = (v <= 1)?v:1;
|
|
// Get context and sign predictor from 'inter_sc_lut'
|
|
SC_LUT[i] = inter_sc_lut[(h + 1) << 3 | (v + 1)];
|
|
}
|
|
inter_sc_lut = null;
|
|
|
|
// Initialize the MR lookup tables
|
|
|
|
// None significant, prev MR off
|
|
MR_LUT[0] = 16;
|
|
// One or more significant, prev MR off
|
|
for (i = 1; i < (1 << (MR_LUT_BITS - 1)); i++)
|
|
{
|
|
MR_LUT[i] = 17;
|
|
}
|
|
// Previous MR on, significance irrelevant
|
|
for (; i < (1 << MR_LUT_BITS); i++)
|
|
{
|
|
MR_LUT[i] = 18;
|
|
}
|
|
|
|
// Initialize the distortion estimation lookup tables
|
|
|
|
// fs tables
|
|
for (i = 0; i < (1 << (MSE_LKP_BITS - 1)); i++)
|
|
{
|
|
// In fs we index by val-1, since val is really: 1 <= val < 2
|
|
val = (double) i / (1 << (MSE_LKP_BITS - 1)) + 1.0;
|
|
deltaMSE = val * val;
|
|
//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'"
|
|
FS_LOSSLESS[i] = (int) System.Math.Floor(deltaMSE * ((double) (1 << MSE_LKP_FRAC_BITS)) + 0.5);
|
|
val -= 1.5;
|
|
deltaMSE -= val * val;
|
|
//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'"
|
|
FS_LOSSY[i] = (int) System.Math.Floor(deltaMSE * ((double) (1 << MSE_LKP_FRAC_BITS)) + 0.5);
|
|
}
|
|
|
|
// fm tables
|
|
for (i = 0; i < (1 << MSE_LKP_BITS); i++)
|
|
{
|
|
val = (double) i / (1 << (MSE_LKP_BITS - 1));
|
|
deltaMSE = (val - 1.0) * (val - 1.0);
|
|
//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'"
|
|
FM_LOSSLESS[i] = (int) System.Math.Floor(deltaMSE * ((double) (1 << MSE_LKP_FRAC_BITS)) + 0.5);
|
|
val -= ((i < (1 << (MSE_LKP_BITS - 1)))?0.5:1.5);
|
|
deltaMSE -= val * val;
|
|
//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'"
|
|
FM_LOSSY[i] = (int) System.Math.Floor(deltaMSE * ((double) (1 << MSE_LKP_FRAC_BITS)) + 0.5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |