text: /* The copyright in this software is being made available under the BSD
   * License, included below. This software may be subject to other third party
   * and contributor rights, including patent rights, and no such rights are
   * granted under this license.
   *
   * Copyright (c) 2010-2017, ITU/ISO/IEC
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   *  * Redistributions of source code must retain the above copyright notice,
   *    this list of conditions and the following disclaimer.
   *  * Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
   *    be used to endorse or promote products derived from this software without
   *    specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   * THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  /** \file     TypeDef.h
      \brief    Define macros, basic types, new types and enumerations
  */
  
  #ifndef __TYPEDEF__
  #define __TYPEDEF__
  
  #ifndef __COMMONDEF__
  #error Include CommonDef.h not TypeDef.h
  #endif
  
  #include <vector>
  #include <utility>
  #include <sstream>
  #include <cstddef>
  #include <cstring>
  #include <assert.h>
  #include <cassert>
  
  #ifndef QTBT_AS_IN_JEM
  #define QTBT_AS_IN_JEM                                    1
  
  #endif
  #ifndef HEVC_TOOLS
  #define HEVC_TOOLS                                        0
  
  #endif
  
  
  
  #ifndef ENABLE_WPP_PARALLELISM
  #define ENABLE_WPP_PARALLELISM                            0
  #endif
  #if ENABLE_WPP_PARALLELISM
  #ifndef ENABLE_WPP_STATIC_LINK
  #define ENABLE_WPP_STATIC_LINK                            0 // bug fix static link
  #endif
  #define PARL_WPP_MAX_NUM_THREADS                         16
  
  #endif
  #ifndef ENABLE_SPLIT_PARALLELISM
  #define ENABLE_SPLIT_PARALLELISM                          0
  #endif
  #if ENABLE_SPLIT_PARALLELISM
  #define PARL_SPLIT_MAX_NUM_JOBS                           6                             // number of parallel jobs that can be defined and need memory allocated
  #define NUM_RESERVERD_SPLIT_JOBS                        ( PARL_SPLIT_MAX_NUM_JOBS + 1 )  // number of all data structures including the merge thread (0)
  #define PARL_SPLIT_MAX_NUM_THREADS                        PARL_SPLIT_MAX_NUM_JOBS
  #define NUM_SPLIT_THREADS_IF_MSVC                         4
  
  #endif
  
  // ====================================================================================================================
  // NEXT software switches
  // ====================================================================================================================
  
  #ifndef ENABLE_TRACING
  #define ENABLE_TRACING                                    0 // DISABLE by default (enable only when debugging, requires 15% run-time in decoding) -- see documentation in 'doc/DTrace for NextSoftware.pdf'
  
  #endif // ! ENABLE_TRACING
  
  #define WCG_EXT                                           0 // part of JEM sharp Luma qp
  #define WCG_WPSNR                                         WCG_EXT 
  
  #if HEVC_TOOLS
  #define HEVC_USE_RQT                                      0
  #define HEVC_USE_INTRA_SMOOTHING_T32                      1
  #define HEVC_USE_INTRA_SMOOTHING_T64                      1
  #define JEM_USE_INTRA_BOUNDARY                            1
  #define HEVC_USE_DC_PREDFILTERING                         1
  #define HEVC_USE_HOR_VER_PREDFILTERING                    1
  #define HEVC_USE_4x4_DSTVII                               1
  #define HEVC_USE_MDCS                                     1
  #define HEVC_USE_SIGN_HIDING                              1
  #define HEVC_USE_SCALING_LISTS                            1
  #define HEVC_USE_PART_SIZE                              ( 1                       && HEVC_USE_RQT )
  #define HEVC_422                                        ( 1                       && HEVC_USE_RQT )
  #define HEVC_PARTITIONER                                ( 1 && HEVC_USE_PART_SIZE && HEVC_USE_RQT )
  #define HEVC_VPS                                          1
  #define HEVC_DEPENDENT_SLICES                             1
  #define HEVC_TILES_WPP                                    1
  #endif
  
  
  #define KEEP_PRED_AND_RESI_SIGNALS                        0
  
  #define ENABLE_BMS                                        1
  
  #if QTBT_AS_IN_JEM // macros which will cause changes in the decoder behavior ara marked with *** - keep them on to retain compatibility with JEM-toolcheck
  #define HM_REPRODUCE_4x4_BLOCK_ESTIMATION_ORDER           0   // estimate 4x4 blocks as in HM
  #define HM_REPRODUCE_422_CHROMA_CONTEXT_RESET_BUG         1   // reproduce 4:2:2 context reset bug in HM
  #define HM_REPRODUCE_CONTEXT_IDX_CALCULATION              1   // reproduce HM context idx calculation
  #define HM_STORE_FRAC_BITS_AND_USE_ROUNDED_BITS           1   // storage and copying of frac bits in ctx classes
  #define HM_REPRODUCE_RDCOST_CALCULATION                   1   // calculate RD cost as in HM
  #define HM_ME_SR_VIOLATION                                1
  #define HM_POSTPONE_SPLIT_BITS                            1
  #define HM_16_6_BIT_EQUAL                                 1   // reproduce behavior of HM 16.6 rather than 16.13
  #define HM_EQ_MOTION_COST                                 1
  #define HM_NO_ADDITIONAL_SPEEDUPS                         1
  #define HM_NO_ADAPT_PPS_QP                                1   // disable corrected inital QP setup for RA GOP 16
  #define HM_QTBT_AS_IN_JEM                                 1   // ***
  #if     HM_QTBT_AS_IN_JEM
  #define HM_QTBT_AS_IN_JEM_CONTEXT                         1   // ***
  #define HM_QTBT_AS_IN_JEM_SYNTAX                        ( 1 && !( ENABLE_BMS ) ) // *** -- cannot be enabled if ENABLE_BMS is on
  #define HM_QTBT_AS_IN_JEM_QUANT                           1   // ***
  #define HM_QTBT_REPRODUCE_FAST_LCTU_BUG                   1
  #define HM_QTBT_ONLY_QT_IMPLICIT                          1   // ***
  #endif
  #define HM_CODED_CU_INFO                                  1   // like in JEM, when related CU is skipped, it stays like this even if a non skip mode wins...
  #define HM_MDIS_AS_IN_JEM                                 1   // *** - PM: not filtering ref. samples for 64xn case and using Planar MDIS condition at encoder
  #define HM_JEM_MERGE_CANDS                                1   // ***
  
  #endif//JEM_COMP
  
  #if ENABLE_BMS
  #if HM_QTBT_AS_IN_JEM_SYNTAX
  #error HM_QTBT_AS_IN_JEM_SYNTAX cannot be enabled if ENABLE_BMS is enabled
  #endif
  #endif
  #define ENABLE_CHROMA_422                               ( HEVC_422 ) // enables chroma 4:2:2 sampling format for HM, with QTBT it is implicitly handled, so the special handling can be disabled
  
  
  // ====================================================================================================================
  // Debugging
  // ====================================================================================================================
  
  // most debugging tools are now bundled within the ENABLE_TRACING macro -- see documentation to see how to use
  
  #define PRINT_MACRO_VALUES                                1 ///< When enabled, the encoder prints out a list of the non-environment-variable controlled macros and their values on startup
  
  #define INTRA_FULL_SEARCH                                 0 ///< enables full mode search for intra estimation
  
  // TODO: rename this macro to DECODER_DEBUG_BIT_STATISTICS (may currently cause merge issues with other branches)
  // This can be enabled by the makefile
  #ifndef RExt__DECODER_DEBUG_BIT_STATISTICS
  #define RExt__DECODER_DEBUG_BIT_STATISTICS                0 ///< 0 (default) = decoder reports as normal, 1 = decoder produces bit usage statistics (will impact decoder run time by up to ~10%)
  #endif
  
  // ====================================================================================================================
  // Tool Switches - transitory (these macros are likely to be removed in future revisions)
  // ====================================================================================================================
  
  #define DECODER_CHECK_SUBSTREAM_AND_SLICE_TRAILING_BYTES  1 ///< TODO: integrate this macro into a broader conformance checking system.
  #define T0196_SELECTIVE_RDOQ                              1 ///< selective RDOQ
  #define U0040_MODIFIED_WEIGHTEDPREDICTION_WITH_BIPRED_AND_CLIPPING 1
  #define U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI    1 ///< Alternative transfer characteristics SEI message (JCTVC-U0033, with syntax naming from V1005)
  #define X0038_LAMBDA_FROM_QP_CAPABILITY                   1 ///< This approach derives lambda from QP+QPoffset+QPoffset2. QPoffset2 is derived from QP+QPoffset using a linear model that is clipped between 0 and 3.
                                                              // To use this capability enable config parameter LambdaFromQpEnable
  
  // ====================================================================================================================
  // Tool Switches
  // ====================================================================================================================
  
  
  // This can be enabled by the makefile
  #ifndef RExt__HIGH_BIT_DEPTH_SUPPORT
  #define RExt__HIGH_BIT_DEPTH_SUPPORT                      0 ///< 0 (default) use data type definitions for 8-10 bit video, 1 = use larger data types to allow for up to 16-bit video (originally developed as part of N0188)
  #endif
  
  // SIMD optimizations
  #define SIMD_ENABLE                                       1
  #define ENABLE_SIMD_OPT                                 ( SIMD_ENABLE && !RExt__HIGH_BIT_DEPTH_SUPPORT )    ///< SIMD optimizations, no impact on RD performance
  #define ENABLE_SIMD_OPT_MCIF                            ( 1 && ENABLE_SIMD_OPT )                            ///< SIMD optimization for the interpolation filter, no impact on RD performance
  #define ENABLE_SIMD_OPT_BUFFER                          ( 1 && ENABLE_SIMD_OPT )                            ///< SIMD optimization for the buffer operations, no impact on RD performance
  #define ENABLE_SIMD_OPT_DIST                            ( 1 && ENABLE_SIMD_OPT )                            ///< SIMD optimization for the distortion calculations(SAD,SSE,HADAMARD), no impact on RD performance
  // End of SIMD optimizations
  
  #define AMP_ENC_SPEEDUP                                   0 ///< encoder only speed-up by AMP mode skipping
  #if AMP_ENC_SPEEDUP
  #define AMP_MRG                                           1 ///< encoder only force merge for AMP partition (no motion search for AMP)
  #endif
  
  #define ENABLE_RQT_INTRA_SPEEDUP                          0 ///< tests one best mode with full rqt
  #define ENABLE_RQT_INTRA_SPEEDUP_MOD                      0 ///< tests two best modes with full rqt
  
  #if ENABLE_RQT_INTRA_SPEEDUP_MOD && !ENABLE_RQT_INTRA_SPEEDUP
  #error
  #endif
  
  #if HM_16_6_BIT_EQUAL
  #define ME_ENABLE_ROUNDING_OF_MVS                         0 ///< 0 (default) = disables rounding of motion vectors when right shifted,  1 = enables rounding
  #else
  #define ME_ENABLE_ROUNDING_OF_MVS                         1 ///< 0 (default) = disables rounding of motion vectors when right shifted,  1 = enables rounding
  #endif
  
  #define RDOQ_CHROMA_LAMBDA                                1 ///< F386: weighting of chroma for RDOQ
  
  #define U0132_TARGET_BITS_SATURATION                      1 ///< Rate control with target bits saturation method
  #ifdef  U0132_TARGET_BITS_SATURATION
  #define V0078_ADAPTIVE_LOWER_BOUND                        1 ///< Target bits saturation with adaptive lower bound
  #endif
  #define W0038_DB_OPT                                      1 ///< adaptive DB parameter selection, LoopFilterOffsetInPPS and LoopFilterDisable are set to 0 and DeblockingFilterMetric=2;
  #define W0038_CQP_ADJ                                     1 ///< chroma QP adjustment based on TL, CQPTLAdjustEnabled is set to 1;
  
  #define SHARP_LUMA_DELTA_QP                               1 ///< include non-normative LCU deltaQP and normative chromaQP change
  #define ER_CHROMA_QP_WCG_PPS                              1 ///< Chroma QP model for WCG used in Anchor 3.2
  #define ENABLE_QPA                                        0
  
  
  
  #define RDOQ_CHROMA                                       1 ///< use of RDOQ in chroma
  
  #define QP_SWITCHING_FOR_PARALLEL                         1 ///< Replace floating point QP with a source-file frame number. After switching POC, increase base QP instead of frame level QP.
  
  // ====================================================================================================================
  // Derived macros
  // ====================================================================================================================
  
  #if RExt__HIGH_BIT_DEPTH_SUPPORT
  #define FULL_NBIT                                         1 ///< When enabled, use distortion measure derived from all bits of source data, otherwise discard (bitDepth - 8) least-significant bits of distortion
  #define RExt__HIGH_PRECISION_FORWARD_TRANSFORM            1 ///< 0 use original 6-bit transform matrices for both forward and inverse transform, 1 (default) = use original matrices for inverse transform and high precision matrices for forward transform
  #else
  #define FULL_NBIT                                         0 ///< When enabled, use distortion measure derived from all bits of source data, otherwise discard (bitDepth - 8) least-significant bits of distortion
  #define RExt__HIGH_PRECISION_FORWARD_TRANSFORM            0 ///< 0 (default) use original 6-bit transform matrices for both forward and inverse transform, 1 = use original matrices for inverse transform and high precision matrices for forward transform
  #endif
  
  #if FULL_NBIT
  # define DISTORTION_PRECISION_ADJUSTMENT(x)  0
  #else
  # define DISTORTION_PRECISION_ADJUSTMENT(x) (x)
  #endif
  
  // ====================================================================================================================
  // Error checks
  // ====================================================================================================================
  
  #if ((RExt__HIGH_PRECISION_FORWARD_TRANSFORM != 0) && (RExt__HIGH_BIT_DEPTH_SUPPORT == 0))
  #error ERROR: cannot enable RExt__HIGH_PRECISION_FORWARD_TRANSFORM without RExt__HIGH_BIT_DEPTH_SUPPORT
  #endif
  
  // ====================================================================================================================
  // Basic type redefinition
  // ====================================================================================================================
  
  typedef       void                Void;
  typedef       bool                Bool;
  
  typedef       char                TChar; // Used for text/characters
  typedef       signed char         SChar; // Signed 8-bit values
  typedef       unsigned char       UChar; // Unsigned 8-bit values
  typedef       short               Short;
  typedef       unsigned short      UShort;
  typedef       int                 Int;
  typedef       unsigned int        UInt;
  typedef       double              Double;
  typedef       float               Float;
  
  
  // ====================================================================================================================
  // 64-bit integer type
  // ====================================================================================================================
  
  #ifdef _MSC_VER
  typedef       __int64             Int64;
  
  #if _MSC_VER <= 1200 // MS VC6
  typedef       __int64             UInt64;   // MS VC6 does not support unsigned __int64 to double conversion
  #else
  typedef       unsigned __int64    UInt64;
  #endif
  
  #else
  
  typedef       long long           Int64;
  typedef       unsigned long long  UInt64;
  
  #endif
  
  // ====================================================================================================================
  // Named numerical types
  // ====================================================================================================================
  
  #if RExt__HIGH_BIT_DEPTH_SUPPORT
  typedef       Int             Pel;               ///< pixel type
  typedef       Int64           TCoeff;            ///< transform coefficient
  typedef       Int             TMatrixCoeff;      ///< transform matrix coefficient
  typedef       Short           TFilterCoeff;      ///< filter coefficient
  typedef       Int64           Intermediate_Int;  ///< used as intermediate value in calculations
  typedef       UInt64          Intermediate_UInt; ///< used as intermediate value in calculations
  #else
  typedef       Short           Pel;               ///< pixel type
  typedef       Int             TCoeff;            ///< transform coefficient
  typedef       Short           TMatrixCoeff;      ///< transform matrix coefficient
  typedef       Short           TFilterCoeff;      ///< filter coefficient
  typedef       Int             Intermediate_Int;  ///< used as intermediate value in calculations
  typedef       UInt            Intermediate_UInt; ///< used as intermediate value in calculations
  #endif
  
  typedef       UInt64          SplitSeries;       ///< used to encoded the splits that caused a particular CU size
  
  #if FULL_NBIT
  typedef       UInt64          Distortion;        ///< distortion measurement
  #else
  typedef       UInt            Distortion;        ///< distortion measurement
  #endif
  
  // ====================================================================================================================
  // Enumeration
  // ====================================================================================================================
  enum QuantFlags
  {
    Q_INIT           = 0x0,
    Q_USE_RDOQ       = 0x1,
    Q_RDOQTS         = 0x2,
    Q_SELECTIVE_RDOQ = 0x4,
  };
  
  //EMT transform tags
  enum TransType
  {
    DCT2 = 0,
    DCT5 = 1,
    DCT8 = 2,
    DST1 = 3,
    DST7 = 4,
    NUM_TRANS_TYPE = 5,
    DCT2_HEVC = 6,
    DCT2_EMT = 7
  };
  
  enum RDPCMMode
  {
    RDPCM_OFF             = 0,
    RDPCM_HOR             = 1,
    RDPCM_VER             = 2,
    NUMBER_OF_RDPCM_MODES = 3
  };
  
  enum RDPCMSignallingMode
  {
    RDPCM_SIGNAL_IMPLICIT            = 0,
    RDPCM_SIGNAL_EXPLICIT            = 1,
    NUMBER_OF_RDPCM_SIGNALLING_MODES = 2
  };
  
  /// supported slice type
  enum SliceType
  {
    B_SLICE               = 0,
    P_SLICE               = 1,
    I_SLICE               = 2,
    NUMBER_OF_SLICE_TYPES = 3
  };
  
  /// chroma formats (according to semantics of chroma_format_idc)
  enum ChromaFormat
  {
    CHROMA_400        = 0,
    CHROMA_420        = 1,
    CHROMA_422        = 2,
    CHROMA_444        = 3,
    NUM_CHROMA_FORMAT = 4
  };
  
  enum ChannelType
  {
    CHANNEL_TYPE_LUMA    = 0,
    CHANNEL_TYPE_CHROMA  = 1,
    MAX_NUM_CHANNEL_TYPE = 2
  };
  
  #define CH_L CHANNEL_TYPE_LUMA
  #define CH_C CHANNEL_TYPE_CHROMA
  
  enum ComponentID
  {
    COMPONENT_Y         = 0,
    COMPONENT_Cb        = 1,
    COMPONENT_Cr        = 2,
  #if ENABLE_CHROMA_422
    SCND_TBLOCK_OFFSET  = 2,
    COMPONENT_Cb2       = COMPONENT_Cb      + SCND_TBLOCK_OFFSET,
    COMPONENT_Cr2       = COMPONENT_Cr      + SCND_TBLOCK_OFFSET,
    MAX_NUM_COMPONENT   = 3,
    MAX_NUM_TBLOCKS     = MAX_NUM_COMPONENT + SCND_TBLOCK_OFFSET
  #else
    MAX_NUM_COMPONENT   = 3,
    MAX_NUM_TBLOCKS     = MAX_NUM_COMPONENT
  #endif
  };
  
  #if ENABLE_CHROMA_422
  #define MAP_CHROMA(c) (ComponentID((c)>=MAX_NUM_COMPONENT?(c)-SCND_TBLOCK_OFFSET:(c)))
  #else
  #define MAP_CHROMA(c) (ComponentID(c))
  #endif
  
  enum InputColourSpaceConversion // defined in terms of conversion prior to input of encoder.
  {
    IPCOLOURSPACE_UNCHANGED               = 0,
    IPCOLOURSPACE_YCbCrtoYCrCb            = 1, // Mainly used for debug!
    IPCOLOURSPACE_YCbCrtoYYY              = 2, // Mainly used for debug!
    IPCOLOURSPACE_RGBtoGBR                = 3,
    NUMBER_INPUT_COLOUR_SPACE_CONVERSIONS = 4
  };
  
  enum MATRIX_COEFFICIENTS // Table E.5 (Matrix coefficients)
  {
    MATRIX_COEFFICIENTS_RGB                           = 0,
    MATRIX_COEFFICIENTS_BT709                         = 1,
    MATRIX_COEFFICIENTS_UNSPECIFIED                   = 2,
    MATRIX_COEFFICIENTS_RESERVED_BY_ITUISOIEC         = 3,
    MATRIX_COEFFICIENTS_USFCCT47                      = 4,
    MATRIX_COEFFICIENTS_BT601_625                     = 5,
    MATRIX_COEFFICIENTS_BT601_525                     = 6,
    MATRIX_COEFFICIENTS_SMPTE240                      = 7,
    MATRIX_COEFFICIENTS_YCGCO                         = 8,
    MATRIX_COEFFICIENTS_BT2020_NON_CONSTANT_LUMINANCE = 9,
    MATRIX_COEFFICIENTS_BT2020_CONSTANT_LUMINANCE     = 10,
  };
  
  enum DeblockEdgeDir
  {
    EDGE_VER     = 0,
    EDGE_HOR     = 1,
    NUM_EDGE_DIR = 2
  };
  
  /// supported partition shape
  enum PartSize
  {
    SIZE_2Nx2N           = 0,           ///< symmetric motion partition,  2Nx2N
  #if HEVC_USE_PART_SIZE
    SIZE_2NxN            = 1,           ///< symmetric motion partition,  2Nx N
    SIZE_Nx2N            = 2,           ///< symmetric motion partition,   Nx2N
    SIZE_NxN             = 3,           ///< symmetric motion partition,   Nx N
    SIZE_2NxnU           = 4,           ///< asymmetric motion partition, 2Nx( N/2) + 2Nx(3N/2)
    SIZE_2NxnD           = 5,           ///< asymmetric motion partition, 2Nx(3N/2) + 2Nx( N/2)
    SIZE_nLx2N           = 6,           ///< asymmetric motion partition, ( N/2)x2N + (3N/2)x2N
    SIZE_nRx2N           = 7,           ///< asymmetric motion partition, (3N/2)x2N + ( N/2)x2N
    NUMBER_OF_PART_SIZES = 8
  #else
    NUMBER_OF_PART_SIZES
  #endif
  };
  
  /// supported prediction type
  enum PredMode
  {
    MODE_INTER                 = 0,     ///< inter-prediction mode
    MODE_INTRA                 = 1,     ///< intra-prediction mode
    NUMBER_OF_PREDICTION_MODES = 2,
  };
  
  /// reference list index
  enum RefPicList
  {
    REF_PIC_LIST_0               = 0,   ///< reference list 0
    REF_PIC_LIST_1               = 1,   ///< reference list 1
    NUM_REF_PIC_LIST_01          = 2,
    REF_PIC_LIST_X               = 100  ///< special mark
  };
  
  #define L0 REF_PIC_LIST_0
  #define L1 REF_PIC_LIST_1
  
  /// distortion function index
  enum DFunc
  {
    DF_SSE             = 0,             ///< general size SSE
    DF_SSE2            = DF_SSE+1,      ///<   2xM SSE
    DF_SSE4            = DF_SSE+2,      ///<   4xM SSE
    DF_SSE8            = DF_SSE+3,      ///<   8xM SSE
    DF_SSE16           = DF_SSE+4,      ///<  16xM SSE
    DF_SSE32           = DF_SSE+5,      ///<  32xM SSE
    DF_SSE64           = DF_SSE+6,      ///<  64xM SSE
    DF_SSE16N          = DF_SSE+7,      ///< 16NxM SSE
  
    DF_SAD             = 8,             ///< general size SAD
    DF_SAD2            = DF_SAD+1,      ///<   2xM SAD
    DF_SAD4            = DF_SAD+2,      ///<   4xM SAD
    DF_SAD8            = DF_SAD+3,      ///<   8xM SAD
    DF_SAD16           = DF_SAD+4,      ///<  16xM SAD
    DF_SAD32           = DF_SAD+5,      ///<  32xM SAD
    DF_SAD64           = DF_SAD+6,      ///<  64xM SAD
    DF_SAD16N          = DF_SAD+7,      ///< 16NxM SAD
  
    DF_HAD             = 16,            ///< general size Hadamard
    DF_HAD2            = DF_HAD+1,      ///<   2xM HAD
    DF_HAD4            = DF_HAD+2,      ///<   4xM HAD
    DF_HAD8            = DF_HAD+3,      ///<   8xM HAD
    DF_HAD16           = DF_HAD+4,      ///<  16xM HAD
    DF_HAD32           = DF_HAD+5,      ///<  32xM HAD
    DF_HAD64           = DF_HAD+6,      ///<  64xM HAD
    DF_HAD16N          = DF_HAD+7,      ///< 16NxM HAD
  
    DF_SAD12           = 24,
    DF_SAD24           = 25,
    DF_SAD48           = 26,
  
    DF_MRSAD           = 27,            ///< general size MR SAD
    DF_MRSAD2          = DF_MRSAD+1,    ///<   2xM MR SAD
    DF_MRSAD4          = DF_MRSAD+2,    ///<   4xM MR SAD
    DF_MRSAD8          = DF_MRSAD+3,    ///<   8xM MR SAD
    DF_MRSAD16         = DF_MRSAD+4,    ///<  16xM MR SAD
    DF_MRSAD32         = DF_MRSAD+5,    ///<  32xM MR SAD
    DF_MRSAD64         = DF_MRSAD+6,    ///<  64xM MR SAD
    DF_MRSAD16N        = DF_MRSAD+7,    ///< 16NxM MR SAD
  
    DF_MRHAD           = 35,            ///< general size MR Hadamard
    DF_MRHAD2          = DF_MRHAD+1,    ///<   2xM MR HAD
    DF_MRHAD4          = DF_MRHAD+2,    ///<   4xM MR HAD
    DF_MRHAD8          = DF_MRHAD+3,    ///<   8xM MR HAD
    DF_MRHAD16         = DF_MRHAD+4,    ///<  16xM MR HAD
    DF_MRHAD32         = DF_MRHAD+5,    ///<  32xM MR HAD
    DF_MRHAD64         = DF_MRHAD+6,    ///<  64xM MR HAD
    DF_MRHAD16N        = DF_MRHAD+7,    ///< 16NxM MR HAD
  
    DF_MRSAD12         = 43,
    DF_MRSAD24         = 44,
    DF_MRSAD48         = 45,
  
    DF_SAD_FULL_NBIT    = 46,
    DF_SAD_FULL_NBIT2   = DF_SAD_FULL_NBIT+1,    ///<   2xM SAD with full bit usage
    DF_SAD_FULL_NBIT4   = DF_SAD_FULL_NBIT+2,    ///<   4xM SAD with full bit usage
    DF_SAD_FULL_NBIT8   = DF_SAD_FULL_NBIT+3,    ///<   8xM SAD with full bit usage
    DF_SAD_FULL_NBIT16  = DF_SAD_FULL_NBIT+4,    ///<  16xM SAD with full bit usage
    DF_SAD_FULL_NBIT32  = DF_SAD_FULL_NBIT+5,    ///<  32xM SAD with full bit usage
    DF_SAD_FULL_NBIT64  = DF_SAD_FULL_NBIT+6,    ///<  64xM SAD with full bit usage
    DF_SAD_FULL_NBIT16N = DF_SAD_FULL_NBIT+7,    ///< 16NxM SAD with full bit usage
  
  #if WCG_EXT
    DF_SSE_WTD          = 54,                ///< general size SSE
    DF_SSE2_WTD         = DF_SSE_WTD+1,      ///<   4xM SSE
    DF_SSE4_WTD         = DF_SSE_WTD+2,      ///<   4xM SSE
    DF_SSE8_WTD         = DF_SSE_WTD+3,      ///<   8xM SSE
    DF_SSE16_WTD        = DF_SSE_WTD+4,      ///<  16xM SSE
    DF_SSE32_WTD        = DF_SSE_WTD+5,      ///<  32xM SSE
    DF_SSE64_WTD        = DF_SSE_WTD+6,      ///<  64xM SSE
    DF_SSE16N_WTD       = DF_SSE_WTD+7,      ///< 16NxM SSE
    DF_DEFAULT_ORI      = DF_SSE_WTD+8,
  #endif
  
    DF_TOTAL_FUNCTIONS = 63
  };
  
  /// motion vector predictor direction used in AMVP
  enum MvpDir
  {
    MD_LEFT = 0,          ///< MVP of left block
    MD_ABOVE,             ///< MVP of above block
    MD_ABOVE_RIGHT,       ///< MVP of above right block
    MD_BELOW_LEFT,        ///< MVP of below left block
    MD_ABOVE_LEFT         ///< MVP of above left block
  };
  
  enum StoredResidualType
  {
    RESIDUAL_RECONSTRUCTED          = 0,
    RESIDUAL_ENCODER_SIDE           = 1,
    NUMBER_OF_STORED_RESIDUAL_TYPES = 2
  };
  
  enum TransformDirection
  {
    TRANSFORM_FORWARD              = 0,
    TRANSFORM_INVERSE              = 1,
    TRANSFORM_NUMBER_OF_DIRECTIONS = 2
  };
  
  /// supported ME search methods
  enum MESearchMethod
  {
    MESEARCH_FULL              = 0,
    MESEARCH_DIAMOND           = 1,
    MESEARCH_SELECTIVE         = 2,
    MESEARCH_DIAMOND_ENHANCED  = 3,
    MESEARCH_NUMBER_OF_METHODS = 4
  };
  
  /// coefficient scanning type used in ACS
  enum CoeffScanType
  {
    SCAN_DIAG = 0,        ///< up-right diagonal scan
  #if HEVC_USE_MDCS
    SCAN_HOR  = 1,        ///< horizontal first scan
    SCAN_VER  = 2,        ///< vertical first scan
  #endif
    SCAN_NUMBER_OF_TYPES
  };
  
  enum CoeffScanGroupType
  {
    SCAN_UNGROUPED   = 0,
    SCAN_GROUPED_4x4 = 1,
    SCAN_NUMBER_OF_GROUP_TYPES = 2
  };
  
  enum SignificanceMapContextType
  {
    CONTEXT_TYPE_4x4    = 0,
    CONTEXT_TYPE_8x8    = 1,
    CONTEXT_TYPE_NxN    = 2,
    CONTEXT_TYPE_SINGLE = 3,
    CONTEXT_NUMBER_OF_TYPES = 4
  };
  
  #if HEVC_USE_SCALING_LISTS
  enum ScalingListMode
  {
    SCALING_LIST_OFF,
    SCALING_LIST_DEFAULT,
    SCALING_LIST_FILE_READ
  };
  
  enum ScalingListSize
  {
    SCALING_LIST_2x2 = 0,
    SCALING_LIST_4x4,
    SCALING_LIST_8x8,
    SCALING_LIST_16x16,
    SCALING_LIST_32x32,
    SCALING_LIST_64x64,
    SCALING_LIST_128x128,
    SCALING_LIST_SIZE_NUM,
    SCALING_LIST_FIRST_CODED = SCALING_LIST_4x4, // smallest scaling coded as High Level Parameter
    SCALING_LIST_LAST_CODED  = SCALING_LIST_32x32
  };
  #endif
  
  // Slice / Slice segment encoding modes
  enum SliceConstraint
  {
    NO_SLICES              = 0,          ///< don't use slices / slice segments
    FIXED_NUMBER_OF_CTU    = 1,          ///< Limit maximum number of largest coding tree units in a slice / slice segments
    FIXED_NUMBER_OF_BYTES  = 2,          ///< Limit maximum number of bytes in a slice / slice segment
  #if HEVC_TILES_WPP
    FIXED_NUMBER_OF_TILES  = 3,          ///< slices / slice segments span an integer number of tiles
    NUMBER_OF_SLICE_CONSTRAINT_MODES = 4
  #else
    NUMBER_OF_SLICE_CONSTRAINT_MODES = 3
  #endif
  };
  
  // For use with decoded picture hash SEI messages, generated by encoder.
  enum HashType
  {
    HASHTYPE_MD5             = 0,
    HASHTYPE_CRC             = 1,
    HASHTYPE_CHECKSUM        = 2,
    HASHTYPE_NONE            = 3,
    NUMBER_OF_HASHTYPES      = 4
  };
  
  enum SAOMode //mode
  {
    SAO_MODE_OFF = 0,
    SAO_MODE_NEW,
    SAO_MODE_MERGE,
    NUM_SAO_MODES
  };
  
  enum SAOModeMergeTypes
  {
    SAO_MERGE_LEFT =0,
    SAO_MERGE_ABOVE,
    NUM_SAO_MERGE_TYPES
  };
  
  
  enum SAOModeNewTypes
  {
    SAO_TYPE_START_EO =0,
    SAO_TYPE_EO_0 = SAO_TYPE_START_EO,
    SAO_TYPE_EO_90,
    SAO_TYPE_EO_135,
    SAO_TYPE_EO_45,
  
    SAO_TYPE_START_BO,
    SAO_TYPE_BO = SAO_TYPE_START_BO,
  
    NUM_SAO_NEW_TYPES
  };
  #define NUM_SAO_EO_TYPES_LOG2 2
  
  enum SAOEOClasses
  {
    SAO_CLASS_EO_FULL_VALLEY = 0,
    SAO_CLASS_EO_HALF_VALLEY = 1,
    SAO_CLASS_EO_PLAIN       = 2,
    SAO_CLASS_EO_HALF_PEAK   = 3,
    SAO_CLASS_EO_FULL_PEAK   = 4,
    NUM_SAO_EO_CLASSES,
  };
  
  #define NUM_SAO_BO_CLASSES_LOG2  5
  #define NUM_SAO_BO_CLASSES       (1<<NUM_SAO_BO_CLASSES_LOG2)
  
  namespace Profile
  {
    enum Name
    {
      NONE = 0,
      MAIN = 1,
      MAIN10 = 2,
      MAINSTILLPICTURE = 3,
      MAINREXT = 4,
      HIGHTHROUGHPUTREXT = 5,
      NEXT = 6
    };
  }
  
  namespace Level
  {
    enum Tier
    {
      MAIN = 0,
      HIGH = 1,
    };
  
    enum Name
    {
      // code = (level * 30)
      NONE     = 0,
      LEVEL1   = 30,
      LEVEL2   = 60,
      LEVEL2_1 = 63,
      LEVEL3   = 90,
      LEVEL3_1 = 93,
      LEVEL4   = 120,
      LEVEL4_1 = 123,
      LEVEL5   = 150,
      LEVEL5_1 = 153,
      LEVEL5_2 = 156,
      LEVEL6   = 180,
      LEVEL6_1 = 183,
      LEVEL6_2 = 186,
      LEVEL8_5 = 255,
    };
  }
  
  enum CostMode
  {
    COST_STANDARD_LOSSY              = 0,
    COST_SEQUENCE_LEVEL_LOSSLESS     = 1,
    COST_LOSSLESS_CODING             = 2,
    COST_MIXED_LOSSLESS_LOSSY_CODING = 3
  };
  
  enum WeightedPredictionMethod
  {
    WP_PER_PICTURE_WITH_SIMPLE_DC_COMBINED_COMPONENT                          =0,
    WP_PER_PICTURE_WITH_SIMPLE_DC_PER_COMPONENT                               =1,
    WP_PER_PICTURE_WITH_HISTOGRAM_AND_PER_COMPONENT                           =2,
    WP_PER_PICTURE_WITH_HISTOGRAM_AND_PER_COMPONENT_AND_CLIPPING              =3,
    WP_PER_PICTURE_WITH_HISTOGRAM_AND_PER_COMPONENT_AND_CLIPPING_AND_EXTENSION=4
  };
  
  enum FastInterSearchMode
  {
    FASTINTERSEARCH_DISABLED = 0,
    FASTINTERSEARCH_MODE1    = 1, // TODO: assign better names to these.
    FASTINTERSEARCH_MODE2    = 2,
    FASTINTERSEARCH_MODE3    = 3
  };
  
  enum SPSExtensionFlagIndex
  {
    SPS_EXT__REXT           = 0,
  //SPS_EXT__MVHEVC         = 1, //for use in future versions
  //SPS_EXT__SHVC           = 2, //for use in future versions
    SPS_EXT__NEXT           = 3,
    NUM_SPS_EXTENSION_FLAGS = 8
  };
  
  enum PPSExtensionFlagIndex
  {
    PPS_EXT__REXT           = 0,
  //PPS_EXT__MVHEVC         = 1, //for use in future versions
  //PPS_EXT__SHVC           = 2, //for use in future versions
    NUM_PPS_EXTENSION_FLAGS = 8
  };
  
  // TODO: Existing names used for the different NAL unit types can be altered to better reflect the names in the spec.
  //       However, the names in the spec are not yet stable at this point. Once the names are stable, a cleanup
  //       effort can be done without use of macros to alter the names used to indicate the different NAL unit types.
  enum NalUnitType
  {
    NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0
    NAL_UNIT_CODED_SLICE_TRAIL_R,     // 1
  
    NAL_UNIT_CODED_SLICE_TSA_N,       // 2
    NAL_UNIT_CODED_SLICE_TSA_R,       // 3
  
    NAL_UNIT_CODED_SLICE_STSA_N,      // 4
    NAL_UNIT_CODED_SLICE_STSA_R,      // 5
  
    NAL_UNIT_CODED_SLICE_RADL_N,      // 6
    NAL_UNIT_CODED_SLICE_RADL_R,      // 7
  
    NAL_UNIT_CODED_SLICE_RASL_N,      // 8
    NAL_UNIT_CODED_SLICE_RASL_R,      // 9
  
    NAL_UNIT_RESERVED_VCL_N10,
    NAL_UNIT_RESERVED_VCL_R11,
    NAL_UNIT_RESERVED_VCL_N12,
    NAL_UNIT_RESERVED_VCL_R13,
    NAL_UNIT_RESERVED_VCL_N14,
    NAL_UNIT_RESERVED_VCL_R15,
  
    NAL_UNIT_CODED_SLICE_BLA_W_LP,    // 16
    NAL_UNIT_CODED_SLICE_BLA_W_RADL,  // 17
    NAL_UNIT_CODED_SLICE_BLA_N_LP,    // 18
    NAL_UNIT_CODED_SLICE_IDR_W_RADL,  // 19
    NAL_UNIT_CODED_SLICE_IDR_N_LP,    // 20
    NAL_UNIT_CODED_SLICE_CRA,         // 21
    NAL_UNIT_RESERVED_IRAP_VCL22,
    NAL_UNIT_RESERVED_IRAP_VCL23,
  
    NAL_UNIT_RESERVED_VCL24,
    NAL_UNIT_RESERVED_VCL25,
    NAL_UNIT_RESERVED_VCL26,
    NAL_UNIT_RESERVED_VCL27,
    NAL_UNIT_RESERVED_VCL28,
    NAL_UNIT_RESERVED_VCL29,
    NAL_UNIT_RESERVED_VCL30,
    NAL_UNIT_RESERVED_VCL31,
  
  #if HEVC_VPS
    NAL_UNIT_VPS,                     // 32
  #else
    NAL_UNIT_RESERVED_32,
  #endif
    NAL_UNIT_SPS,                     // 33
    NAL_UNIT_PPS,                     // 34
    NAL_UNIT_ACCESS_UNIT_DELIMITER,   // 35
    NAL_UNIT_EOS,                     // 36
    NAL_UNIT_EOB,                     // 37
    NAL_UNIT_FILLER_DATA,             // 38
    NAL_UNIT_PREFIX_SEI,              // 39
    NAL_UNIT_SUFFIX_SEI,              // 40
  
    NAL_UNIT_RESERVED_NVCL41,
    NAL_UNIT_RESERVED_NVCL42,
    NAL_UNIT_RESERVED_NVCL43,
    NAL_UNIT_RESERVED_NVCL44,
    NAL_UNIT_RESERVED_NVCL45,
    NAL_UNIT_RESERVED_NVCL46,
    NAL_UNIT_RESERVED_NVCL47,
    NAL_UNIT_UNSPECIFIED_48,
    NAL_UNIT_UNSPECIFIED_49,
    NAL_UNIT_UNSPECIFIED_50,
    NAL_UNIT_UNSPECIFIED_51,
    NAL_UNIT_UNSPECIFIED_52,
    NAL_UNIT_UNSPECIFIED_53,
    NAL_UNIT_UNSPECIFIED_54,
    NAL_UNIT_UNSPECIFIED_55,
    NAL_UNIT_UNSPECIFIED_56,
    NAL_UNIT_UNSPECIFIED_57,
    NAL_UNIT_UNSPECIFIED_58,
    NAL_UNIT_UNSPECIFIED_59,
    NAL_UNIT_UNSPECIFIED_60,
    NAL_UNIT_UNSPECIFIED_61,
    NAL_UNIT_UNSPECIFIED_62,
    NAL_UNIT_UNSPECIFIED_63,
    NAL_UNIT_INVALID,
  };
  
  #if SHARP_LUMA_DELTA_QP
  enum LumaLevelToDQPMode
  {
    LUMALVL_TO_DQP_DISABLED   = 0,
    LUMALVL_TO_DQP_AVG_METHOD = 1, // use average of CTU to determine luma level
  #if !WCG_EXT
    LUMALVL_TO_DQP_MAX_METHOD = 2,  // use maximum value of CTU to determine luma level
    LUMALVL_TO_DQP_NUM_MODES  = 3
  #else
    LUMALVL_TO_DQP_NUM_MODES  = 2
  #endif
  };
  #endif
  
  enum SaveLoadTag
  {
    SAVE_LOAD_INIT = 0,
    SAVE_ENC_INFO  = 1,
    LOAD_ENC_INFO  = 2
  };
  
  enum MergeType
  {
    MRG_TYPE_DEFAULT_N        = 0, // 0
    NUM_MRG_TYPE                   // 5
  };
  
  
  //////////////////////////////////////////////////////////////////////////
  // Encoder modes to try out
  //////////////////////////////////////////////////////////////////////////
  
  enum EncModeFeature
  {
    ENC_FT_FRAC_BITS = 0,
    ENC_FT_DISTORTION,
    ENC_FT_RD_COST,
    ENC_FT_ENC_MODE_TYPE,
    ENC_FT_ENC_MODE_OPTS,
    ENC_FT_ENC_MODE_PART,
    NUM_ENC_FEATURES
  };
  
  enum ImvMode
  {
    IMV_OFF = 0,
    IMV_DEFAULT,
    IMV_4PEL,
    NUM_IMV_MODES
  };
  
  
  // ====================================================================================================================
  // Type definition
  // ====================================================================================================================
  
  /// parameters for adaptive loop filter
  class PicSym;
  
  #define MAX_NUM_SAO_CLASSES  32  //(NUM_SAO_EO_GROUPS > NUM_SAO_BO_GROUPS)?NUM_SAO_EO_GROUPS:NUM_SAO_BO_GROUPS
  
  struct SAOOffset
  {
    SAOMode modeIdc; // NEW, MERGE, OFF
    Int typeIdc;     // union of SAOModeMergeTypes and SAOModeNewTypes, depending on modeIdc.
    Int typeAuxInfo; // BO: starting band index
    Int offset[MAX_NUM_SAO_CLASSES];
  
    SAOOffset();
    ~SAOOffset();
    Void reset();
  
    const SAOOffset& operator= (const SAOOffset& src);
  };
  
  struct SAOBlkParam
  {
  
    SAOBlkParam();
    ~SAOBlkParam();
    Void reset();
    const SAOBlkParam& operator= (const SAOBlkParam& src);
    SAOOffset& operator[](Int compIdx){ return offsetParam[compIdx];}
    const SAOOffset& operator[](Int compIdx) const { return offsetParam[compIdx];}
  private:
    SAOOffset offsetParam[MAX_NUM_COMPONENT];
  
  };
  
  
  
  struct BitDepths
  {
    Int recon[MAX_NUM_CHANNEL_TYPE]; ///< the bit depth as indicated in the SPS
  };
  
  /// parameters for deblocking filter
  struct LFCUParam
  {
    Bool internalEdge;                     ///< indicates internal edge
    Bool leftEdge;                         ///< indicates left edge
    Bool topEdge;                          ///< indicates top edge
  };
  
  
  
  struct PictureHash
  {
    std::vector<UChar> hash;
  
    Bool operator==(const PictureHash &other) const
    {
      if (other.hash.size() != hash.size())
      {
        return false;
      }
      for(UInt i=0; i<UInt(hash.size()); i++)
      {
        if (other.hash[i] != hash[i])
        {
          return false;
        }
      }
      return true;
    }
  
    Bool operator!=(const PictureHash &other) const
    {
      return !(*this == other);
    }
  };
  
  struct SEITimeSet
  {
    SEITimeSet() : clockTimeStampFlag(false),
                       numUnitFieldBasedFlag(false),
                       countingType(0),
                       fullTimeStampFlag(false),
                       discontinuityFlag(false),
                       cntDroppedFlag(false),
                       numberOfFrames(0),
                       secondsValue(0),
                       minutesValue(0),
                       hoursValue(0),
                       secondsFlag(false),
                       minutesFlag(false),
                       hoursFlag(false),
                       timeOffsetLength(0),
                       timeOffsetValue(0)
    { }
    Bool clockTimeStampFlag;
    Bool numUnitFieldBasedFlag;
    Int  countingType;
    Bool fullTimeStampFlag;
    Bool discontinuityFlag;
    Bool cntDroppedFlag;
    Int  numberOfFrames;
    Int  secondsValue;
    Int  minutesValue;
    Int  hoursValue;
    Bool secondsFlag;
    Bool minutesFlag;
    Bool hoursFlag;
    Int  timeOffsetLength;
    Int  timeOffsetValue;
  };
  
  struct SEIMasteringDisplay
  {
    Bool      colourVolumeSEIEnabled;
    UInt      maxLuminance;
    UInt      minLuminance;
    UShort    primaries[3][2];
    UShort    whitePoint[2];
  };
  
  #if SHARP_LUMA_DELTA_QP
  struct LumaLevelToDeltaQPMapping
  {
    LumaLevelToDQPMode                 mode;             ///< use deltaQP determined by block luma level
    Double                             maxMethodWeight;  ///< weight of max luma value when mode = 2
    std::vector< std::pair<Int, Int> > mapping;          ///< first=luma level, second=delta QP.
  #if ENABLE_QPA
    bool isEnabled() const { return (mode != LUMALVL_TO_DQP_DISABLED && mode != LUMALVL_TO_DQP_NUM_MODES); }
  #else
    Bool isEnabled() const { return mode!=LUMALVL_TO_DQP_DISABLED; }
  #endif
  };
  #endif
  
  #if ER_CHROMA_QP_WCG_PPS
  struct WCGChromaQPControl
  {
    Bool isEnabled() const { return enabled; }
    Bool   enabled;         ///< Enabled flag (0:default)
    Double chromaCbQpScale; ///< Chroma Cb QP Scale (1.0:default)
    Double chromaCrQpScale; ///< Chroma Cr QP Scale (1.0:default)
    Double chromaQpScale;   ///< Chroma QP Scale (0.0:default)
    Double chromaQpOffset;  ///< Chroma QP Offset (0.0:default)
  };
  #endif
  
  class ChromaCbfs
  {
  public:
    ChromaCbfs()
      : Cb(true), Cr(true)
  #if ENABLE_CHROMA_422
      , Cb2(true), Cr2(true)
  #endif
    {}
    ChromaCbfs( bool _cbf )
      : Cb( _cbf ), Cr( _cbf )
  #if ENABLE_CHROMA_422
      , Cb2( _cbf ), Cr2( _cbf )
  #endif
    {}
  public:
    bool sigChroma( ChromaFormat chromaFormat ) const
    {
      if( chromaFormat == CHROMA_400 )
      {
        return false;
      }
  #if ENABLE_CHROMA_422
      else if( chromaFormat == CHROMA_422 )
      {
        return ( Cb || Cb2 || Cr || Cr2 );
      }
  #endif
      return   ( Cb || Cr );
    }
    bool& cbf( ComponentID compID )
    {
  #if ENABLE_CHROMA_422
      bool *cbfs[MAX_NUM_TBLOCKS] = { nullptr, &Cb, &Cr, &Cb2, &Cr2 };
  #else
      bool *cbfs[MAX_NUM_TBLOCKS] = { nullptr, &Cb, &Cr };
  #endif
  
      return *cbfs[compID];
    }
  public:
    bool Cb;
    bool Cr;
  #if ENABLE_CHROMA_422
    bool Cb2;
    bool Cr2;
  #endif
  };
  
  
  enum MsgLevel
  {
    SILENT  = 0,
    ERROR   = 1,
    WARNING = 2,
    INFO    = 3,
    NOTICE  = 4,
    VERBOSE = 5,
    DETAILS = 6
  };
  
  
  // ---------------------------------------------------------------------------
  // exception class
  // ---------------------------------------------------------------------------
  
  class Exception : public std::exception
  {
  public:
    Exception( const std::string& _s ) : m_str( _s ) { }
    Exception( const Exception& _e ) : std::exception( _e ), m_str( _e.m_str ) { }
    virtual ~Exception() noexcept { };
    virtual const char* what() const noexcept { return m_str.c_str(); }
    Exception& operator=( const Exception& _e ) { std::exception::operator=( _e ); m_str = _e.m_str; return *this; }
    template<typename T> Exception& operator<<( T t ) { std::ostringstream oss; oss << t; m_str += oss.str(); return *this; }
  private:
    std::string m_str;
  };
  
  // if a check fails with THROW or CHECK, please check if ported correctly from assert in revision 1196)
  #define THROW(x)            throw( Exception( "\nERROR: In function \"" ) << __FUNCTION__ << "\" in " << __FILE__ << ":" << __LINE__ << ": " << x )
  #define CHECK(c,x)          if(c){ THROW(x); }
  #define EXIT(x)             throw( Exception( "\n" ) << x << "\n" )
  #define CHECK_NULLPTR(_ptr) CHECK( !( _ptr ), "Accessing an empty pointer pointer!" )
  #if defined( _DEBUG )
  #define CHECKD(c,x)         if(c){ THROW(x); }
  #else
  #define CHECKD(c,x)
  #endif // _DEBUG
  
  // ---------------------------------------------------------------------------
  // static vector
  // ---------------------------------------------------------------------------
  
  template<typename T, size_t N>
  class static_vector
  {
    T _arr[ N ];
    size_t _size;
  
  public:
  
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T&        reference;
    typedef T const&  const_reference;
    typedef T*        pointer;
    typedef T const*  const_pointer;
    typedef T*        iterator;
    typedef T const*  const_iterator;
  
    static const size_type max_num_elements = N;
  
    static_vector() : _size( 0 )                                 { }
    static_vector( size_t N_ ) : _size( N_ )                     { }
    static_vector( size_t N_, const T& _val ) : _size( 0 )       { resize( N_, _val ); }
    template<typename It>
    static_vector( It _it1, It _it2 ) : _size( 0 )               { while( _it1 < _it2 ) _arr[ _size++ ] = *_it1++; }
    static_vector( std::initializer_list<T> _il ) : _size( 0 )
    {
      typename std::initializer_list<T>::iterator _src1 = _il.begin();
      typename std::initializer_list<T>::iterator _src2 = _il.end();
  
      while( _src1 < _src2 ) _arr[ _size++ ] = *_src1++;
  
      CHECKD( _size > N, "capacity exceeded" );
    }
    static_vector& operator=( std::initializer_list<T> _il )
    {
      _size = 0;
  
      typename std::initializer_list<T>::iterator _src1 = _il.begin();
      typename std::initializer_list<T>::iterator _src2 = _il.end();
  
      while( _src1 < _src2 ) _arr[ _size++ ] = *_src1++;
  
      CHECKD( _size > N, "capacity exceeded" );
    }
  
    void resize( size_t N_ )                      { CHECKD( N_ > N, "capacity exceeded" ); while(_size < N_) _arr[ _size++ ] = T() ; _size = N_; }
    void resize( size_t N_, const T& _val )       { CHECKD( N_ > N, "capacity exceeded" ); while(_size < N_) _arr[ _size++ ] = _val; _size = N_; }
    void reserve( size_t N_ )                     { CHECKD( N_ > N, "capacity exceeded" ); }
    void push_back( const T& _val )               { CHECKD( _size >= N, "capacity exceeded" ); _arr[ _size++ ] = _val; }
    void push_back( T&& val )                     { CHECKD( _size >= N, "capacity exceeded" ); _arr[ _size++ ] = std::forward<T>( val ); }
    void pop_back()                               { CHECKD( _size == 0, "calling pop_back on an empty vector" ); _size--; }
    void pop_front()                              { CHECKD( _size == 0, "calling pop_front on an empty vector" ); _size--; for( int i = 0; i < _size; i++ ) _arr[i] = _arr[i + 1]; }
    void clear()                                  { _size = 0; }
    reference       at( size_t _i )               { CHECKD( _i >= _size, "Trying to access an out-of-bound-element" ); return _arr[ _i ]; }
    const_reference at( size_t _i ) const         { CHECKD( _i >= _size, "Trying to access an out-of-bound-element" ); return _arr[ _i ]; }
    reference       operator[]( size_t _i )       { CHECKD( _i >= _size, "Trying to access an out-of-bound-element" ); return _arr[ _i ]; }
    const_reference operator[]( size_t _i ) const { CHECKD( _i >= _size, "Trying to access an out-of-bound-element" ); return _arr[ _i ]; }
    reference       front()                       { CHECKD( _size == 0, "Trying to access the first element of an empty vector" ); return _arr[ 0 ]; }
    const_reference front() const                 { CHECKD( _size == 0, "Trying to access the first element of an empty vector" ); return _arr[ 0 ]; }
    reference       back()                        { CHECKD( _size == 0, "Trying to access the last element of an empty vector" );  return _arr[ _size - 1 ]; }
    const_reference back() const                  { CHECKD( _size == 0, "Trying to access the last element of an empty vector" );  return _arr[ _size - 1 ]; }
    pointer         data()                        { return _arr; }
    const_pointer   data() const                  { return _arr; }
    iterator        begin()                       { return _arr; }
    const_iterator  begin() const                 { return _arr; }
    const_iterator  cbegin() const                { return _arr; }
    iterator        end()                         { return _arr + _size; }
    const_iterator  end() const                   { return _arr + _size; };
    const_iterator  cend() const                  { return _arr + _size; };
    size_type       size() const                  { return _size; };
    size_type       byte_size() const             { return _size * sizeof( T ); }
    bool            empty() const                 { return _size == 0; }
  
    size_type       capacity() const              { return N; }
    size_type       max_size() const              { return N; }
    size_type       byte_capacity() const         { return sizeof(_arr); }
  
    iterator        insert( const_iterator _pos, const T& _val )
                                                  { CHECKD( _size >= N, "capacity exceeded" );
                                                    for( difference_type i = _size - 1; i >= _pos - _arr; i-- ) _arr[i + 1] = _arr[i];
                                                    *const_cast<iterator>( _pos ) = _val;
                                                    _size++;
                                                    return const_cast<iterator>( _pos ); }
  
    iterator        insert( const_iterator _pos, T&& _val )
                                                  { CHECKD( _size >= N, "capacity exceeded" );
                                                    for( difference_type i = _size - 1; i >= _pos - _arr; i-- ) _arr[i + 1] = _arr[i];
                                                    *const_cast<iterator>( _pos ) = std::forward<T>( _val );
                                                    _size++; return const_cast<iterator>( _pos ); }
    template<class InputIt>
    iterator        insert( const_iterator _pos, InputIt first, InputIt last )
                                                  { const difference_type numEl = last - first;
                                                    CHECKD( _size + numEl >= N, "capacity exceeded" );
                                                    for( difference_type i = _size - 1; i >= _pos - _arr; i-- ) _arr[i + numEl] = _arr[i];
                                                    iterator it = const_cast<iterator>( _pos ); _size += numEl;
                                                    while( first != last ) *it++ = *first++;
                                                    return const_cast<iterator>( _pos ); }
  };
  
  
  // ---------------------------------------------------------------------------
  // dynamic cache
  // ---------------------------------------------------------------------------
  
  template<typename T>
  class dynamic_cache
  {
    std::vector<T*> m_cache;
  #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
    int64_t         m_cacheId;
  #endif
  
  public:
  
  #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
    dynamic_cache()
    {
      static int cacheId = 0;
      m_cacheId = cacheId++;
    }
  
  #endif
    ~dynamic_cache()
    {
      deleteEntries();
    }
  
    void deleteEntries()
    {
      for( auto &p : m_cache )
      {
        delete p;
        p = nullptr;
      }
  
      m_cache.clear();
    }
  
    T* get()
    {
      T* ret;
  
      if( !m_cache.empty() )
      {
        ret = m_cache.back();
        m_cache.pop_back();
  #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
        CHECK( ret->cacheId != m_cacheId, "Putting item into wrong cache!" );
        CHECK( !ret->cacheUsed,           "Fetched an element that should've been in cache!!" );
  #endif
      }
      else
      {
        ret = new T;
      }
  
  #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
      ret->cacheId   = m_cacheId;
      ret->cacheUsed = false;
  
  #endif
      return ret;
    }
  
    void cache( T* el )
    {
  #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
      CHECK( el->cacheId != m_cacheId, "Putting item into wrong cache!" );
      CHECK( el->cacheUsed,            "Putting cached item back into cache!" );
  
      el->cacheUsed = true;
  
  #endif
      m_cache.push_back( el );
    }
  
    void cache( std::vector<T*>& vel )
    {
  #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
      for( auto el : vel )
      {
        CHECK( el->cacheId != m_cacheId, "Putting item into wrong cache!" );
        CHECK( el->cacheUsed,            "Putting cached item back into cache!" );
  
        el->cacheUsed = true;
      }
  
  #endif
      m_cache.insert( m_cache.end(), vel.begin(), vel.end() );
      vel.clear();
    }
  };
  
  typedef dynamic_cache<struct CodingUnit    > CUCache;
  typedef dynamic_cache<struct PredictionUnit> PUCache;
  typedef dynamic_cache<struct TransformUnit > TUCache;
  
  struct XUCache
  {
    CUCache cuCache;
    PUCache puCache;
    TUCache tuCache;
  };
  
  #define SIGN(x) ( (x) >= 0 ? 1 : -1 )
  //! \}
  
  #endif
  
  
  