Skip to content
Snippets Groups Projects
EncAppCfg.cpp 287 KiB
Newer Older
  • Learn to ignore specific revisions
  •                                            !m_enableIntraReferenceSmoothing          ||
                                               m_persistentRiceAdaptationEnabledFlag     ||
                                               m_log2MaxTransformSkipBlockSize!=2;
    
          const bool bUsingChromaQPTool      = m_cuChromaQpOffsetSubdiv >= 0;
    
          const bool bUsingExtendedPrecision = m_extendedPrecisionProcessingFlag;
    
          xConfirmPara((m_chromaFormatConstraint==CHROMA_420 || m_chromaFormatConstraint==CHROMA_400) && bUsingChromaQPTool, "CU Chroma QP adjustment cannot be used for 4:0:0 or 4:2:0 RExt profiles");
          xConfirmPara(m_bitDepthConstraint != 16 && bUsingExtendedPrecision, "Extended precision can only be used in 16-bit RExt profiles");
          if (!(m_chromaFormatConstraint == CHROMA_400 && m_bitDepthConstraint == 16) && m_chromaFormatConstraint!=CHROMA_444)
          {
            xConfirmPara(bUsingGeneralRExtTools, "Combination of tools and profiles are not possible in the specified RExt profile.");
          }
          xConfirmPara( m_onePictureOnlyConstraintFlag && m_chromaFormatConstraint!=CHROMA_444, "chroma format constraint must be 4:4:4 when one-picture-only constraint flag is 1");
          xConfirmPara( m_onePictureOnlyConstraintFlag && m_bitDepthConstraint != 8 && m_bitDepthConstraint != 16, "bit depth constraint must be 8 or 16 when one-picture-only constraint flag is 1");
          xConfirmPara( m_onePictureOnlyConstraintFlag && m_framesToBeEncoded > 1, "Number of frames to be encoded must be 1 when one-picture-only constraint flag is 1.");
    
          if (!m_intraConstraintFlag && m_bitDepthConstraint==16 && m_chromaFormatConstraint==CHROMA_444)
          {
            msg( WARNING, "********************************************************************************************************\n");
            msg( WARNING, "** WARNING: The RExt constraint flags describe a non standard combination (used for development only) **\n");
            msg( WARNING, "********************************************************************************************************\n");
          }
        }
        else
        {
          xConfirmPara( m_chromaFormatConstraint != CHROMA_444, "chroma format constraint must be 4:4:4 in the High Throughput 4:4:4 16-bit Intra profile.");
          xConfirmPara( m_bitDepthConstraint     != 16,         "bit depth constraint must be 4:4:4 in the High Throughput 4:4:4 16-bit Intra profile.");
          xConfirmPara( m_intraConstraintFlag    != 1,          "intra constraint flag must be 1 in the High Throughput 4:4:4 16-bit Intra profile.");
        }
      }
      else
      {
        xConfirmPara(m_bitDepthConstraint!=((m_profile==Profile::MAIN10 || m_profile==Profile::NEXT)?10:8), "BitDepthConstraint must be 8 for MAIN profile and 10 for MAIN10 profile.");
        xConfirmPara(m_chromaFormatConstraint!=CHROMA_420 && m_profile!=Profile::NEXT, "ChromaFormatConstraint must be 420 for non main-RExt and non-Next profiles.");
        xConfirmPara(m_intraConstraintFlag==true, "IntraConstraintFlag must be false for non main_RExt profiles.");
        xConfirmPara(m_lowerBitRateConstraintFlag==false, "LowerBitrateConstraintFlag must be true for non main-RExt profiles.");
        xConfirmPara(m_profile == Profile::MAINSTILLPICTURE && m_framesToBeEncoded > 1, "Number of frames to be encoded must be 1 when main still picture profile is used.");
    
        xConfirmPara(m_crossComponentPredictionEnabledFlag==true, "CrossComponentPrediction must not be used for non main-RExt profiles.");
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        xConfirmPara(m_log2MaxTransformSkipBlockSize>=6, "Transform Skip Log2 Max Size must be less or equal to 5.");
    
        xConfirmPara(m_transformSkipRotationEnabledFlag==true, "UseResidualRotation must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_transformSkipContextEnabledFlag==true, "UseSingleSignificanceMapContext must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_rdpcmEnabledFlag[RDPCM_SIGNAL_IMPLICIT]==true, "ImplicitResidualDPCM must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_rdpcmEnabledFlag[RDPCM_SIGNAL_EXPLICIT]==true, "ExplicitResidualDPCM must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_persistentRiceAdaptationEnabledFlag==true, "GolombRiceParameterAdaption must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_extendedPrecisionProcessingFlag==true, "UseExtendedPrecision must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_highPrecisionOffsetsEnabledFlag==true, "UseHighPrecisionPredictionWeighting must not be enabled for non main-RExt profiles.");
        xConfirmPara(m_enableIntraReferenceSmoothing==false, "EnableIntraReferenceSmoothing must be enabled for non main-RExt profiles.");
        xConfirmPara(m_cabacBypassAlignmentEnabledFlag, "AlignCABACBeforeBypass cannot be enabled for non main-RExt profiles.");
      }
    
    
      // check range of parameters
      xConfirmPara( m_inputBitDepth[CHANNEL_TYPE_LUMA  ] < 8,                                   "InputBitDepth must be at least 8" );
      xConfirmPara( m_inputBitDepth[CHANNEL_TYPE_CHROMA] < 8,                                   "InputBitDepthC must be at least 8" );
    
    
      if (m_extendedPrecisionProcessingFlag)
      {
        for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++)
        {
          xConfirmPara((m_internalBitDepth[channelType] > 8) , "Model is not configured to support high enough internal accuracies - enable RExt__HIGH_BIT_DEPTH_SUPPORT to use increased precision internal data types etc...");
        }
      }
      else
      {
        for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++)
        {
          xConfirmPara((m_internalBitDepth[channelType] > 12) , "Model is not configured to support high enough internal accuracies - enable RExt__HIGH_BIT_DEPTH_SUPPORT to use increased precision internal data types etc...");
        }
      }
    
    
      xConfirmPara( (m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA  ] < m_inputBitDepth[CHANNEL_TYPE_LUMA  ]), "MSB-extended bit depth for luma channel (--MSBExtendedBitDepth) must be greater than or equal to input bit depth for luma channel (--InputBitDepth)" );
      xConfirmPara( (m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA] < m_inputBitDepth[CHANNEL_TYPE_CHROMA]), "MSB-extended bit depth for chroma channel (--MSBExtendedBitDepthC) must be greater than or equal to input bit depth for chroma channel (--InputBitDepthC)" );
    
      xConfirmPara( m_log2SaoOffsetScale[CHANNEL_TYPE_LUMA]   > (m_internalBitDepth[CHANNEL_TYPE_LUMA  ]<10?0:(m_internalBitDepth[CHANNEL_TYPE_LUMA  ]-10)), "SaoLumaOffsetBitShift must be in the range of 0 to InternalBitDepth-10, inclusive");
    
    #if JVET_P0243_SINGLE_BIT_DEPTH
      xConfirmPara( m_log2SaoOffsetScale[CHANNEL_TYPE_CHROMA] > (m_internalBitDepth[CHANNEL_TYPE_CHROMA]<10?0:(m_internalBitDepth[CHANNEL_TYPE_CHROMA]-10)), "SaoChromaOffsetBitShift must be in the range of 0 to InternalBitDepth-10, inclusive");
    #else
    
      xConfirmPara( m_log2SaoOffsetScale[CHANNEL_TYPE_CHROMA] > (m_internalBitDepth[CHANNEL_TYPE_CHROMA]<10?0:(m_internalBitDepth[CHANNEL_TYPE_CHROMA]-10)), "SaoChromaOffsetBitShift must be in the range of 0 to InternalBitDepthC-10, inclusive");
    
    #endif
    
    
      xConfirmPara( m_chromaFormatIDC >= NUM_CHROMA_FORMAT,                                     "ChromaFormatIDC must be either 400, 420, 422 or 444" );
      std::string sTempIPCSC="InputColourSpaceConvert must be empty, "+getListOfColourSpaceConverts(true);
      xConfirmPara( m_inputColourSpaceConvert >= NUMBER_INPUT_COLOUR_SPACE_CONVERSIONS,         sTempIPCSC.c_str() );
      xConfirmPara( m_InputChromaFormatIDC >= NUM_CHROMA_FORMAT,                                "InputChromaFormatIDC must be either 400, 420, 422 or 444" );
      xConfirmPara( m_iFrameRate <= 0,                                                          "Frame rate must be more than 1" );
      xConfirmPara( m_framesToBeEncoded <= 0,                                                   "Total Number Of Frames encoded must be more than 0" );
      xConfirmPara( m_framesToBeEncoded < m_switchPOC,                                          "debug POC out of range" );
    
      xConfirmPara( m_iGOPSize < 1 ,                                                            "GOP Size must be greater or equal to 1" );
      xConfirmPara( m_iGOPSize > 1 &&  m_iGOPSize % 2,                                          "GOP Size must be a multiple of 2, if GOP Size is greater than 1" );
      xConfirmPara( (m_iIntraPeriod > 0 && m_iIntraPeriod < m_iGOPSize) || m_iIntraPeriod == 0, "Intra period must be more than GOP size, or -1 , not 0" );
    
      xConfirmPara( m_drapPeriod < 0,                                                           "DRAP period must be greater or equal to 0" );
    
      xConfirmPara( m_iDecodingRefreshType < 0 || m_iDecodingRefreshType > 3,                   "Decoding Refresh Type must be comprised between 0 and 3 included" );
    
      if(m_iDecodingRefreshType == 3)
      {
        xConfirmPara( !m_recoveryPointSEIEnabled,                                               "When using RecoveryPointSEI messages as RA points, recoveryPointSEI must be enabled" );
      }
    
        if (!m_frameFieldInfoSEIEnabled)
        {
          msg( WARNING, "*************************************************************************************\n");
          msg( WARNING, "** WARNING: Frame field information SEI should be enabled for field coding!        **\n");
          msg( WARNING, "*************************************************************************************\n");
        }
    
      if ( m_pictureTimingSEIEnabled && (!m_bufferingPeriodSEIEnabled))
      {
        msg( WARNING, "****************************************************************************\n");
        msg( WARNING, "** WARNING: Picture Timing SEI requires Buffering Period SEI. Disabling.  **\n");
        msg( WARNING, "****************************************************************************\n");
        m_pictureTimingSEIEnabled = false;
      }
    
    
      if(m_crossComponentPredictionEnabledFlag && (m_chromaFormatIDC != CHROMA_444))
      {
        msg( WARNING, "****************************************************************************\n");
        msg( WARNING, "** WARNING: Cross-component prediction is specified for 4:4:4 format only **\n");
        msg( WARNING, "****************************************************************************\n");
    
        m_crossComponentPredictionEnabledFlag = false;
      }
    
    
      xConfirmPara( m_bufferingPeriodSEIEnabled == true && m_RCCpbSize == 0,  "RCCpbSize must be greater than zero, when buffering period SEI is enabled" );
    
    
    #if !JVET_P2001_REMOVE_TRANSQUANT_BYPASS
    
      if ( m_CUTransquantBypassFlagForce && m_bUseHADME )
      {
        msg( WARNING, "****************************************************************************\n");
        msg( WARNING, "** WARNING: --HadamardME has been disabled due to the enabling of         **\n");
        msg( WARNING, "**          --CUTransquantBypassFlagForce                                 **\n");
        msg( WARNING, "****************************************************************************\n");
    
        m_bUseHADME = false; // this has been disabled so that the lambda is calculated slightly differently for lossless modes (as a result of JCTVC-R0104).
      }
    
    
      xConfirmPara (m_log2MaxTransformSkipBlockSize < 2, "Transform Skip Log2 Max Size must be at least 2 (4x4)");
    
    
      if( m_SubPuMvpMode == 3 && m_maxNumMergeCand < 7 )
      {
        msg( WARNING, "****************************************************************************\n" );
        msg( WARNING, "** WARNING: Allowing less than 7 merge candidates, although both          **\n" );
        msg( WARNING, "**          advanced sup-pu temporal merging modes are enabled.           **\n" );
        msg( WARNING, "****************************************************************************\n" );
      }
      else if( m_SubPuMvpMode != 0 && m_maxNumMergeCand < 6 )
      {
        msg( WARNING, "****************************************************************************\n" );
        msg( WARNING, "** WARNING: Allowing less than 6 merge candidates, although               **\n" );
        msg( WARNING, "**          an advanced sup-pu temporal merging mode is enabled.          **\n" );
        msg( WARNING, "****************************************************************************\n" );
      }
      xConfirmPara( m_iQP < -6 * (m_internalBitDepth[CHANNEL_TYPE_LUMA] - 8) || m_iQP > MAX_QP, "QP exceeds supported range (-QpBDOffsety to 63)" );
    #if W0038_DB_OPT
      xConfirmPara( m_deblockingFilterMetric!=0 && (m_bLoopFilterDisable || m_loopFilterOffsetInPPS), "If DeblockingFilterMetric is non-zero then both LoopFilterDisable and LoopFilterOffsetInPPS must be 0");
    #else
      xConfirmPara( m_DeblockingFilterMetric && (m_bLoopFilterDisable || m_loopFilterOffsetInPPS), "If DeblockingFilterMetric is true then both LoopFilterDisable and LoopFilterOffsetInPPS must be 0");
    #endif
      xConfirmPara( m_loopFilterBetaOffsetDiv2 < -6 || m_loopFilterBetaOffsetDiv2 > 6,          "Loop Filter Beta Offset div. 2 exceeds supported range (-6 to 6)" );
      xConfirmPara( m_loopFilterTcOffsetDiv2 < -6 || m_loopFilterTcOffsetDiv2 > 6,              "Loop Filter Tc Offset div. 2 exceeds supported range (-6 to 6)" );
      xConfirmPara( m_iSearchRange < 0 ,                                                        "Search Range must be more than 0" );
      xConfirmPara( m_bipredSearchRange < 0 ,                                                   "Bi-prediction refinement search range must be more than 0" );
      xConfirmPara( m_minSearchWindow < 0,                                                      "Minimum motion search window size for the adaptive window ME must be greater than or equal to 0" );
      xConfirmPara( m_iMaxDeltaQP > MAX_DELTA_QP,                                               "Absolute Delta QP exceeds supported range (0 to 7)" );
    
    #if ENABLE_QPA
      xConfirmPara( m_bUsePerceptQPA && m_uiDeltaQpRD > 0,                                      "Perceptual QPA cannot be used together with slice-level multiple-QP optimization" );
    #endif
    
    #if SHARP_LUMA_DELTA_QP
      xConfirmPara( m_lumaLevelToDeltaQPMapping.mode && m_uiDeltaQpRD > 0,                      "Luma-level-based Delta QP cannot be used together with slice level multiple-QP optimization\n" );
    #endif
    
      if (m_lumaLevelToDeltaQPMapping.mode && m_lmcsEnabled)
    
    Taoran Lu's avatar
    Taoran Lu committed
    #if !JVET_P0335_HDRCTC_CHANGE
    
        msg(WARNING, "For HDR-PQ, reshaper should be used mutual-exclusively with Luma-level-based Delta QP. If use luma DQP, turn reshaper off.\n");
    
    Taoran Lu's avatar
    Taoran Lu committed
    #else
        msg(WARNING, "For HDR-PQ, LMCS should be used mutual-exclusively with Luma-level-based Delta QP. If use LMCS, turn lumaDQP off.\n");
        m_lumaLevelToDeltaQPMapping.mode = LUMALVL_TO_DQP_DISABLED;
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
        m_reshapeSignalType = RESHAPE_SIGNAL_NULL;
        m_intraCMD = 0;
    
      if (m_lmcsEnabled && m_reshapeSignalType == RESHAPE_SIGNAL_PQ)
    
    Taoran Lu's avatar
    Taoran Lu committed
        m_intraCMD = 1;
    
      else if (m_lmcsEnabled && (m_reshapeSignalType == RESHAPE_SIGNAL_SDR || m_reshapeSignalType == RESHAPE_SIGNAL_HLG))
    
    Taoran Lu's avatar
    Taoran Lu committed
        m_intraCMD = 0;
    
      {
        xConfirmPara(m_updateCtrl < 0, "Min. LMCS Update Control is 0");
        xConfirmPara(m_updateCtrl > 2, "Max. LMCS Update Control is 2");
        xConfirmPara(m_adpOption < 0, "Min. LMCS Adaptation Option is 0");
        xConfirmPara(m_adpOption > 4, "Max. LMCS Adaptation Option is 4");
        xConfirmPara(m_initialCW < 0, "Min. Initial Total Codeword is 0");
        xConfirmPara(m_initialCW > 1023, "Max. Initial Total Codeword is 1023");
    
    #if JVET_P0371_CHROMA_SCALING_OFFSET
        xConfirmPara(m_CSoffset < -7, "Min. LMCS Offset value is -7");
        xConfirmPara(m_CSoffset > 7, "Max. LMCS Offset value is 7");
    #endif
    
        if (m_updateCtrl > 0 && m_adpOption > 2) { m_adpOption -= 2; }
      }
    
    
      xConfirmPara( m_cbQpOffset < -12,   "Min. Chroma Cb QP Offset is -12" );
      xConfirmPara( m_cbQpOffset >  12,   "Max. Chroma Cb QP Offset is  12" );
      xConfirmPara( m_crQpOffset < -12,   "Min. Chroma Cr QP Offset is -12" );
      xConfirmPara( m_crQpOffset >  12,   "Max. Chroma Cr QP Offset is  12" );
      xConfirmPara( m_cbQpOffsetDualTree < -12,   "Min. Chroma Cb QP Offset for dual tree is -12" );
      xConfirmPara( m_cbQpOffsetDualTree >  12,   "Max. Chroma Cb QP Offset for dual tree is  12" );
      xConfirmPara( m_crQpOffsetDualTree < -12,   "Min. Chroma Cr QP Offset for dual tree is -12" );
      xConfirmPara( m_crQpOffsetDualTree >  12,   "Max. Chroma Cr QP Offset for dual tree is  12" );
    
      if (m_JointCbCrMode && (m_chromaFormatIDC == CHROMA_400))
    
    Fangdong Chen's avatar
    Fangdong Chen committed
      {
        msg( WARNING, "****************************************************************************\n");
    
        msg( WARNING, "** WARNING: --JointCbCr has been disabled because the chromaFormat is 400 **\n");
    
    Fangdong Chen's avatar
    Fangdong Chen committed
        msg( WARNING, "****************************************************************************\n");
    
        m_JointCbCrMode = false;
    
      if (m_JointCbCrMode)
    
    Fangdong Chen's avatar
    Fangdong Chen committed
      {
    
    Fangdong Chen's avatar
    Fangdong Chen committed
        xConfirmPara( m_cbCrQpOffset < -12, "Min. Joint Cb-Cr QP Offset is -12");
        xConfirmPara( m_cbCrQpOffset >  12, "Max. Joint Cb-Cr QP Offset is  12");
        xConfirmPara( m_cbCrQpOffsetDualTree < -12, "Min. Joint Cb-Cr QP Offset for dual tree is -12");
        xConfirmPara( m_cbCrQpOffsetDualTree >  12, "Max. Joint Cb-Cr QP Offset for dual tree is  12");
    
    Fangdong Chen's avatar
    Fangdong Chen committed
      }
    
      xConfirmPara( m_iQPAdaptationRange <= 0,                                                  "QP Adaptation Range must be more than 0" );
      if (m_iDecodingRefreshType == 2)
      {
        xConfirmPara( m_iIntraPeriod > 0 && m_iIntraPeriod <= m_iGOPSize ,                      "Intra period must be larger than GOP size for periodic IDR pictures");
      }
      xConfirmPara( m_uiMaxCUDepth > MAX_CU_DEPTH,                                              "MaxPartitionDepth exceeds predefined MAX_CU_DEPTH limit");
      xConfirmPara( m_uiMaxCUWidth > MAX_CU_SIZE,                                               "MaxCUWith exceeds predefined MAX_CU_SIZE limit");
    
      xConfirmPara( m_uiMinQT[0] < 1<<MIN_CU_LOG2,                                              "Minimum QT size should be larger than or equal to 4");
      xConfirmPara( m_uiMinQT[1] < 1<<MIN_CU_LOG2,                                              "Minimum QT size should be larger than or equal to 4");
    
      xConfirmPara( m_uiCTUSize < 32,                                                           "CTUSize must be greater than or equal to 32");
      xConfirmPara( m_uiCTUSize > 128,                                                          "CTUSize must be less than or equal to 128");
      xConfirmPara( m_uiCTUSize != 32 && m_uiCTUSize != 64 && m_uiCTUSize != 128,               "CTUSize must be a power of 2 (32, 64, or 128)");
    
      xConfirmPara( m_uiMaxCUDepth < 1,                                                         "MaxPartitionDepth must be greater than zero");
      xConfirmPara( (m_uiMaxCUWidth  >> m_uiMaxCUDepth) < 4,                                    "Minimum partition width size should be larger than or equal to 8");
      xConfirmPara( (m_uiMaxCUHeight >> m_uiMaxCUDepth) < 4,                                    "Minimum partition height size should be larger than or equal to 8");
      xConfirmPara( m_uiMaxCUWidth < 16,                                                        "Maximum partition width size should be larger than or equal to 16");
      xConfirmPara( m_uiMaxCUHeight < 16,                                                       "Maximum partition height size should be larger than or equal to 16");
    
      xConfirmPara( (m_iSourceWidth  % (std::max(8, int(m_uiMaxCUWidth  >> (m_uiMaxCUDepth - 1))))) != 0, "Resulting coded frame width must be a multiple of Max(8, the minimum CU size)");
      xConfirmPara( (m_iSourceHeight % (std::max(8, int(m_uiMaxCUHeight >> (m_uiMaxCUDepth - 1))))) != 0, "Resulting coded frame height must be a multiple of Max(8, the minimum CU size)");
    
      xConfirmPara( m_log2MaxTbSize > 6, "Log2MaxTbSize must be 6 or smaller." );
    
    Yan Zhang's avatar
    Yan Zhang committed
      xConfirmPara( m_log2MaxTbSize < 5,  "Log2MaxTbSize must be 5 or greater." );
    
      xConfirmPara( m_maxNumMergeCand < 1,  "MaxNumMergeCand must be 1 or greater.");
      xConfirmPara( m_maxNumMergeCand > MRG_MAX_NUM_CANDS, "MaxNumMergeCand must be no more than MRG_MAX_NUM_CANDS." );
    
      xConfirmPara( m_maxNumTriangleCand > TRIANGLE_MAX_NUM_UNI_CANDS, "MaxNumTriangleCand must be no more than TRIANGLE_MAX_NUM_UNI_CANDS." );
      xConfirmPara( m_maxNumTriangleCand > m_maxNumMergeCand, "MaxNumTriangleCand must be no more than MaxNumMergeCand." );
      xConfirmPara( 0 < m_maxNumTriangleCand && m_maxNumTriangleCand < 2, "MaxNumTriangleCand must be no less than 2 unless MaxNumTriangleCand is 0." );
    
    Yan Zhang's avatar
    Yan Zhang committed
      xConfirmPara( m_maxNumIBCMergeCand < 1, "MaxNumIBCMergeCand must be 1 or greater." );
      xConfirmPara( m_maxNumIBCMergeCand > IBC_MRG_MAX_NUM_CANDS, "MaxNumIBCMergeCand must be no more than IBC_MRG_MAX_NUM_CANDS." );
    
      xConfirmPara( m_maxNumAffineMergeCand < 1, "MaxNumAffineMergeCand must be 1 or greater." );
    
      xConfirmPara( m_maxNumAffineMergeCand > AFFINE_MRG_MAX_NUM_CANDS, "MaxNumAffineMergeCand must be no more than AFFINE_MRG_MAX_NUM_CANDS." );
    
      if ( m_Affine == 0 )
      {
        m_maxNumAffineMergeCand = m_SubPuMvpMode;
    
        if (m_PROF) msg(WARNING, "PROF is forcefully disabled when Affine is off \n");
        m_PROF = false;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      xConfirmPara( m_MTS < 0 || m_MTS > 3, "MTS must be greater than 0 smaller than 4" );
      xConfirmPara( m_MTSIntraMaxCand < 0 || m_MTSIntraMaxCand > 5, "m_MTSIntraMaxCand must be greater than 0 and smaller than 6" );
      xConfirmPara( m_MTSInterMaxCand < 0 || m_MTSInterMaxCand > 5, "m_MTSInterMaxCand must be greater than 0 and smaller than 6" );
    
    Jani Lainema's avatar
    Jani Lainema committed
      xConfirmPara( m_MTS != 0 && m_MTSImplicit != 0, "Both explicit and implicit MTS cannot be enabled at the same time" );
    
    Xiang Li's avatar
    Xiang Li committed
      if (m_useBDPCM)
      {
        xConfirmPara(!m_useTransformSkip, "BDPCM cannot be used when transform skip is disabled.");
      }
    
    
    #if !JVET_P1004_REMOVE_BRICKS
    
      if (m_sliceMode!=NO_SLICES)
      {
        xConfirmPara( m_sliceArgument < 1 ,         "SliceArgument should be larger than or equal to 1" );
      }
    
    #endif
    
    #if !JVET_P1004_REMOVE_BRICKS
    
      bool tileFlag = (m_numTileColumnsMinus1 > 0 || m_numTileRowsMinus1 > 0 );
      if (m_profile!=Profile::HIGHTHROUGHPUTREXT)
      {
        xConfirmPara( tileFlag && m_entropyCodingSyncEnabledFlag, "Tiles and entropy-coding-sync (Wavefronts) can not be applied together, except in the High Throughput Intra 4:4:4 16 profile");
      }
    
    #endif
    
    
      xConfirmPara( m_iSourceWidth  % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Picture width must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_iSourceHeight % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Picture height must be an integer multiple of the specified chroma subsampling");
    
      xConfirmPara( m_aiPad[0] % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Horizontal padding must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_aiPad[1] % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Vertical padding must be an integer multiple of the specified chroma subsampling");
    
      xConfirmPara( m_confWinLeft   % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Left conformance window offset must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_confWinRight  % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Right conformance window offset must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_confWinTop    % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Top conformance window offset must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_confWinBottom % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Bottom conformance window offset must be an integer multiple of the specified chroma subsampling");
    
    
      // max CU width and height should be power of 2
      uint32_t ui = m_uiMaxCUWidth;
      while(ui)
      {
        ui >>= 1;
        if( (ui & 1) == 1)
        {
          xConfirmPara( ui != 1 , "Width should be 2^n");
        }
      }
      ui = m_uiMaxCUHeight;
      while(ui)
      {
        ui >>= 1;
        if( (ui & 1) == 1)
        {
          xConfirmPara( ui != 1 , "Height should be 2^n");
        }
      }
    
      /* if this is an intra-only sequence, ie IntraPeriod=1, don't verify the GOP structure
       * This permits the ability to omit a GOP structure specification */
      if (m_iIntraPeriod == 1 && m_GOPList[0].m_POC == -1)
      {
        m_GOPList[0] = GOPEntry();
        m_GOPList[0].m_QPFactor = 1;
        m_GOPList[0].m_betaOffsetDiv2 = 0;
        m_GOPList[0].m_tcOffsetDiv2 = 0;
        m_GOPList[0].m_POC = 1;
    
    Hendry's avatar
    Hendry committed
        m_RPLList0[0] = RPLEntry();
        m_RPLList1[0] = RPLEntry();
        m_RPLList0[0].m_POC = m_RPLList1[0].m_POC = 1;
        m_RPLList0[0].m_numRefPicsActive = 4;
        m_GOPList[0].m_numRefPicsActive0 = 4;
    
      }
      else
      {
        xConfirmPara( m_intraConstraintFlag, "IntraConstraintFlag cannot be 1 for inter sequences");
      }
    
    
      int multipleFactor = m_compositeRefEnabled ? 2 : 1;
    
      bool verifiedGOP=false;
      bool errorGOP=false;
      int checkGOP=1;
      int numRefs = m_isField ? 2 : 1;
    
      int refList[MAX_NUM_REF_PICS+1] = {0};
    
      if(m_isField)
      {
        refList[1] = 1;
      }
      bool isOK[MAX_GOP];
      for(int i=0; i<MAX_GOP; i++)
      {
        isOK[i]=false;
      }
      int numOK=0;
      xConfirmPara( m_iIntraPeriod >=0&&(m_iIntraPeriod%m_iGOPSize!=0), "Intra period must be a multiple of GOPSize, or -1" );
    
      for(int i=0; i<m_iGOPSize; i++)
      {
    
        if (m_GOPList[i].m_POC == m_iGOPSize * multipleFactor)
    
        {
          xConfirmPara( m_GOPList[i].m_temporalId!=0 , "The last frame in each GOP must have temporal ID = 0 " );
        }
      }
    
      if ( (m_iIntraPeriod != 1) && !m_loopFilterOffsetInPPS && (!m_bLoopFilterDisable) )
      {
        for(int i=0; i<m_iGOPSize; i++)
        {
          xConfirmPara( (m_GOPList[i].m_betaOffsetDiv2 + m_loopFilterBetaOffsetDiv2) < -6 || (m_GOPList[i].m_betaOffsetDiv2 + m_loopFilterBetaOffsetDiv2) > 6, "Loop Filter Beta Offset div. 2 for one of the GOP entries exceeds supported range (-6 to 6)" );
          xConfirmPara( (m_GOPList[i].m_tcOffsetDiv2 + m_loopFilterTcOffsetDiv2) < -6 || (m_GOPList[i].m_tcOffsetDiv2 + m_loopFilterTcOffsetDiv2) > 6, "Loop Filter Tc Offset div. 2 for one of the GOP entries exceeds supported range (-6 to 6)" );
        }
      }
    
    #if W0038_CQP_ADJ
      for(int i=0; i<m_iGOPSize; i++)
      {
        xConfirmPara( abs(m_GOPList[i].m_CbQPoffset               ) > 12, "Cb QP Offset for one of the GOP entries exceeds supported range (-12 to 12)" );
        xConfirmPara( abs(m_GOPList[i].m_CbQPoffset + m_cbQpOffset) > 12, "Cb QP Offset for one of the GOP entries, when combined with the PPS Cb offset, exceeds supported range (-12 to 12)" );
        xConfirmPara( abs(m_GOPList[i].m_CrQPoffset               ) > 12, "Cr QP Offset for one of the GOP entries exceeds supported range (-12 to 12)" );
        xConfirmPara( abs(m_GOPList[i].m_CrQPoffset + m_crQpOffset) > 12, "Cr QP Offset for one of the GOP entries, when combined with the PPS Cr offset, exceeds supported range (-12 to 12)" );
      }
      xConfirmPara( abs(m_sliceChromaQpOffsetIntraOrPeriodic[0]                 ) > 12, "Intra/periodic Cb QP Offset exceeds supported range (-12 to 12)" );
      xConfirmPara( abs(m_sliceChromaQpOffsetIntraOrPeriodic[0]  + m_cbQpOffset ) > 12, "Intra/periodic Cb QP Offset, when combined with the PPS Cb offset, exceeds supported range (-12 to 12)" );
      xConfirmPara( abs(m_sliceChromaQpOffsetIntraOrPeriodic[1]                 ) > 12, "Intra/periodic Cr QP Offset exceeds supported range (-12 to 12)" );
      xConfirmPara( abs(m_sliceChromaQpOffsetIntraOrPeriodic[1]  + m_crQpOffset ) > 12, "Intra/periodic Cr QP Offset, when combined with the PPS Cr offset, exceeds supported range (-12 to 12)" );
    #endif
    
    
      xConfirmPara( m_fastLocalDualTreeMode < 0 || m_fastLocalDualTreeMode > 2, "FastLocalDualTreeMode must be in range [0..2]" );
    
    
    Hendry's avatar
    Hendry committed
      int extraRPLs = 0;
      //start looping through frames in coding order until we can verify that the GOP structure is correct.
      while (!verifiedGOP && !errorGOP)
      {
        int curGOP = (checkGOP - 1) % m_iGOPSize;
        int curPOC = ((checkGOP - 1) / m_iGOPSize)*m_iGOPSize * multipleFactor + m_RPLList0[curGOP].m_POC;
        if (m_RPLList0[curGOP].m_POC < 0 || m_RPLList1[curGOP].m_POC < 0)
        {
          msg(WARNING, "\nError: found fewer Reference Picture Sets than GOPSize\n");
          errorGOP = true;
        }
        else
        {
          //check that all reference pictures are available, or have a POC < 0 meaning they might be available in the next GOP.
          bool beforeI = false;
          for (int i = 0; i< m_RPLList0[curGOP].m_numRefPics; i++)
          {
            int absPOC = curPOC - m_RPLList0[curGOP].m_deltaRefPics[i];
            if (absPOC < 0)
            {
              beforeI = true;
            }
            else
            {
              bool found = false;
              for (int j = 0; j<numRefs; j++)
              {
                if (refList[j] == absPOC)
                {
                  found = true;
                  for (int k = 0; k<m_iGOPSize; k++)
                  {
                    if (absPOC % (m_iGOPSize * multipleFactor) == m_RPLList0[k].m_POC % (m_iGOPSize * multipleFactor))
                    {
                      if (m_RPLList0[k].m_temporalId == m_RPLList0[curGOP].m_temporalId)
                      {
                        m_RPLList0[k].m_refPic = true;
                      }
                    }
                  }
                }
              }
              if (!found)
              {
                msg(WARNING, "\nError: ref pic %d is not available for GOP frame %d\n", m_RPLList0[curGOP].m_deltaRefPics[i], curGOP + 1);
                errorGOP = true;
              }
            }
          }
          if (!beforeI && !errorGOP)
          {
            //all ref frames were present
            if (!isOK[curGOP])
            {
              numOK++;
              isOK[curGOP] = true;
              if (numOK == m_iGOPSize)
              {
                verifiedGOP = true;
              }
            }
          }
          else
          {
            //create a new RPLEntry for this frame containing all the reference pictures that were available (POC > 0)
            m_RPLList0[m_iGOPSize + extraRPLs] = m_RPLList0[curGOP];
            m_RPLList1[m_iGOPSize + extraRPLs] = m_RPLList1[curGOP];
            int newRefs0 = 0;
            for (int i = 0; i< m_RPLList0[curGOP].m_numRefPics; i++)
            {
              int absPOC = curPOC - m_RPLList0[curGOP].m_deltaRefPics[i];
              if (absPOC >= 0)
              {
                m_RPLList0[m_iGOPSize + extraRPLs].m_deltaRefPics[newRefs0] = m_RPLList0[curGOP].m_deltaRefPics[i];
                newRefs0++;
              }
            }
            int numPrefRefs0 = m_RPLList0[curGOP].m_numRefPicsActive;
    
            int newRefs1 = 0;
            for (int i = 0; i< m_RPLList1[curGOP].m_numRefPics; i++)
            {
              int absPOC = curPOC - m_RPLList1[curGOP].m_deltaRefPics[i];
              if (absPOC >= 0)
              {
                m_RPLList1[m_iGOPSize + extraRPLs].m_deltaRefPics[newRefs1] = m_RPLList1[curGOP].m_deltaRefPics[i];
                newRefs1++;
              }
            }
            int numPrefRefs1 = m_RPLList1[curGOP].m_numRefPicsActive;
    
            for (int offset = -1; offset>-checkGOP; offset--)
            {
              //step backwards in coding order and include any extra available pictures we might find useful to replace the ones with POC < 0.
              int offGOP = (checkGOP - 1 + offset) % m_iGOPSize;
              int offPOC = ((checkGOP - 1 + offset) / m_iGOPSize)*(m_iGOPSize * multipleFactor) + m_RPLList0[offGOP].m_POC;
              if (offPOC >= 0 && m_RPLList0[offGOP].m_temporalId <= m_RPLList0[curGOP].m_temporalId)
              {
                bool newRef = false;
                for (int i = 0; i<(newRefs0 + newRefs1); i++)
                {
                  if (refList[i] == offPOC)
                  {
                    newRef = true;
                  }
                }
                for (int i = 0; i<newRefs0; i++)
                {
                  if (m_RPLList0[m_iGOPSize + extraRPLs].m_deltaRefPics[i] == curPOC - offPOC)
                  {
                    newRef = false;
                  }
                }
                if (newRef)
                {
                  int insertPoint = newRefs0;
                  //this picture can be added, find appropriate place in list and insert it.
                  if (m_RPLList0[offGOP].m_temporalId == m_RPLList0[curGOP].m_temporalId)
                  {
                    m_RPLList0[offGOP].m_refPic = true;
                  }
                  for (int j = 0; j<newRefs0; j++)
                  {
                    if (m_RPLList0[m_iGOPSize + extraRPLs].m_deltaRefPics[j] > curPOC - offPOC && curPOC - offPOC > 0)
                    {
                      insertPoint = j;
                      break;
                    }
                  }
                  int prev = curPOC - offPOC;
                  for (int j = insertPoint; j<newRefs0 + 1; j++)
                  {
                    int newPrev = m_RPLList0[m_iGOPSize + extraRPLs].m_deltaRefPics[j];
                    m_RPLList0[m_iGOPSize + extraRPLs].m_deltaRefPics[j] = prev;
                    prev = newPrev;
                  }
                  newRefs0++;
                }
              }
              if (newRefs0 >= numPrefRefs0)
              {
                break;
              }
            }
    
            for (int offset = -1; offset>-checkGOP; offset--)
            {
              //step backwards in coding order and include any extra available pictures we might find useful to replace the ones with POC < 0.
              int offGOP = (checkGOP - 1 + offset) % m_iGOPSize;
              int offPOC = ((checkGOP - 1 + offset) / m_iGOPSize)*(m_iGOPSize * multipleFactor) + m_RPLList1[offGOP].m_POC;
              if (offPOC >= 0 && m_RPLList1[offGOP].m_temporalId <= m_RPLList1[curGOP].m_temporalId)
              {
                bool newRef = false;
                for (int i = 0; i<(newRefs0 + newRefs1); i++)
                {
                  if (refList[i] == offPOC)
                  {
                    newRef = true;
                  }
                }
                for (int i = 0; i<newRefs1; i++)
                {
                  if (m_RPLList1[m_iGOPSize + extraRPLs].m_deltaRefPics[i] == curPOC - offPOC)
                  {
                    newRef = false;
                  }
                }
                if (newRef)
                {
                  int insertPoint = newRefs1;
                  //this picture can be added, find appropriate place in list and insert it.
                  if (m_RPLList1[offGOP].m_temporalId == m_RPLList1[curGOP].m_temporalId)
                  {
                    m_RPLList1[offGOP].m_refPic = true;
                  }
                  for (int j = 0; j<newRefs1; j++)
                  {
                    if (m_RPLList1[m_iGOPSize + extraRPLs].m_deltaRefPics[j] > curPOC - offPOC && curPOC - offPOC > 0)
                    {
                      insertPoint = j;
                      break;
                    }
                  }
                  int prev = curPOC - offPOC;
                  for (int j = insertPoint; j<newRefs1 + 1; j++)
                  {
                    int newPrev = m_RPLList1[m_iGOPSize + extraRPLs].m_deltaRefPics[j];
                    m_RPLList1[m_iGOPSize + extraRPLs].m_deltaRefPics[j] = prev;
                    prev = newPrev;
                  }
                  newRefs1++;
                }
              }
              if (newRefs1 >= numPrefRefs1)
              {
                break;
              }
            }
    
            m_RPLList0[m_iGOPSize + extraRPLs].m_numRefPics = newRefs0;
            m_RPLList0[m_iGOPSize + extraRPLs].m_numRefPicsActive = min(m_RPLList0[m_iGOPSize + extraRPLs].m_numRefPics, m_RPLList0[m_iGOPSize + extraRPLs].m_numRefPicsActive);
            m_RPLList1[m_iGOPSize + extraRPLs].m_numRefPics = newRefs1;
            m_RPLList1[m_iGOPSize + extraRPLs].m_numRefPicsActive = min(m_RPLList1[m_iGOPSize + extraRPLs].m_numRefPics, m_RPLList1[m_iGOPSize + extraRPLs].m_numRefPicsActive);
            curGOP = m_iGOPSize + extraRPLs;
            extraRPLs++;
          }
          numRefs = 0;
          for (int i = 0; i< m_RPLList0[curGOP].m_numRefPics; i++)
          {
            int absPOC = curPOC - m_RPLList0[curGOP].m_deltaRefPics[i];
            if (absPOC >= 0)
            {
              refList[numRefs] = absPOC;
              numRefs++;
            }
          }
          for (int i = 0; i< m_RPLList1[curGOP].m_numRefPics; i++)
          {
            int absPOC = curPOC - m_RPLList1[curGOP].m_deltaRefPics[i];
            if (absPOC >= 0)
            {
              bool alreadyExist = false;
              for (int j = 0; !alreadyExist && j < numRefs; j++)
              {
                if (refList[j] == absPOC)
                {
                  alreadyExist = true;
                }
              }
              if (!alreadyExist)
              {
                refList[numRefs] = absPOC;
                numRefs++;
              }
            }
          }
          refList[numRefs] = curPOC;
          numRefs++;
        }
        checkGOP++;
      }
      xConfirmPara(errorGOP, "Invalid GOP structure given");
    
    
      for(int i=0; i<m_iGOPSize; i++)
      {
        if(m_GOPList[i].m_temporalId >= m_maxTempLayer)
        {
          m_maxTempLayer = m_GOPList[i].m_temporalId+1;
        }
        xConfirmPara(m_GOPList[i].m_sliceType!='B' && m_GOPList[i].m_sliceType!='P' && m_GOPList[i].m_sliceType!='I', "Slice type must be equal to B or P or I");
      }
      for(int i=0; i<MAX_TLAYER; i++)
      {
        m_numReorderPics[i] = 0;
        m_maxDecPicBuffering[i] = 1;
      }
      for(int i=0; i<m_iGOPSize; i++)
      {
    
    Hendry's avatar
    Hendry committed
        int numRefPic = m_RPLList0[i].m_numRefPics;
        for (int tmp = 0; tmp < m_RPLList1[i].m_numRefPics; tmp++)
        {
          bool notSame = true;
          for (int jj = 0; notSame && jj < m_RPLList0[i].m_numRefPics; jj++)
          {
            if (m_RPLList1[i].m_deltaRefPics[tmp] == m_RPLList0[i].m_deltaRefPics[jj]) notSame = false;
          }
          if (notSame) numRefPic++;
        }
        if (numRefPic + 1 > m_maxDecPicBuffering[m_GOPList[i].m_temporalId])
        {
          m_maxDecPicBuffering[m_GOPList[i].m_temporalId] = numRefPic + 1;
        }
    
        int highestDecodingNumberWithLowerPOC = 0;
        for(int j=0; j<m_iGOPSize; j++)
        {
          if(m_GOPList[j].m_POC <= m_GOPList[i].m_POC)
          {
            highestDecodingNumberWithLowerPOC = j;
          }
        }
        int numReorder = 0;
        for(int j=0; j<highestDecodingNumberWithLowerPOC; j++)
        {
          if(m_GOPList[j].m_temporalId <= m_GOPList[i].m_temporalId &&
            m_GOPList[j].m_POC > m_GOPList[i].m_POC)
          {
            numReorder++;
          }
        }
        if(numReorder > m_numReorderPics[m_GOPList[i].m_temporalId])
        {
          m_numReorderPics[m_GOPList[i].m_temporalId] = numReorder;
        }
      }
    
      for(int i=0; i<MAX_TLAYER-1; i++)
      {
        // a lower layer can not have higher value of m_numReorderPics than a higher layer
        if(m_numReorderPics[i+1] < m_numReorderPics[i])
        {
          m_numReorderPics[i+1] = m_numReorderPics[i];
        }
        // the value of num_reorder_pics[ i ] shall be in the range of 0 to max_dec_pic_buffering[ i ] - 1, inclusive
        if(m_numReorderPics[i] > m_maxDecPicBuffering[i] - 1)
        {
          m_maxDecPicBuffering[i] = m_numReorderPics[i] + 1;
        }
        // a lower layer can not have higher value of m_uiMaxDecPicBuffering than a higher layer
        if(m_maxDecPicBuffering[i+1] < m_maxDecPicBuffering[i])
        {
          m_maxDecPicBuffering[i+1] = m_maxDecPicBuffering[i];
        }
      }
    
      // the value of num_reorder_pics[ i ] shall be in the range of 0 to max_dec_pic_buffering[ i ] -  1, inclusive
      if(m_numReorderPics[MAX_TLAYER-1] > m_maxDecPicBuffering[MAX_TLAYER-1] - 1)
      {
        m_maxDecPicBuffering[MAX_TLAYER-1] = m_numReorderPics[MAX_TLAYER-1] + 1;
      }
    
    
    #if JVET_P1004_REMOVE_BRICKS
      if( m_picPartitionFlag ) 
      {
        PPS pps;
        uint32_t colIdx, rowIdx;
        uint32_t remSize;
     
        pps.setPicWidthInLumaSamples( m_iSourceWidth );
        pps.setPicHeightInLumaSamples( m_iSourceHeight );
        pps.setLog2CtuSize( floorLog2(m_uiCTUSize) );
    
        // set default tile column if not provided
        if( m_tileColumnWidth.size() == 0 ) 
        {
          m_tileColumnWidth.push_back( pps.getPicWidthInCtu() );
        }
        // set default tile row if not provided
        if( m_tileRowHeight.size() == 0 ) 
        {
          m_tileRowHeight.push_back( pps.getPicHeightInCtu() );
        }
    
        // remove any tile columns that can be specified implicitly
        while( m_tileColumnWidth.size() > 1 && m_tileColumnWidth.end()[-1] == m_tileColumnWidth.end()[-2] )
        {
          m_tileColumnWidth.pop_back();
        }
    
        // remove any tile rows that can be specified implicitly
        while( m_tileRowHeight.size() > 1 && m_tileRowHeight.end()[-1] == m_tileRowHeight.end()[-2] )
        {
          m_tileRowHeight.pop_back();
        }
    
        // setup tiles in temporary PPS structure
        remSize = pps.getPicWidthInCtu();
        for( colIdx=0; remSize > 0 && colIdx<m_tileColumnWidth.size(); colIdx++ )
        {
          xConfirmPara(m_tileColumnWidth[ colIdx ] == 0, "Tile column widths cannot be equal to 0");
          m_tileColumnWidth[ colIdx ] = std::min( remSize, m_tileColumnWidth[ colIdx ]);
          pps.addTileColumnWidth( m_tileColumnWidth[ colIdx ] );
          remSize -= m_tileColumnWidth[ colIdx ];
        }
        m_tileColumnWidth.resize( colIdx );
        pps.setNumExpTileColumns( (uint32_t)m_tileColumnWidth.size() );    
        remSize = pps.getPicHeightInCtu();
        for( rowIdx=0; remSize > 0 && rowIdx<m_tileRowHeight.size(); rowIdx++ )
        {
          xConfirmPara(m_tileRowHeight[ rowIdx ] == 0, "Tile row heights cannot be equal to 0");
          m_tileRowHeight[ rowIdx ] = std::min( remSize, m_tileRowHeight[ rowIdx ]);
          pps.addTileRowHeight( m_tileRowHeight[ rowIdx ] );
          remSize -= m_tileRowHeight[ rowIdx ];
        }
        m_tileRowHeight.resize( rowIdx );
        pps.setNumExpTileRows( (uint32_t)m_tileRowHeight.size() );
        pps.initTiles();
        xConfirmPara(pps.getNumTileColumns() > getMaxTileColsByLevel( m_level ), "Number of tile columns exceeds maximum number allowed according to specified level");
        xConfirmPara(pps.getNumTileRows()    > getMaxTileRowsByLevel( m_level ), "Number of tile rows exceeds maximum number allowed according to specified level");
        m_numTileCols = pps.getNumTileColumns();
        m_numTileRows = pps.getNumTileRows();
    
        // rectangular slices
        if( !m_rasterSliceFlag )
        {
          uint32_t sliceIdx;
          bool     needTileIdxDelta = false;
    
          // generate slice list for the simplified fixed-rectangular-slice-size config option
          if( m_rectSliceFixedWidth > 0 && m_rectSliceFixedHeight > 0 )
          {
            int tileIdx = 0;
            m_rectSlicePos.clear();
            while( tileIdx < pps.getNumTiles() ) 
            {
              uint32_t startTileX = tileIdx % pps.getNumTileColumns();
              uint32_t startTileY = tileIdx / pps.getNumTileColumns();
              uint32_t startCtuX  = pps.getTileColumnBd( startTileX );
              uint32_t startCtuY  = pps.getTileRowBd( startTileY );
              uint32_t stopCtuX   = (startTileX + m_rectSliceFixedWidth)  >= pps.getNumTileColumns() ? pps.getPicWidthInCtu() - 1  : pps.getTileColumnBd( startTileX + m_rectSliceFixedWidth ) - 1;
              uint32_t stopCtuY   = (startTileY + m_rectSliceFixedHeight) >= pps.getNumTileRows()    ? pps.getPicHeightInCtu() - 1 : pps.getTileRowBd( startTileY + m_rectSliceFixedHeight ) - 1;
              uint32_t stopTileX  = pps.ctuToTileCol( stopCtuX );
              uint32_t stopTileY  = pps.ctuToTileRow( stopCtuY );
              
              // add rectangular slice to list
              m_rectSlicePos.push_back( startCtuY * pps.getPicWidthInCtu() + startCtuX );          
              m_rectSlicePos.push_back( stopCtuY  * pps.getPicWidthInCtu() + stopCtuX  );
              
              // get slice size in tiles
              uint32_t sliceWidth  = stopTileX - startTileX + 1;
              uint32_t sliceHeight = stopTileY - startTileY + 1;
    
              // move to next tile in raster scan order
              tileIdx += sliceWidth;
              if( tileIdx % pps.getNumTileColumns() == 0 )
              {
                tileIdx += (sliceHeight - 1) * pps.getNumTileColumns();
              }
            }
          }
    
          xConfirmPara( m_rectSlicePos.size() & 1, "Odd number of rectangular slice positions provided. Rectangular slice positions must be specified in pairs of (top-left / bottom-right) raster-scan CTU addresses.");
          
          // set default slice size if not provided
          if( m_rectSlicePos.size() == 0 ) 
          {
            m_rectSlicePos.push_back( 0 );
            m_rectSlicePos.push_back( pps.getPicWidthInCtu() * pps.getPicHeightInCtu() - 1 );
          }
          pps.setNumSlicesInPic( (uint32_t)(m_rectSlicePos.size() >> 1) );
          xConfirmPara(pps.getNumSlicesInPic() > getMaxSlicesByLevel( m_level ), "Number of rectangular slices exceeds maximum number allowed according to specified level");
          pps.initRectSlices();
    
          // set slice parameters from CTU addresses
          for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ )
          {
            xConfirmPara( m_rectSlicePos[2*sliceIdx]     >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture.");
            xConfirmPara( m_rectSlicePos[2*sliceIdx + 1] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture.");
    
            // map raster scan CTU address to X/Y position
            uint32_t startCtuX = m_rectSlicePos[2*sliceIdx]     % pps.getPicWidthInCtu();
            uint32_t startCtuY = m_rectSlicePos[2*sliceIdx]     / pps.getPicWidthInCtu();
            uint32_t stopCtuX  = m_rectSlicePos[2*sliceIdx + 1] % pps.getPicWidthInCtu();
            uint32_t stopCtuY  = m_rectSlicePos[2*sliceIdx + 1] / pps.getPicWidthInCtu();
            
            // get corresponding tile index
            uint32_t startTileX = pps.ctuToTileCol( startCtuX );
            uint32_t startTileY = pps.ctuToTileRow( startCtuY );
            uint32_t stopTileX  = pps.ctuToTileCol( stopCtuX );
            uint32_t stopTileY  = pps.ctuToTileRow( stopCtuY );
            uint32_t tileIdx    = startTileY * pps.getNumTileColumns() + startTileX;
    
            // get slice size in tiles
            uint32_t sliceWidth  = stopTileX - startTileX + 1;
            uint32_t sliceHeight = stopTileY - startTileY + 1;
            
            // check for slice / tile alignment
            xConfirmPara( startCtuX != pps.getTileColumnBd( startTileX ), "Rectangular slice position does not align with a left tile edge.");
            xConfirmPara( stopCtuX  != (pps.getTileColumnBd( stopTileX + 1 ) - 1), "Rectangular slice position does not align with a right tile edge.");
            if( sliceWidth > 1 || sliceHeight > 1 )
            {
              xConfirmPara( startCtuY != pps.getTileRowBd( startTileY ), "Rectangular slice position does not align with a top tile edge.");
              xConfirmPara( stopCtuY  != (pps.getTileRowBd( stopTileY + 1 ) - 1), "Rectangular slice position does not align with a bottom tile edge.");
            }
    
            // set slice size and tile index
            pps.setSliceWidthInTiles( sliceIdx, sliceWidth );
            pps.setSliceHeightInTiles( sliceIdx, sliceHeight );
            pps.setSliceTileIdx( sliceIdx, tileIdx );
            if( sliceIdx > 0 && !needTileIdxDelta )
            {
              uint32_t lastTileIdx = pps.getSliceTileIdx( sliceIdx-1 );
              lastTileIdx += pps.getSliceWidthInTiles( sliceIdx-1 );
              if( lastTileIdx % pps.getNumTileColumns() == 0)
              {
                lastTileIdx += (pps.getSliceHeightInTiles( sliceIdx-1 ) - 1) * pps.getNumTileColumns();
              }
              if( lastTileIdx != tileIdx )
              {
                needTileIdxDelta = true;
              }
            }
    
            // special case for multiple slices within a single tile
            if( sliceWidth == 1 && sliceHeight == 1 )
            {
              uint32_t firstSliceIdx = sliceIdx;
              uint32_t numSlicesInTile = 1;
              pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 );
              
              while( sliceIdx < pps.getNumSlicesInPic()-1 ) 
              {
                uint32_t nextTileIdx;
                startCtuX   = m_rectSlicePos[2*(sliceIdx+1)]     % pps.getPicWidthInCtu();
                startCtuY   = m_rectSlicePos[2*(sliceIdx+1)]     / pps.getPicWidthInCtu();
                stopCtuX    = m_rectSlicePos[2*(sliceIdx+1) + 1] % pps.getPicWidthInCtu();
                stopCtuY    = m_rectSlicePos[2*(sliceIdx+1) + 1] / pps.getPicWidthInCtu();          
                startTileX  = pps.ctuToTileCol( startCtuX );
                startTileY  = pps.ctuToTileRow( startCtuY );
                stopTileX   = pps.ctuToTileCol( stopCtuX );
                stopTileY   = pps.ctuToTileRow( stopCtuY );
                nextTileIdx = startTileY * pps.getNumTileColumns() + startTileX;
                sliceWidth  = stopTileX - startTileX + 1;
                sliceHeight = stopTileY - startTileY + 1;
                if(nextTileIdx != tileIdx || sliceWidth != 1 || sliceHeight != 1) 
                {
                  break;
                }
                numSlicesInTile++;
                sliceIdx++;
                pps.setSliceWidthInTiles( sliceIdx, 1 );
                pps.setSliceHeightInTiles( sliceIdx, 1 );
                pps.setSliceTileIdx( sliceIdx, tileIdx );    
                pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 );
              }
              pps.setNumSlicesInTile( firstSliceIdx, numSlicesInTile );
            }
          }
          pps.setTileIdxDeltaPresentFlag( needTileIdxDelta );
          m_tileIdxDeltaPresentFlag = needTileIdxDelta;
          
          // check rectangular slice mapping and full picture CTU coverage
          pps.initRectSliceMap();
    
          // store rectangular slice parameters from temporary PPS structure
          m_numSlicesInPic = pps.getNumSlicesInPic();
          m_rectSlices.resize( pps.getNumSlicesInPic() );
          for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ )
          {
            m_rectSlices[sliceIdx].setSliceWidthInTiles( pps.getSliceWidthInTiles(sliceIdx) );
            m_rectSlices[sliceIdx].setSliceHeightInTiles( pps.getSliceHeightInTiles(sliceIdx) );
            m_rectSlices[sliceIdx].setNumSlicesInTile( pps.getNumSlicesInTile(sliceIdx) );
            m_rectSlices[sliceIdx].setSliceHeightInCtu( pps.getSliceHeightInCtu(sliceIdx) );
            m_rectSlices[sliceIdx].setTileIdx( pps.getSliceTileIdx(sliceIdx) );
          }
        }
        // raster-scan slices
        else
        {
          uint32_t listIdx = 0;
          uint32_t remTiles = pps.getNumTiles();
    
          // set default slice size if not provided
          if( m_rasterSliceSize.size() == 0 ) 
          {
            m_rasterSliceSize.push_back( remTiles );
          }
    
          // set raster slice sizes
          while( remTiles > 0 )
          {
            // truncate if size exceeds number of remaining tiles
            if( listIdx < m_rasterSliceSize.size() )
            {
              m_rasterSliceSize[listIdx] = std::min( remTiles, m_rasterSliceSize[listIdx] );
              remTiles -= m_rasterSliceSize[listIdx];
            }
            // replicate last size uniformly as needed to cover the remainder of the picture
            else
            {
              m_rasterSliceSize.push_back( std::min( remTiles, m_rasterSliceSize.back() ) );
              remTiles -= m_rasterSliceSize.back();
            }
            listIdx++;
          }
          // shrink list if too many sizes were provided
          m_rasterSliceSize.resize( listIdx );
          
          m_numSlicesInPic = (uint32_t)m_rasterSliceSize.size();
          xConfirmPara(m_rasterSliceSize.size() > getMaxSlicesByLevel( m_level ), "Number of raster-scan slices exceeds maximum number allowed according to specified level");
        }
      }
      else 
      {
        m_numTileCols = 1;
        m_numTileRows = 1;
        m_numSlicesInPic = 1;
      }
    #else
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      for (int i=0; i<MAX_TILES; i++)
      {
        if (m_brickSplits[i].m_tileIdx>=0)
        {
          m_brickSplitMap[m_brickSplits[i].m_tileIdx] = m_brickSplits[i];
          // ToDo: check that brick dimensions don't exceed tile dimensions
        }
      }
    
    #endif