/* * 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 { /// 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. /// ///

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.

/// ///

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.

/// ///

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).

/// ///

This implementation buffers the symbols and calls the MQ coder only once /// per stripe and per coding pass, to reduce the method call overhead.

/// ///

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.

/// ///

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.

/// ///
/// /// /// /// /// /// /// public class StdEntropyCoder:EntropyCoder { /// Whether to collect timing information or not: false. Used as a compile /// time directive. /// private const bool DO_TIMING = false; /// 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. /// //private long[] time; /// The Java system property name for the number of threads to use: /// jj2000.j2k.entropy.encoder.StdEntropyCoder.nthreads /// public const System.String THREADS_PROP_NAME = "jj2000.j2k.entropy.encoder.StdEntropyCoder.nthreads"; /// The default value for the property in THREADS_PROP_NAME: 0 public const System.String DEF_THREADS_NUM = "0"; /// 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. /// public const int THREADS_PRIORITY_INC = 0; /// The pool of threads, for the threaded implementation. It is null, if /// non threaded implementation is used /// private ThreadPool tPool; /// The queue of idle compressors. Used in multithreaded /// implementation only /// private System.Collections.ArrayList idleComps; /// The queue of completed compressors, for each component. Used /// in multithreaded implementation only. /// private System.Collections.ArrayList[] completedComps; /// The number of busy compressors, for each component. Used in /// multithreaded implementation only. /// private int[] nBusyComps; /// A flag indicating for each component if all the code-blocks of the * /// current tile have been returned. Used in multithreaded implementation /// only. /// private bool[] finishedTileComponent; /// The MQ coder used, for each thread private MQCoder[] mqT; /// The raw bit output used, for each thread private BitToByteOutput[] boutT; /// The output stream used, for each thread private ByteOutputBuffer[] outT; /// The code-block size specifications private CBlkSizeSpec cblks; /// The precinct partition specifications private PrecinctSizeSpec pss; /// By-pass mode specifications public StringSpec bms; /// MQ reset specifications public StringSpec mqrs; /// Regular termination specifications public StringSpec rts; /// Causal stripes specifications public StringSpec css; /// Error resilience segment symbol use specifications public StringSpec sss; /// The length calculation specifications public StringSpec lcs; /// The termination type specifications public StringSpec tts; /// 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 /// /// /// /// /// private int[][] opts = null; /// The length calculation type for each tile-component private int[][] lenCalc = null; /// The termination type for each tile-component private int[][] tType = null; /// Number of bits used for the Zero Coding lookup table private const int ZC_LUT_BITS = 8; /// Zero Coding context lookup tables for the LH global orientation //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]; /// Zero Coding context lookup tables for the HL global orientation //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]; /// Zero Coding context lookup tables for the HH global orientation //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]; /// Number of bits used for the Sign Coding lookup table private const int SC_LUT_BITS = 9; /// 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". /// //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]; /// The mask to obtain the context index from the 'SC_LUT' private const int SC_LUT_MASK = (1 << 4) - 1; /// The shift to obtain the sign predictor from the 'SC_LUT'. It must be /// an unsigned shift. /// private const int SC_SPRED_SHIFT = 31; /// The sign bit for int data private const int INT_SIGN_BIT = 1 << 31; /// The number of bits used for the Magnitude Refinement lookup table private const int MR_LUT_BITS = 9; /// Magnitude Refinement context lookup table //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]; /// The number of contexts used private const int NUM_CTXTS = 19; /// The RLC context private const int RLC_CTXT = 1; /// The UNIFORM context (with a uniform probability distribution which /// does not adapt) /// private const int UNIF_CTXT = 0; /// The initial states for the MQ coder //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}; /// The 4 bits of the error resilience segmentation symbol (1010) //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}; /// The 4 contexts for the error resilience segmentation symbol (always /// the UNIFORM context, UNIF_CTXT) /// //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}; /// 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. /// ///

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).

/// ///

The upper 16 bits the state is stored as in the lower 16 bits, but /// with the bits shifted up by 16.

/// ///

The lower 16 bits are referred to as "row 1" ("R1") while the upper /// 16 bits are referred to as "row 2" ("R2").

/// ///
private int[][] stateT; /* The separation between the upper and lower bits in the state array: 16 * */ private const int STATE_SEP = 16; /// The flag bit for the significance in the state array, for row 1. private const int STATE_SIG_R1 = 1 << 15; /// The flag bit for the "visited" bit in the state array, for row 1. private const int STATE_VISITED_R1 = 1 << 14; /// 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. /// private const int STATE_NZ_CTXT_R1 = 1 << 13; /// 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. /// private const int STATE_H_L_SIGN_R1 = 1 << 12; /// 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. /// private const int STATE_H_R_SIGN_R1 = 1 << 11; /// 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. /// private const int STATE_V_U_SIGN_R1 = 1 << 10; /// 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. /// private const int STATE_V_D_SIGN_R1 = 1 << 9; /// The flag bit for the previous MR primitive applied in the state array, /// for row 1. /// private const int STATE_PREV_MR_R1 = 1 << 8; /// The flag bit for the horizontal-left significance in the state array, /// for row 1. /// private const int STATE_H_L_R1 = 1 << 7; /// The flag bit for the horizontal-right significance in the state array, /// for row 1. /// private const int STATE_H_R_R1 = 1 << 6; /// The flag bit for the vertical-up significance in the state array, for /// row 1. /// private const int STATE_V_U_R1 = 1 << 5; /// The flag bit for the vertical-down significance in the state array, /// for row 1. /// private const int STATE_V_D_R1 = 1 << 4; /// The flag bit for the diagonal up-left significance in the state array, /// for row 1. /// private const int STATE_D_UL_R1 = 1 << 3; /// The flag bit for the diagonal up-right significance in the state /// array, for row 1. /// private const int STATE_D_UR_R1 = 1 << 2; /// The flag bit for the diagonal down-left significance in the state /// array, for row 1. /// private const int STATE_D_DL_R1 = 1 << 1; /// The flag bit for the diagonal down-right significance in the state /// array , for row 1. /// private const int STATE_D_DR_R1 = 1; /// The flag bit for the significance in the state array, for row 2. //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; /// The flag bit for the "visited" bit in the state array, for row 2. //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; /// 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. /// //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; /// 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. /// //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; /// 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. /// //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; /// 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. /// //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; /// 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. /// //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; /// The flag bit for the previous MR primitive applied in the state array, /// for row 2. /// //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; /// The flag bit for the horizontal-left significance in the state array, /// for row 2. /// //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; /// The flag bit for the horizontal-right significance in the state array, /// for row 2. /// //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; /// The flag bit for the vertical-up significance in the state array, for /// row 2. /// //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; /// The flag bit for the vertical-down significance in the state array, /// for row 2. /// //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; /// The flag bit for the diagonal up-left significance in the state array, /// for row 2. /// //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; /// The flag bit for the diagonal up-right significance in the state /// array, for row 2. /// //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; /// The flag bit for the diagonal down-left significance in the state /// array, for row 2. /// //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; /// The flag bit for the diagonal down-right significance in the state /// array , for row 2. /// //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; /// The mask to isolate the significance bits for row 1 and 2 of the state /// array. /// //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; /// The mask to isolate the visited bits for row 1 and 2 of the state /// array. /// //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; /// The mask to isolate the bits necessary to identify RLC coding state /// (significant, visited and non-zero context, for row 1 and 2). /// //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; /// The mask to obtain the ZC_LUT index from the state information // 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; /// The shift to obtain the SC index to 'SC_LUT' from the state /// information, for row 1. /// private const int SC_SHIFT_R1 = 4; /// The shift to obtain the SC index to 'SC_LUT' from the state /// information, for row 2. /// //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; /// The bit mask to isolate the state bits relative to the sign coding /// lookup table ('SC_LUT'). /// //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; /// The mask to obtain the MR index to 'MR_LUT' from the 'state' /// information. It is to be applied after the 'MR_SHIFT'. /// //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; /// The number of bits used to index in the 'fm' lookup table, 7. The 'fs' /// table is indexed with one less bit. /// private const int MSE_LKP_BITS = 7; private const int MSE_LKP_BITS_M1 = 6; /// The number of fractional bits used to store data in the 'fm' and 'fs' /// lookup tables. /// private const int MSE_LKP_FRAC_BITS = 13; /// Distortion estimation lookup table for bits coded using the sign-code /// (SC) primative, for lossy coding (i.e. normal). /// //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_M1]; /// Distortion estimation lookup table for bits coded using the /// magnitude-refinement (MR) primative, for lossy coding (i.e. normal) /// //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]; /// 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. /// //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_M1]; /// 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. /// //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]; /// The buffer for distortion values (avoids reallocation for each /// code-block), for each thread. /// private double[][] distbufT; /// The buffer for rate values (avoids reallocation for each /// code-block), for each thread. /// private int[][] ratebufT; /// The buffer for indicating terminated passes (avoids reallocation for /// each code-block), for each thread. /// private bool[][] istermbufT; /// The source code-block to entropy code (avoids reallocation for each /// code-block), for each thread. /// private CBlkWTData[] srcblkT; /// Buffer for symbols to send to the MQ-coder, for each thread. Used to /// reduce the number of calls to the MQ coder. /// // 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; /// 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. /// private int[][] ctxtbufT; /// boolean used to signal if the precinct partition is used for /// each component and each tile. /// 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'" /// Class that takes care of running the 'compressCodeBlock()' method with /// thread local arguments. Used only in multithreaded implementation. /// /// private class Compressor : IThreadRunnable { private void InitBlock(StdEntropyCoder enclosingInstance) { this.enclosingInstance = enclosingInstance; } private StdEntropyCoder enclosingInstance; /// Returns the index of this compressor. /// /// /// The index of this compressor. /// /// virtual public int Idx { get { return idx; } } public StdEntropyCoder Enclosing_Instance { get { return enclosingInstance; } } /// The index of this compressor. Used to access thread local /// variables /// //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; /// The object where to store the compressed code-block // Should be private, but some buggy JDK 1.1 compilers complain internal CBlkRateDistStats ccb; /// The component on which to compress // Should be private, but some buggy JDK 1.1 compilers complain internal int c; /// The options bitmask to use in compression // Should be private, but some buggy JDK 1.1 compilers complain internal int options; /// The reversible flag to use in compression // Should be private, but some buggy JDK 1.1 compilers complain internal bool rev; /// The length calculation type to use in compression // Should be private, but some buggy JDK 1.1 compilers complain internal int lcType; /// The MQ termination type to use in compression // Should be private, but some buggy JDK 1.1 compilers complain internal int tType; /// The cumulative wall time for this compressor, for each /// component. /// //private long[] time; /// Creates a new compressor object with the given index. /// /// /// The index of this compressor. /// /// internal Compressor(StdEntropyCoder enclosingInstance, int idx) { InitBlock(enclosingInstance); this.idx = idx; #if DO_TIMING time = new long[Enclosing_Instance.src.NumComps]; #endif } /// 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. /// /// 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); } } } /// Instantiates a new entropy coder engine, with the specified source of /// data, nominal block width and height. /// ///

