Skip to content
Snippets Groups Projects
EncAppCfg.cpp 247 KiB
Newer Older
  • Learn to ignore specific revisions
  •           CHECK( m_virtualBoundariesPosY[i] - m_virtualBoundariesPosY[i-1] < m_uiCTUSize, "The distance between any two horizontal virtual boundaries shall be greater than or equal to the CTU size" );
            }
    
        CHECK( m_maxNumAlfAlternativesChroma < 1 || m_maxNumAlfAlternativesChroma > MAX_NUM_ALF_ALTERNATIVES_CHROMA, std::string("The maximum number of ALF Chroma filter alternatives must be in the range (1-") + std::to_string(MAX_NUM_ALF_ALTERNATIVES_CHROMA) + std::string (", inclusive)") );
    
      // reading external dQP description from file
      if ( !m_dQPFileName.empty() )
      {
        FILE* fpt=fopen( m_dQPFileName.c_str(), "r" );
        if ( fpt )
        {
          int iValue;
          int iPOC = 0;
          while ( iPOC < m_framesToBeEncoded )
          {
            if ( fscanf(fpt, "%d", &iValue ) == EOF )
            {
              break;
            }
            m_aidQP[ iPOC ] = iValue;
            iPOC++;
          }
          fclose(fpt);
        }
      }
    
      if( m_masteringDisplay.colourVolumeSEIEnabled )
      {
        for(uint32_t idx=0; idx<6; idx++)
        {
          m_masteringDisplay.primaries[idx/2][idx%2] = uint16_t((cfg_DisplayPrimariesCode.values.size() > idx) ? cfg_DisplayPrimariesCode.values[idx] : 0);
        }
        for(uint32_t idx=0; idx<2; idx++)
        {
          m_masteringDisplay.whitePoint[idx] = uint16_t((cfg_DisplayWhitePointCode.values.size() > idx) ? cfg_DisplayWhitePointCode.values[idx] : 0);
        }
      }
    
      if ( m_omniViewportSEIEnabled && !m_omniViewportSEICancelFlag )
      {
        CHECK (!( m_omniViewportSEICntMinus1 >= 0 && m_omniViewportSEICntMinus1 < 16 ), "SEIOmniViewportCntMinus1 must be in the range of 0 to 16");
        m_omniViewportSEIAzimuthCentre.resize  (m_omniViewportSEICntMinus1+1);
        m_omniViewportSEIElevationCentre.resize(m_omniViewportSEICntMinus1+1);
        m_omniViewportSEITiltCentre.resize     (m_omniViewportSEICntMinus1+1);
        m_omniViewportSEIHorRange.resize       (m_omniViewportSEICntMinus1+1);
        m_omniViewportSEIVerRange.resize       (m_omniViewportSEICntMinus1+1);
        for(int i=0; i<(m_omniViewportSEICntMinus1+1); i++)
        {
          m_omniViewportSEIAzimuthCentre[i]   = cfg_omniViewportSEIAzimuthCentre  .values.size() > i ? cfg_omniViewportSEIAzimuthCentre  .values[i] : 0;
          m_omniViewportSEIElevationCentre[i] = cfg_omniViewportSEIElevationCentre.values.size() > i ? cfg_omniViewportSEIElevationCentre.values[i] : 0;
          m_omniViewportSEITiltCentre[i]      = cfg_omniViewportSEITiltCentre     .values.size() > i ? cfg_omniViewportSEITiltCentre     .values[i] : 0;
          m_omniViewportSEIHorRange[i]        = cfg_omniViewportSEIHorRange       .values.size() > i ? cfg_omniViewportSEIHorRange       .values[i] : 0;
          m_omniViewportSEIVerRange[i]        = cfg_omniViewportSEIVerRange       .values.size() > i ? cfg_omniViewportSEIVerRange       .values[i] : 0;
        }
      }
    
      if(!m_rwpSEIRwpCancelFlag && m_rwpSEIEnabled)
      {
        CHECK (!( m_rwpSEINumPackedRegions > 0 && m_rwpSEINumPackedRegions <= std::numeric_limits<uint8_t>::max() ), "SEIRwpNumPackedRegions must be in the range of 1 to 255");
        CHECK (!(cfg_rwpSEIRwpTransformType.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIRwpTransformType values be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIRwpGuardBandFlag.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIRwpGuardBandFlag values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIProjRegionWidth.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIProjRegionWidth values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIProjRegionHeight.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIProjRegionHeight values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIRwpSEIProjRegionTop.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIRwpSEIProjRegionTop values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIProjRegionLeft.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIProjRegionLeft values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIPackedRegionWidth.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIPackedRegionWidth values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIPackedRegionHeight.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIPackedRegionHeight values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIPackedRegionTop.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIPackedRegionTop values must be equal to SEIRwpNumPackedRegions");
        CHECK (!(cfg_rwpSEIPackedRegionLeft.values.size() == m_rwpSEINumPackedRegions), "Number of must SEIPackedRegionLeft values must be equal to SEIRwpNumPackedRegions");
    
        m_rwpSEIRwpTransformType.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpGuardBandFlag.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIProjRegionWidth.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIProjRegionHeight.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpSEIProjRegionTop.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIProjRegionLeft.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIPackedRegionWidth.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIPackedRegionHeight.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIPackedRegionTop.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIPackedRegionLeft.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpLeftGuardBandWidth.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpRightGuardBandWidth.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpTopGuardBandHeight.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpBottomGuardBandHeight.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpGuardBandNotUsedForPredFlag.resize(m_rwpSEINumPackedRegions);
        m_rwpSEIRwpGuardBandType.resize(4*m_rwpSEINumPackedRegions);
        for( int i=0; i < m_rwpSEINumPackedRegions; i++ )
        {
          m_rwpSEIRwpTransformType[i]                     = cfg_rwpSEIRwpTransformType.values[i];
          CHECK (!( m_rwpSEIRwpTransformType[i] >= 0 && m_rwpSEIRwpTransformType[i] <= 7 ), "SEIRwpTransformType must be in the range of 0 to 7");
          m_rwpSEIRwpGuardBandFlag[i]                     = cfg_rwpSEIRwpGuardBandFlag.values[i];
          m_rwpSEIProjRegionWidth[i]                      = cfg_rwpSEIProjRegionWidth.values[i];
          m_rwpSEIProjRegionHeight[i]                     = cfg_rwpSEIProjRegionHeight.values[i];
          m_rwpSEIRwpSEIProjRegionTop[i]                  = cfg_rwpSEIRwpSEIProjRegionTop.values[i];
          m_rwpSEIProjRegionLeft[i]                       = cfg_rwpSEIProjRegionLeft.values[i];
          m_rwpSEIPackedRegionWidth[i]                    = cfg_rwpSEIPackedRegionWidth.values[i];
          m_rwpSEIPackedRegionHeight[i]                   = cfg_rwpSEIPackedRegionHeight.values[i];
          m_rwpSEIPackedRegionTop[i]                      = cfg_rwpSEIPackedRegionTop.values[i];
          m_rwpSEIPackedRegionLeft[i]                     = cfg_rwpSEIPackedRegionLeft.values[i]; 
          if( m_rwpSEIRwpGuardBandFlag[i] )
          {
            m_rwpSEIRwpLeftGuardBandWidth[i]              =  cfg_rwpSEIRwpLeftGuardBandWidth.values[i];
            m_rwpSEIRwpRightGuardBandWidth[i]             =  cfg_rwpSEIRwpRightGuardBandWidth.values[i];
            m_rwpSEIRwpTopGuardBandHeight[i]              =  cfg_rwpSEIRwpTopGuardBandHeight.values[i];
            m_rwpSEIRwpBottomGuardBandHeight[i]           =  cfg_rwpSEIRwpBottomGuardBandHeight.values[i];
            CHECK (! ( m_rwpSEIRwpLeftGuardBandWidth[i] > 0 || m_rwpSEIRwpRightGuardBandWidth[i] > 0 || m_rwpSEIRwpTopGuardBandHeight[i] >0 || m_rwpSEIRwpBottomGuardBandHeight[i] >0 ), "At least one of the RWP guard band parameters mut be greater than zero");
            m_rwpSEIRwpGuardBandNotUsedForPredFlag[i]     =  cfg_rwpSEIRwpGuardBandNotUsedForPredFlag.values[i];
            for( int j=0; j < 4; j++ )
            {
              m_rwpSEIRwpGuardBandType[i*4 + j]           =  cfg_rwpSEIRwpGuardBandType.values[i*4 + j];
            }
    
          }
        }
      }
    
      if (m_gcmpSEIEnabled && !m_gcmpSEICancelFlag)
      {
        int numFace = m_gcmpSEIPackingType == 4 || m_gcmpSEIPackingType == 5 ? 5 : 6;
        CHECK (!(cfg_gcmpSEIFaceIndex.values.size()                  == numFace), "Number of SEIGcmpFaceIndex must be equal to 5 when SEIGcmpPackingType is equal to 4 or 5, otherwise, it must be equal to 6");
        CHECK (!(cfg_gcmpSEIFaceRotation.values.size()               == numFace), "Number of SEIGcmpFaceRotation must be equal to 5 when SEIGcmpPackingType is equal to 4 or 5, otherwise, it must be equal to 6");
        m_gcmpSEIFaceIndex.resize(numFace);
        m_gcmpSEIFaceRotation.resize(numFace);
        if (m_gcmpSEIMappingFunctionType == 2)
        {
          CHECK (!(cfg_gcmpSEIFunctionCoeffU.values.size()           == numFace), "Number of SEIGcmpFunctionCoeffU must be equal to 5 when SEIGcmpPackingType is equal to 4 or 5, otherwise, it must be equal to 6");
          CHECK (!(cfg_gcmpSEIFunctionUAffectedByVFlag.values.size() == numFace), "Number of SEIGcmpFunctionUAffectedByVFlag must be equal to 5 when SEIGcmpPackingType is equal to 4 or 5, otherwise, it must be equal to 6");
          CHECK (!(cfg_gcmpSEIFunctionCoeffV.values.size()           == numFace), "Number of SEIGcmpFunctionCoeffV must be equal to 5 when SEIGcmpPackingType is equal to 4 or 5, otherwise, it must be equal to 6");
          CHECK (!(cfg_gcmpSEIFunctionVAffectedByUFlag.values.size() == numFace), "Number of SEIGcmpFunctionVAffectedByUFlag must be equal to 5 when SEIGcmpPackingType is equal to 4 or 5, otherwise, it must be equal to 6");
          m_gcmpSEIFunctionCoeffU.resize(numFace);
          m_gcmpSEIFunctionUAffectedByVFlag.resize(numFace);
          m_gcmpSEIFunctionCoeffV.resize(numFace);
          m_gcmpSEIFunctionVAffectedByUFlag.resize(numFace);
        }
        for (int i = 0; i < numFace; i++)
        {
          m_gcmpSEIFaceIndex[i]                = cfg_gcmpSEIFaceIndex.values[i];
          m_gcmpSEIFaceRotation[i]             = cfg_gcmpSEIFaceRotation.values[i];
          if (m_gcmpSEIMappingFunctionType == 2)
          {
            m_gcmpSEIFunctionCoeffU[i]           = cfg_gcmpSEIFunctionCoeffU.values[i];
            m_gcmpSEIFunctionUAffectedByVFlag[i] = cfg_gcmpSEIFunctionUAffectedByVFlag.values[i];
            m_gcmpSEIFunctionCoeffV[i]           = cfg_gcmpSEIFunctionCoeffV.values[i];
            m_gcmpSEIFunctionVAffectedByUFlag[i] = cfg_gcmpSEIFunctionVAffectedByUFlag.values[i];
          }
        }
      }
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_reshapeCW.binCW.resize(3);
      m_reshapeCW.rspFps = m_iFrameRate;
      m_reshapeCW.rspPicSize = m_iSourceWidth*m_iSourceHeight;
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_reshapeCW.rspFpsToIp = std::max(16, 16 * (int)(round((double)m_iFrameRate /16.0)));
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_reshapeCW.rspBaseQP = m_iQP;
    
      m_reshapeCW.updateCtrl = m_updateCtrl;
      m_reshapeCW.adpOption = m_adpOption;
      m_reshapeCW.initialCW = m_initialCW;
    
    #if ENABLE_TRACING
      g_trace_ctx = tracing_init(sTracingFile, sTracingRule);
      if( bTracingChannelsList && g_trace_ctx )
      {
        std::string sChannelsList;
        g_trace_ctx->getChannelsList( sChannelsList );
        msg( INFO, "\n Using tracing channels:\n\n%s\n", sChannelsList.c_str() );
      }
    #endif
    
    #if ENABLE_QPA
    
      if (m_bUsePerceptQPA && !m_bUseAdaptiveQP && m_dualTree && (m_cbQpOffsetDualTree != 0 || m_crQpOffsetDualTree != 0 || m_cbCrQpOffsetDualTree != 0))
    
      {
        msg( WARNING, "*************************************************************************\n" );
        msg( WARNING, "* WARNING: chroma QPA on, ignoring nonzero dual-tree chroma QP offsets! *\n" );
        msg( WARNING, "*************************************************************************\n" );
      }
    
    
    #if ENABLE_QPA_SUB_CTU
     #if QP_SWITCHING_FOR_PARALLEL
    
      if ((m_iQP < 38) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && (m_iSourceWidth <= 2048) && (m_iSourceHeight <= 1280)
    
      if (((int)m_fQP < 38) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && (m_iSourceWidth <= 2048) && (m_iSourceHeight <= 1280)
    
     #if WCG_EXT && ER_CHROMA_QP_WCG_PPS
          && (!m_wcgChromaQpControl.enabled)
     #endif
    
          && ((1 << (m_log2MaxTbSize + 1)) == m_uiCTUSize) && (m_iSourceWidth > 512 || m_iSourceHeight > 320))
    
        m_cuQpDeltaSubdiv = 2;
    
      if( ( m_iQP < 38 ) && ( m_iGOPSize > 4 ) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && ( m_iSourceHeight <= 1280 ) && ( m_iSourceWidth <= 2048 ) )
    
      if( ( ( int ) m_fQP < 38 ) && ( m_iGOPSize > 4 ) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && ( m_iSourceHeight <= 1280 ) && ( m_iSourceWidth <= 2048 ) )
    
        msg( WARNING, "*************************************************************************\n" );
        msg( WARNING, "* WARNING: QPA on with large CTU for <=HD sequences, limiting CTU size! *\n" );
        msg( WARNING, "*************************************************************************\n" );
    
        if( ( 1u << m_log2MaxTbSize         ) > m_uiCTUSize ) m_log2MaxTbSize--;
    
      if( m_costMode == COST_LOSSLESS_CODING )
      {
        m_iQP = LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP - ( ( m_internalBitDepth[CHANNEL_TYPE_LUMA] - 8 ) * 6 );
      }
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      m_uiMaxCUWidth = m_uiMaxCUHeight = m_uiCTUSize;
    
    
      // check validity of input parameters
      if( xCheckParameter() )
      {
        // return check failed
        return false;
      }
    
      // print-out parameters
      xPrintParameter();
    
      return true;
    }
    
    
    // ====================================================================================================================
    // Private member functions
    // ====================================================================================================================
    
    
    ///< auto determine the profile to use given the other configuration settings. Returns 1 if erred. Can select profile 'NONE'
    
    int EncAppCfg::xAutoDetermineProfile()
    {
      const int maxBitDepth= std::max(m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[m_chromaFormatIDC==ChromaFormat::CHROMA_400 ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA]);
      m_profile=Profile::NONE;
    
      if (m_chromaFormatIDC==ChromaFormat::CHROMA_400 || m_chromaFormatIDC==ChromaFormat::CHROMA_420)
      {
        if (maxBitDepth<=10)
        {
          m_profile=Profile::MAIN_10;
        }
      }
      else if (m_chromaFormatIDC==ChromaFormat::CHROMA_422 || m_chromaFormatIDC==ChromaFormat::CHROMA_444)
      {
        if (maxBitDepth<=10)
        {
          m_profile=Profile::MAIN_444_10;
        }
      }
      else
      {
        return 1; // unknown chroma format
      }
      return 0;
    }
    
    
    bool EncAppCfg::xCheckParameter()
    {
      msg( NOTICE, "\n" );
      if (m_decodedPictureHashSEIType==HASHTYPE_NONE)
      {
        msg( DETAILS, "******************************************************************\n");
        msg( DETAILS, "** WARNING: --SEIDecodedPictureHash is now disabled by default. **\n");
        msg( DETAILS, "**          Automatic verification of decoded pictures by a     **\n");
        msg( DETAILS, "**          decoder requires this option to be enabled.         **\n");
        msg( DETAILS, "******************************************************************\n");
      }
      if( m_profile==Profile::NONE )
      {
        msg( DETAILS, "***************************************************************************\n");
        msg( DETAILS, "** WARNING: For conforming bitstreams a valid Profile value must be set! **\n");
        msg( DETAILS, "***************************************************************************\n");
      }
      if( m_level==Level::NONE )
      {
        msg( DETAILS, "***************************************************************************\n");
        msg( DETAILS, "** WARNING: For conforming bitstreams a valid Level value must be set!   **\n");
        msg( DETAILS, "***************************************************************************\n");
      }
    
      bool check_failed = false; /* abort if there is a fatal configuration problem */
    #define xConfirmPara(a,b) check_failed |= confirmPara(a,b)
    
    
    
      if( m_depQuantEnabledFlag )
      {
        xConfirmPara( !m_useRDOQ || !m_useRDOQTS, "RDOQ and RDOQTS must be equal to 1 if dependent quantization is enabled" );
        xConfirmPara( m_signDataHidingEnabledFlag, "SignHideFlag must be equal to 0 if dependent quantization is enabled" );
      }
    
        const int minCUSize = 1 << m_log2MinCuSize;
        xConfirmPara(m_wrapAroundOffset <= m_uiCTUSize + minCUSize, "Wrap-around offset must be greater than CtbSizeY + MinCbSize");
        xConfirmPara(m_wrapAroundOffset > m_iSourceWidth, "Wrap-around offset must not be greater than the source picture width");
    
        xConfirmPara( m_wrapAroundOffset % minCUSize != 0, "Wrap-around offset must be an integer multiple of the specified minimum CU size" );
    
      }
    
    #if ENABLE_SPLIT_PARALLELISM
      xConfirmPara( m_numSplitThreads < 1, "Number of used threads cannot be smaller than 1" );
      xConfirmPara( m_numSplitThreads > PARL_SPLIT_MAX_NUM_THREADS, "Number of used threads cannot be higher than the number of actual jobs" );
    #else
      xConfirmPara( m_numSplitThreads != 1, "ENABLE_SPLIT_PARALLELISM is disabled, numSplitThreads has to be 1" );
    #endif
    
      xConfirmPara( m_numWppThreads != 1, "ENABLE_WPP_PARALLELISM is disabled, numWppThreads has to be 1" );
      xConfirmPara( m_ensureWppBitEqual, "ENABLE_WPP_PARALLELISM is disabled, cannot ensure being WPP bit-equal" );
    
    
    #if SHARP_LUMA_DELTA_QP && ENABLE_QPA
      xConfirmPara( m_bUsePerceptQPA && m_lumaLevelToDeltaQPMapping.mode >= 2, "QPA and SharpDeltaQP mode 2 cannot be used together" );
      if( m_bUsePerceptQPA && m_lumaLevelToDeltaQPMapping.mode == LUMALVL_TO_DQP_AVG_METHOD )
      {
        msg( WARNING, "*********************************************************************************\n" );
        msg( WARNING, "** WARNING: Applying custom luma-based QPA with activity-based perceptual QPA! **\n" );
        msg( WARNING, "*********************************************************************************\n" );
    
        m_lumaLevelToDeltaQPMapping.mode = LUMALVL_TO_DQP_NUM_MODES; // special QPA mode
      }
    #endif
    
    
    
      xConfirmPara( m_useAMaxBT && !m_SplitConsOverrideEnabledFlag, "AMaxBt can only be used with PartitionConstriantsOverride enabled" );
    
      xConfirmPara(m_bitstreamFileName.empty(), "A bitstream file name must be specified (BitstreamFile)");
    
      xConfirmPara(m_internalBitDepth[CHANNEL_TYPE_CHROMA] != m_internalBitDepth[CHANNEL_TYPE_LUMA], "The internalBitDepth must be the same for luma and chroma");
    
      if (m_profile==Profile::MAIN_10 || m_profile==Profile::MAIN_444_10)
      {
        xConfirmPara(m_log2MaxTransformSkipBlockSize>=6, "Transform Skip Log2 Max Size must be less or equal to 5 for given profile.");
        xConfirmPara(m_transformSkipRotationEnabledFlag==true, "UseResidualRotation must not be enabled for given profile.");
        xConfirmPara(m_transformSkipContextEnabledFlag==true, "UseSingleSignificanceMapContext must not be enabled for given profile.");
        xConfirmPara(m_rdpcmEnabledFlag[RDPCM_SIGNAL_IMPLICIT]==true, "ImplicitResidualDPCM must not be enabled for given profile.");
        xConfirmPara(m_rdpcmEnabledFlag[RDPCM_SIGNAL_EXPLICIT]==true, "ExplicitResidualDPCM must not be enabled for given profile.");
        xConfirmPara(m_persistentRiceAdaptationEnabledFlag==true, "GolombRiceParameterAdaption must not be enabled for given profile.");
        xConfirmPara(m_extendedPrecisionProcessingFlag==true, "UseExtendedPrecision must not be enabled for given profile.");
        xConfirmPara(m_highPrecisionOffsetsEnabledFlag==true, "UseHighPrecisionPredictionWeighting must not be enabled for given profile.");
        xConfirmPara(m_enableIntraReferenceSmoothing==false, "EnableIntraReferenceSmoothing must be enabled for given profile.");
        xConfirmPara(m_cabacBypassAlignmentEnabledFlag, "AlignCABACBeforeBypass cannot be enabled for given profile.");
      }
    
    
      // 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_internalBitDepth[CHANNEL_TYPE_LUMA] < m_inputBitDepth[CHANNEL_TYPE_LUMA]) || (m_internalBitDepth[CHANNEL_TYPE_CHROMA] < m_inputBitDepth[CHANNEL_TYPE_CHROMA]) )
      {
          msg(WARNING, "*****************************************************************************\n");
          msg(WARNING, "** WARNING: InternalBitDepth is set to the lower value than InputBitDepth! **\n");
    
    Takeshi Tsukuba's avatar
    Takeshi Tsukuba committed
          msg(WARNING, "**          min_qp_prime_ts_minus4 will be clipped to 0 at the low end!    **\n");
    
          msg(WARNING, "*****************************************************************************\n");
      }
    
    
      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_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_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)");
    
    
      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 < -12 || m_loopFilterBetaOffsetDiv2 > 12,          "Loop Filter Beta Offset div. 2 exceeds supported range (-12 to 12" );
      xConfirmPara( m_loopFilterTcOffsetDiv2 < -12 || m_loopFilterTcOffsetDiv2 > 12,              "Loop Filter Tc Offset div. 2 exceeds supported range (-12 to 12)" );
      xConfirmPara( m_loopFilterCbBetaOffsetDiv2 < -12 || m_loopFilterCbBetaOffsetDiv2 > 12,      "Loop Filter Beta Offset div. 2 exceeds supported range (-12 to 12" );
      xConfirmPara( m_loopFilterCbTcOffsetDiv2 < -12 || m_loopFilterCbTcOffsetDiv2 > 12,          "Loop Filter Tc Offset div. 2 exceeds supported range (-12 to 12)" );
      xConfirmPara( m_loopFilterCrBetaOffsetDiv2 < -12 || m_loopFilterCrBetaOffsetDiv2 > 12,      "Loop Filter Beta Offset div. 2 exceeds supported range (-12 to 12" );
      xConfirmPara( m_loopFilterCrTcOffsetDiv2 < -12 || m_loopFilterCrTcOffsetDiv2 > 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" );
    #endif
    
      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; }
      }
    
    
      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;
      }
      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] < 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_iSourceWidth % minCuSize ) || (m_iSourceHeight % 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_iSourceWidth  % (std::max(8u, m_log2MinCuSize))) != 0,                   "Resulting coded frame width must be a multiple of Max(8, the minimum CU size)");
      xConfirmPara( (m_iSourceHeight % (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_uiMaxMTTHierarchyDepthI == 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 < 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 (!m_alf)
      {
        xConfirmPara( m_ccalf, "CCALF cannot be enabled when ALF is disabled" );
      }
    
    
    
      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_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;
    
      }
      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) < -12 || (m_GOPList[i].m_betaOffsetDiv2 + m_loopFilterBetaOffsetDiv2) > 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_loopFilterTcOffsetDiv2) < -12 || (m_GOPList[i].m_tcOffsetDiv2 + m_loopFilterTcOffsetDiv2) > 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_loopFilterCbBetaOffsetDiv2) < -12 || (m_GOPList[i].m_CbBetaOffsetDiv2 + m_loopFilterCbBetaOffsetDiv2) > 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_loopFilterCbTcOffsetDiv2) < -12 || (m_GOPList[i].m_CbTcOffsetDiv2 + m_loopFilterCbTcOffsetDiv2) > 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_loopFilterCrBetaOffsetDiv2) < -12 || (m_GOPList[i].m_CrBetaOffsetDiv2 + m_loopFilterCrBetaOffsetDiv2) > 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_loopFilterCrTcOffsetDiv2) < -12 || (m_GOPList[i].m_CrTcOffsetDiv2 + m_loopFilterCrTcOffsetDiv2) > 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_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;
          }