Skip to content
Snippets Groups Projects
EncAppCfg.cpp 314 KiB
Newer Older
  • Learn to ignore specific revisions
  •   bool check_sps_range_extension_flag = m_extendedPrecisionProcessingFlag || 
    
                                      m_rrcRiceExtensionEnableFlag ||
                                      m_persistentRiceAdaptationEnabledFlag || 
                                      m_tsrcRicePresentFlag;
      if (m_internalBitDepth[CHANNEL_TYPE_LUMA] <= 10)
    
        xConfirmPara( (check_sps_range_extension_flag == 1) ,
    
                     "RExt tools (Extended Precision Processing, RRC Rice Extension, Persistent Rice Adaptation and TSRC Rice Extension) must be disabled for BitDepth is less than or equal to 10 (the value of sps_range_extension_flag shall be 0 when BitDepth is less than or equal to 10.)");
    #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_edrapPeriod < 0,                                                          "EDRAP 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_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;
      }
    
      xConfirmPara( m_bufferingPeriodSEIEnabled == true && m_RCCpbSize == 0,  "RCCpbSize must be greater than zero, when buffering period SEI is enabled" );
    
    
      xConfirmPara (m_log2MaxTransformSkipBlockSize < 2, "Transform Skip Log2 Max Size must be at least 2 (4x4)");
    
    
      xConfirmPara ( m_onePictureOnlyConstraintFlag && m_framesToBeEncoded!=1, "When onePictureOnlyConstraintFlag is true, the number of frames to be encoded must be 1" );
    
      if (m_profile != Profile::NONE)
      {
        const ProfileFeatures *features = ProfileFeatures::getProfileFeatures(m_profile);
        CHECK(features->profile != m_profile, "Profile not found");
        xConfirmPara(m_level == Level::LEVEL15_5 && !features->canUseLevel15p5, "Profile does not support level 15.5");
      }
    
    
      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_deblockingFilterDisable || m_deblockingFilterOffsetInPPS), "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_deblockingFilterBetaOffsetDiv2 < -12 || m_deblockingFilterBetaOffsetDiv2 > 12,          "Loop Filter Beta Offset div. 2 exceeds supported range (-12 to 12" );
      xConfirmPara( m_deblockingFilterTcOffsetDiv2 < -12 || m_deblockingFilterTcOffsetDiv2 > 12,              "Loop Filter Tc Offset div. 2 exceeds supported range (-12 to 12)" );
      xConfirmPara( m_deblockingFilterCbBetaOffsetDiv2 < -12 || m_deblockingFilterCbBetaOffsetDiv2 > 12,      "Loop Filter Beta Offset div. 2 exceeds supported range (-12 to 12" );
      xConfirmPara( m_deblockingFilterCbTcOffsetDiv2 < -12 || m_deblockingFilterCbTcOffsetDiv2 > 12,          "Loop Filter Tc Offset div. 2 exceeds supported range (-12 to 12)" );
      xConfirmPara( m_deblockingFilterCrBetaOffsetDiv2 < -12 || m_deblockingFilterCrBetaOffsetDiv2 > 12,      "Loop Filter Beta Offset div. 2 exceeds supported range (-12 to 12" );
      xConfirmPara( m_deblockingFilterCrTcOffsetDiv2 < -12 || m_deblockingFilterCrTcOffsetDiv2 > 12,          "Loop Filter Tc Offset div. 2 exceeds supported range (-12 to 12)" );
    
      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" );
    
      xConfirmPara( m_lumaLevelToDeltaQPMapping.mode && m_RCEnableRateControl,                  "Luma-level-based Delta QP cannot be used together with rate control\n" );
    
      if (m_lumaLevelToDeltaQPMapping.mode && m_lmcsEnabled)
    
    Taoran Lu's avatar
    Taoran Lu committed
        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;
    
    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");
    
        xConfirmPara(m_CSoffset < -7, "Min. LMCS Offset value is -7");
        xConfirmPara(m_CSoffset > 7, "Max. LMCS Offset value is 7");
    
        if (m_updateCtrl > 0 && m_adpOption > 2) { m_adpOption -= 2; }
      }
    
      if (m_ctiSEIEnabled)
      {
        xConfirmPara(m_ctiSEINumberChromaLut < 0 || m_ctiSEINumberChromaLut > 2, "CTI number of chroma LUTs is out of range");
      }
    
      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_dualTree && (m_chromaFormatIDC == CHROMA_400))
      {
        msg( WARNING, "****************************************************************************\n");
        msg( WARNING, "** WARNING: --DualITree has been disabled because the chromaFormat is 400 **\n");
        msg( WARNING, "****************************************************************************\n");
        m_dualTree = false;
      }
    
        xConfirmPara(m_alfStrengthLuma < 0.0, "ALFStrengthLuma is less than 0. Valid range is 0.0 <= ALFStrengthLuma <= 1.0");
        xConfirmPara(m_alfStrengthLuma > 1.0, "ALFStrengthLuma is greater than 1. Valid range is 0.0 <= ALFStrengthLuma <= 1.0");
    
      if (m_ccalf)
      {
        xConfirmPara(m_ccalfStrength < 0.0, "CCALFStrength is less than 0. Valid range is 0.0 <= CCALFStrength <= 1.0");
        xConfirmPara(m_ccalfStrength > 1.0, "CCALFStrength is greater than 1. Valid range is 0.0 <= CCALFStrength <= 1.0");
    
      if (m_alf)
      {
        xConfirmPara(m_alfStrengthChroma < 0.0, "ALFStrengthChroma is less than 0. Valid range is 0.0 <= ALFStrengthChroma <= 1.0");
        xConfirmPara(m_alfStrengthChroma > 1.0, "ALFStrengthChroma is greater than 1. Valid range is 0.0 <= ALFStrengthChroma <= 1.0");
        xConfirmPara(m_alfStrengthTargetLuma < 0.0, "ALFStrengthTargetLuma is less than 0. Valid range is 0.0 <= ALFStrengthTargetLuma <= 1.0");
        xConfirmPara(m_alfStrengthTargetLuma > 1.0, "ALFStrengthTargetLuma is greater than 1. Valid range is 0.0 <= ALFStrengthTargetLuma <= 1.0");
        xConfirmPara(m_alfStrengthTargetChroma < 0.0, "ALFStrengthTargetChroma is less than 0. Valid range is 0.0 <= ALFStrengthTargetChroma <= 1.0");
        xConfirmPara(m_alfStrengthTargetChroma > 1.0, "ALFStrengthTargetChroma is greater than 1. Valid range is 0.0 <= ALFStrengthTargetChroma <= 1.0");
      }
      if (m_ccalf)
      {
        xConfirmPara(m_ccalfStrengthTarget < 0.0, "CCALFStrengthTarget is less than 0. Valid range is 0.0 <= CCALFStrengthTarget <= 1.0");
        xConfirmPara(m_ccalfStrengthTarget > 1.0, "CCALFStrengthTarget is greater than 1. Valid range is 0.0 <= CCALFStrengthTarget <= 1.0");
      }
    
      if (m_ccalf && (m_chromaFormatIDC == CHROMA_400))
      {
        msg( WARNING, "****************************************************************************\n");
        msg( WARNING, "** WARNING: --CCALF has been disabled because the chromaFormat is 400     **\n");
        msg( WARNING, "****************************************************************************\n");
        m_ccalf = false;
      }
    
      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_uiMaxCUWidth > MAX_CU_SIZE,                                               "MaxCUWith exceeds predefined MAX_CU_SIZE limit");
    
    
      const int minCuSize = 1 << m_log2MinCuSize;
    
      xConfirmPara( m_uiMinQT[0] > 64,                                                          "Min Luma QT size in I slices should be smaller than or equal to 64");
      xConfirmPara( m_uiMinQT[1] > 64,                                                          "Min Luma QT size in non-I slices should be smaller than or equal to 64");
      xConfirmPara( m_uiMaxBT[2] > 64,                                                          "Maximum BT size for chroma block in I slice should be smaller than or equal to 64");
      xConfirmPara( m_uiMaxTT[0] > 64,                                                          "Maximum TT size for luma block in I slice should be smaller than or equal to 64");
      xConfirmPara( m_uiMaxTT[1] > 64,                                                          "Maximum TT size for luma block in non-I slice should be smaller than or equal to 64");
      xConfirmPara( m_uiMaxTT[2] > 64,                                                          "Maximum TT size for chroma block in I slice should be smaller than or equal to 64");
    
      xConfirmPara( m_uiMinQT[0] < minCuSize,                                                   "Min Luma QT size in I slices should be larger than or equal to minCuSize");
      xConfirmPara( m_uiMinQT[1] < minCuSize,                                                   "Min Luma QT size in non-I slices should be larger than or equal to minCuSize");
    
      xConfirmPara((m_sourceWidth % minCuSize ) || (m_sourceHeight % minCuSize),              "Picture width or height is not a multiple of minCuSize");
    
      const int minDiff = (int)floorLog2(m_uiMinQT[2]) - std::max(MIN_CU_LOG2, (int)m_log2MinCuSize - (int)getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, m_chromaFormatIDC));
    
      xConfirmPara( minDiff < 0 ,                                                               "Min Chroma QT size in I slices is smaller than Min Luma CU size even considering color format");
      xConfirmPara( (m_uiMinQT[2] << (int)getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, m_chromaFormatIDC)) > std::min(64, (int)m_uiCTUSize),
                                                                                                "Min Chroma QT size in I slices should be smaller than or equal to CTB size or CB size after implicit split of CTB");
    
      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_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_uiMaxBT[0] < m_uiMinQT[0],                                                "Maximum BT size for luma block in I slice should be larger than minimum QT size");
      xConfirmPara( m_uiMaxBT[0] > m_uiCTUSize,                                                 "Maximum BT size for luma block in I slice should be smaller than or equal to CTUSize");
      xConfirmPara( m_uiMaxBT[1] < m_uiMinQT[1],                                                "Maximum BT size for luma block in non I slice should be larger than minimum QT size");
      xConfirmPara( m_uiMaxBT[1] > m_uiCTUSize,                                                 "Maximum BT size for luma block in non I slice should be smaller than or equal to CTUSize");
    
      xConfirmPara( m_uiMaxBT[2] < (m_uiMinQT[2] << (int)getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, m_chromaFormatIDC)),
    
                                                                                                "Maximum BT size for chroma block in I slice should be larger than minimum QT size");
    
      xConfirmPara( m_uiMaxBT[2] > m_uiCTUSize,                                                 "Maximum BT size for chroma block in I slice should be smaller than or equal to CTUSize");
      xConfirmPara( m_uiMaxTT[0] < m_uiMinQT[0],                                                "Maximum TT size for luma block in I slice should be larger than minimum QT size");
      xConfirmPara( m_uiMaxTT[0] > m_uiCTUSize,                                                 "Maximum TT size for luma block in I slice should be smaller than or equal to CTUSize");
      xConfirmPara( m_uiMaxTT[1] < m_uiMinQT[1],                                                "Maximum TT size for luma block in non I slice should be larger than minimum QT size");
      xConfirmPara( m_uiMaxTT[1] > m_uiCTUSize,                                                 "Maximum TT size for luma block in non I slice should be smaller than or equal to CTUSize");
    
      xConfirmPara( m_uiMaxTT[2] < (m_uiMinQT[2] << (int)getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, m_chromaFormatIDC)),
    
                                                                                                "Maximum TT size for chroma block in I slice should be larger than minimum QT size");
    
      xConfirmPara( m_uiMaxTT[2] > m_uiCTUSize,                                                 "Maximum TT size for chroma block in I slice should be smaller than or equal to CTUSize");
    
      xConfirmPara( (m_sourceWidth  % (std::max(8u, m_log2MinCuSize))) != 0,                   "Resulting coded frame width must be a multiple of Max(8, the minimum CU size)");
      xConfirmPara( (m_sourceHeight % (std::max(8u, m_log2MinCuSize))) != 0,                   "Resulting coded frame height must be a multiple of Max(8, the minimum CU size)");
    
      if (m_uiMaxMTTHierarchyDepthI == 0)
      {
        xConfirmPara(m_uiMaxBT[0] != m_uiMinQT[0], "MaxBTLumaISlice shall be equal to MinQTLumaISlice when MaxMTTHierarchyDepthISliceL is 0.");
        xConfirmPara(m_uiMaxTT[0] != m_uiMinQT[0], "MaxTTLumaISlice shall be equal to MinQTLumaISlice when MaxMTTHierarchyDepthISliceL is 0.");
      }
      if (m_uiMaxMTTHierarchyDepthIChroma == 0)
      {
    
        xConfirmPara(m_uiMaxBT[2] != (m_uiMinQT[2] << (int)getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, m_chromaFormatIDC)), "MaxBTChromaISlice shall be equal to MinQTChromaISlice when MaxMTTHierarchyDepthISliceC is 0.");
        xConfirmPara(m_uiMaxTT[2] != (m_uiMinQT[2] << (int)getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, m_chromaFormatIDC)), "MaxTTChromaISlice shall be equal to MinQTChromaISlice when MaxMTTHierarchyDepthISliceC is 0.");
    
      if (m_uiMaxMTTHierarchyDepth == 0)
    
      {
        xConfirmPara(m_uiMaxBT[1] != m_uiMinQT[1], "MaxBTNonISlice shall be equal to MinQTNonISlice when MaxMTTHierarchyDepth is 0.");
        xConfirmPara(m_uiMaxTT[1] != m_uiMinQT[1], "MaxTTNonISlice shall be equal to MinQTNonISlice when MaxMTTHierarchyDepth is 0.");
      }
    
      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_maxNumGeoCand > GEO_MAX_NUM_UNI_CANDS, "MaxNumGeoCand must be no more than GEO_MAX_NUM_UNI_CANDS." );
      xConfirmPara( m_maxNumGeoCand > m_maxNumMergeCand, "MaxNumGeoCand must be no more than MaxNumMergeCand." );
      xConfirmPara( 0 < m_maxNumGeoCand && m_maxNumGeoCand < 2, "MaxNumGeoCand must be no less than 2 unless MaxNumGeoCand 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 < (m_sbTmvpEnableFlag ? 1 : 0),
                   "MaxNumAffineMergeCand must be greater than 0 when SbTMVP is enabled");
    
      xConfirmPara( m_maxNumAffineMergeCand > AFFINE_MRG_MAX_NUM_CANDS, "MaxNumAffineMergeCand must be no more than AFFINE_MRG_MAX_NUM_CANDS." );
    
        m_maxNumAffineMergeCand = m_sbTmvpEnableFlag ? 1 : 0;
    
        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 (!m_alf)
      {
        xConfirmPara( m_ccalf, "CCALF cannot be enabled when ALF is disabled" );
      }
    
      xConfirmPara( m_sourceWidth  % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Picture width must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_sourceHeight % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Picture height must be an integer multiple of the specified chroma subsampling");
    
      xConfirmPara( m_sourcePadding[0] % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Horizontal padding must be an integer multiple of the specified chroma subsampling");
      xConfirmPara( m_sourcePadding[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_CbBetaOffsetDiv2 = 0;
        m_GOPList[0].m_CbTcOffsetDiv2 = 0;
        m_GOPList[0].m_CrBetaOffsetDiv2 = 0;
        m_GOPList[0].m_CrTcOffsetDiv2 = 0;
    
    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;
    
        xConfirmPara( m_intraOnlyConstraintFlag, "IntraOnlyConstraintFlag 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_deblockingFilterOffsetInPPS && (!m_deblockingFilterDisable) )
    
          xConfirmPara( (m_GOPList[i].m_betaOffsetDiv2 + m_deblockingFilterBetaOffsetDiv2) < -12 || (m_GOPList[i].m_betaOffsetDiv2 + m_deblockingFilterBetaOffsetDiv2) > 12, "Loop Filter Beta Offset div. 2 for one of the GOP entries exceeds supported range (-12 to 12)" );
          xConfirmPara( (m_GOPList[i].m_tcOffsetDiv2 + m_deblockingFilterTcOffsetDiv2) < -12 || (m_GOPList[i].m_tcOffsetDiv2 + m_deblockingFilterTcOffsetDiv2) > 12, "Loop Filter Tc Offset div. 2 for one of the GOP entries exceeds supported range (-12 to 12)" );
          xConfirmPara( (m_GOPList[i].m_CbBetaOffsetDiv2 + m_deblockingFilterCbBetaOffsetDiv2) < -12 || (m_GOPList[i].m_CbBetaOffsetDiv2 + m_deblockingFilterCbBetaOffsetDiv2) > 12, "Loop Filter Beta Offset div. 2 for one of the GOP entries exceeds supported range (-12 to 12)" );
          xConfirmPara( (m_GOPList[i].m_CbTcOffsetDiv2 + m_deblockingFilterCbTcOffsetDiv2) < -12 || (m_GOPList[i].m_CbTcOffsetDiv2 + m_deblockingFilterCbTcOffsetDiv2) > 12, "Loop Filter Tc Offset div. 2 for one of the GOP entries exceeds supported range (-12 to 12)" );
          xConfirmPara( (m_GOPList[i].m_CrBetaOffsetDiv2 + m_deblockingFilterCrBetaOffsetDiv2) < -12 || (m_GOPList[i].m_CrBetaOffsetDiv2 + m_deblockingFilterCrBetaOffsetDiv2) > 12, "Loop Filter Beta Offset div. 2 for one of the GOP entries exceeds supported range (-12 to 12)" );
          xConfirmPara( (m_GOPList[i].m_CrTcOffsetDiv2 + m_deblockingFilterCrTcOffsetDiv2) < -12 || (m_GOPList[i].m_CrTcOffsetDiv2 + m_deblockingFilterCrTcOffsetDiv2) > 12, "Loop Filter Tc Offset div. 2 for one of the GOP entries exceeds supported range (-12 to 12)" );
    
        }
      }
    
    #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_maxSublayers < 1 || m_maxSublayers > 7, "MaxSublayers must be in range [1..7]" );
    
    
    
      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_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_maxNumReorderPics[m_GOPList[i].m_temporalId])
    
          m_maxNumReorderPics[m_GOPList[i].m_temporalId] = numReorder;
    
        // a lower layer can not have higher value of m_maxNumReorderPics than a higher layer
        if(m_maxNumReorderPics[i+1] < m_maxNumReorderPics[i])
    
          m_maxNumReorderPics[i+1] = m_maxNumReorderPics[i];
    
        // the value of dpb_max_num_reorder_pics[ i ] shall be in the range of 0 to max_dec_pic_buffering[ i ] - 1, inclusive
        if(m_maxNumReorderPics[i] > m_maxDecPicBuffering[i] - 1)
    
          m_maxDecPicBuffering[i] = m_maxNumReorderPics[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 dpb_max_num_reorder_pics[ i ] shall be in the range of 0 to max_dec_pic_buffering[ i ] -  1, inclusive
      if(m_maxNumReorderPics[MAX_TLAYER-1] > m_maxDecPicBuffering[MAX_TLAYER-1] - 1)
    
        m_maxDecPicBuffering[MAX_TLAYER-1] = m_maxNumReorderPics[MAX_TLAYER-1] + 1;
    
      if( m_picPartitionFlag )
    
      {
        PPS pps;
        uint32_t colIdx, rowIdx;
        uint32_t remSize;
    
        pps.setPicWidthInLumaSamples( m_sourceWidth );
        pps.setPicHeightInLumaSamples( m_sourceHeight );
    
        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 )
        {
    
            // 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(nullptr);
    
            // 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");
        }
      }
    
      {
        m_numTileCols = 1;
        m_numTileRows = 1;
        m_numSlicesInPic = 1;
      }
    
      if ((m_MCTSEncConstraint) && (!m_disableLFCrossTileBoundaryFlag))
    
    Valeri George's avatar
    Valeri George committed
      {
        printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling filtering across tile boundaries!\n");
    
        m_disableLFCrossTileBoundaryFlag = true;
    
    Valeri George's avatar
    Valeri George committed
      }
      if ((m_MCTSEncConstraint) && (m_TMVPModeId))
      {
        printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling TMVP!\n");
        m_TMVPModeId = 0;
      }
    
      if ((m_MCTSEncConstraint) && ( m_alf ))
      {
        printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling ALF!\n");
        m_alf = false;
      }
      if( ( m_MCTSEncConstraint ) && ( m_BIO ) )
      {
        printf( "Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling BIO!\n" );
        m_BIO = false;
      }
    
      xConfirmPara( m_sariAspectRatioIdc < 0 || m_sariAspectRatioIdc > 255, "SEISARISampleAspectRatioIdc must be in the range of 0 to 255");
    
      if ( m_RCEnableRateControl )
      {
        if ( m_RCForceIntraQP )
        {
          if ( m_RCInitialQP == 0 )
          {
            msg( WARNING, "\nInitial QP for rate control is not specified. Reset not to use force intra QP!" );
            m_RCForceIntraQP = false;
          }
        }
        xConfirmPara( m_uiDeltaQpRD > 0, "Rate control cannot be used together with slice level multiple-QP optimization!\n" );
    #if U0132_TARGET_BITS_SATURATION