If the 'OPT_PRED_TERM' option is given then the MQ termination must /// be 'TERM_PRED_ER' or an exception is thrown.

/// ///
/// The source of data /// /// /// Code-block size specifications /// /// /// Precinct partition specifications /// /// /// By-pass mode specifications /// /// /// MQ-reset specifications /// /// /// Regular termination specifications /// /// /// Causal stripes specifications /// /// /// Error resolution segment symbol use specifications /// /// /// Length computation specifications /// /// /// Termination type specifications /// /// /// /// /// 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 /// Prints the timing information, if collected, and calls 'finalize' on /// the super class. /// /// ~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 /// Returns the code-block width for the specified tile and component. /// /// /// The tile index /// /// /// the component index /// /// /// The code-block width for the specified tile and component /// /// public override int getCBlkWidth(int t, int c) { return cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, t, c); } /// Returns the code-block height for the specified tile and component. /// /// /// The tile index /// /// /// The component index /// /// /// The code-block height for the specified tile and component. /// /// public override int getCBlkHeight(int t, int c) { return cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, t, c); } /// 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'. /// ///

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.

/// ///

The data returned by this method is always a copy of the internal /// data of this object, if any, and it can be modified "in place" without /// any problems after being returned.

/// ///
/// The component for which to return the next code-block. /// /// /// 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. /// /// /// 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. /// /// /// /// /// 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) { } } // 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; } } } /// Changes the current tile, given the new indexes. An /// IllegalArgumentException is thrown if the indexes do not correspond to /// a valid tile. /// ///

This default implementation just changes the tile in the source.

/// ///
/// The horizontal index of the tile. /// /// /// The vertical index of the new tile. /// /// 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; } } } /// 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). /// ///

This default implementation just advances to the next tile in the /// source.

/// ///
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(); } /// Compresses the code-block in 'srcblk' and puts the results in 'ccb', /// using the specified options and temporary storage. /// /// /// The component for which to return the next code-block. /// /// /// 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. /// /// /// The code-block data to code /// /// /// The MQ-coder to use /// /// /// The bit level output to use. Used only if 'OPT_BYPASS' is /// turned on in the 'options' argument. /// /// /// The byte buffer trough which the compressed data is stored. /// /// /// The state information for the code-block /// /// /// The buffer where to store the distortion at /// the end of each coding pass. /// /// /// The buffer where to store the rate (i.e. coded lenth) at /// the end of each coding pass. /// /// /// The buffer where to store the terminated flag for each /// coding pass. /// /// /// The buffer to hold symbols to send to the MQ coder /// /// /// A buffer to hold the contexts to use in sending the /// buffered symbols to the MQ coder. /// /// /// The options to use when coding this code-block /// /// /// The reversible flag. Should be true if the source of this /// code-block's data is reversible. /// /// /// The type of length calculation to use with the MQ coder. /// /// /// The type of termination to use with the MQ coder. /// /// /// /// /// 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(); } /// 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. /// /// /// The code-block of data to scan /// /// /// The least significant magnitude bit in the data /// /// /// The number of magnitude bit-planes to skip (i.e. all zero most /// significant bit-planes). /// /// 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; } /// 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. /// /// /// The code-block data to code /// /// /// The MQ-coder to use /// /// /// If true it performs an MQ-coder termination after the end /// of the pass /// /// /// The bit-plane to code /// /// /// The state information for the code-block /// /// /// The distortion estimation lookup table for SC /// /// /// The ZC lookup table to use in ZC. /// /// /// The buffer to hold symbols to send to the MQ coder /// /// /// A buffer to hold the contexts to use in sending the /// buffered symbols to the MQ coder. /// /// /// The buffer where to store the rate (i.e. coded lenth) at /// the end of this coding pass. /// /// /// The coding pass index. Is the index in the 'ratebuf' array /// where to store the coded length after this coding pass. /// /// /// The index of the last pass that was terminated, or /// negative if none. /// /// /// The bitmask of entropy coding options to apply to the /// code-block /// /// /// The decrease in distortion for this pass, in the fixed-point /// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables. /// /// 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_M1; 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_M1) - 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_M1) - 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_M1) - 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_M1) - 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; } /// 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. /// ///

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 code-block data to code /// /// /// The bit based output /// /// /// If true the bit based output is byte aligned after the /// end of the pass. /// /// /// The bit-plane to code /// /// /// The state information for the code-block /// /// /// The distortion estimation lookup table for SC /// /// /// The buffer where to store the rate (i.e. coded lenth) at /// the end of this coding pass. /// /// /// The coding pass index. Is the index in the 'ratebuf' array /// where to store the coded length after this coding pass. /// /// /// The index of the last pass that was terminated, or /// negative if none. /// /// /// The bitmask of entropy coding options to apply to the /// code-block /// /// /// The decrease in distortion for this pass, in the fixed-point /// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables. /// /// 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_M1; 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_M1) - 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_M1) - 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_M1) - 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_M1) - 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; } /// 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. /// /// /// The code-block data to code /// /// /// The MQ-coder to use /// /// /// If true it performs an MQ-coder termination after the end /// of the pass /// /// /// The bit-plane to code /// /// /// The state information for the code-block /// /// /// The distortion estimation lookup table for MR /// /// /// The buffer to hold symbols to send to the MQ coder /// /// /// A buffer to hold the contexts to use in sending the /// buffered symbols to the MQ coder. /// /// /// The buffer where to store the rate (i.e. coded lenth) at /// the end of this coding pass. /// /// /// The coding pass index. Is the index in the 'ratebuf' array /// where to store the coded length after this coding pass. /// /// /// The index of the last pass that was terminated, or /// negative if none. /// /// /// The bitmask of entropy coding options to apply to the /// code-block /// /// /// The decrease in distortion for this pass, in the fixed-point /// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables. /// /// 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_M1; 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; } /// 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. /// ///

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.

/// ///
/// The code-block data to code /// /// /// The bit based output /// /// /// If true the bit based output is byte aligned after the /// end of the pass. /// /// /// The bit-plane to code /// /// /// The state information for the code-block /// /// /// The distortion estimation lookup table for MR /// /// /// The buffer where to store the rate (i.e. coded lenth) at /// the end of this coding pass. /// /// /// The coding pass index. Is the index in the 'ratebuf' array /// where to store the coded length after this coding pass. /// /// /// The index of the last pass that was terminated, or /// negative if none. /// /// /// The bitmask of entropy coding options to apply to the /// code-block /// /// /// The decrease in distortion for this pass, in the fixed-point /// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables. /// /// 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_M1; 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; } /// 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. /// /// /// The code-block data to code /// /// /// The MQ-coder to use /// /// /// If true it performs an MQ-coder termination after the end /// of the pass /// /// /// The bit-plane to code /// /// /// The state information for the code-block /// /// /// The distortion estimation lookup table for SC /// /// /// The ZC lookup table to use in ZC. /// /// /// The buffer to hold symbols to send to the MQ coder /// /// /// A buffer to hold the contexts to use in sending the /// buffered symbols to the MQ coder. /// /// /// The buffer where to store the rate (i.e. coded lenth) at /// the end of this coding pass. /// /// /// The coding pass index. Is the index in the 'ratebuf' array /// where to store the coded length after this coding pass. /// /// /// The index of the last pass that was terminated, or /// negative if none. /// /// /// The bitmask of entropy coding options to apply to the /// code-block /// /// /// The decrease in distortion for this pass, in the fixed-point /// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables. /// /// 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_M1; 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_M1) - 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_M1) - 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_M1) - 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_M1) - 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_M1) - 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; } /// Ensures that at the end of a non-terminated coding pass there is not a /// 0xFF byte, modifying the stored rates if necessary. /// ///

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.

/// ///

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.

/// ///

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.

/// ///
/// The coded data for the code-block /// /// /// The rate (i.e. accumulated number of bytes) for each /// coding pass /// /// /// 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. /// /// /// The number of coding passes /// /// 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]--; } } } } } /// Load options, length calculation type and termination type for each /// tile-component. /// /// /// The number of tiles /// /// /// The number of components /// /// 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 } /// Returns the precinct partition width for the specified component, tile /// and resolution level. /// /// /// the tile index /// /// /// the component /// /// /// the resolution level /// /// /// The precinct partition width for the specified component, tile /// and resolution level /// /// public override int getPPX(int t, int c, int rl) { return pss.getPPX(t, c, rl); } /// Returns the precinct partition height for the specified component, tile /// and resolution level. /// /// /// the tile index /// /// /// the component /// /// /// the resolution level /// /// /// The precinct partition height for the specified component, tile /// and resolution level /// /// public override int getPPY(int t, int c, int rl) { return pss.getPPY(t, c, rl); } /// Returns true if precinct partition is used for the specified component /// and tile, returns false otherwise. /// /// /// The component /// /// /// The tile /// /// /// True if precinct partition is used for the specified component /// and tile, returns false otherwise. /// /// public override bool precinctPartitionUsed(int c, int t) { return precinctPartition[c][t]; } /// Static initializer: initializes all the lookup tables. 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_M1); i++) { // In fs we index by val-1, since val is really: 1 <= val < 2 val = (double) i / (1 << MSE_LKP_BITS_M1) + 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_M1); 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_M1))?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); } } } } }