Skip to content
Snippets Groups Projects
EncLib.cpp 66.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
      sps.setSPSTemporalMVPEnabledFlag((getTMVPModeId() == 2 || getTMVPModeId() == 1));
    
    
    #if MAX_TB_SIZE_SIGNALLING
      sps.setLog2MaxTbSize   ( m_log2MaxTbSize );
    #endif
    
    
      for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++)
      {
        sps.setBitDepth      (ChannelType(channelType), m_bitDepth[channelType] );
        sps.setQpBDOffset  (ChannelType(channelType), (6 * (m_bitDepth[channelType] - 8)));
        sps.setPCMBitDepth (ChannelType(channelType), m_PCMBitDepth[channelType]         );
      }
    
    
      sps.setSAOEnabledFlag( m_bUseSAO );
    
    
      sps.setMaxTLayers( m_maxTempLayer );
      sps.setTemporalIdNestingFlag( ( m_maxTempLayer == 1 ) ? true : false );
    
    
      for (int i = 0; i < std::min(sps.getMaxTLayers(), (uint32_t) MAX_TLAYER); i++ )
    
      {
        sps.setMaxDecPicBuffering(m_maxDecPicBuffering[i], i);
        sps.setNumReorderPics(m_numReorderPics[i], i);
      }
    
      sps.setPCMFilterDisableFlag  ( m_bPCMFilterDisableFlag );
    #if HEVC_USE_SCALING_LISTS
      sps.setScalingListFlag ( (m_useScalingListId == SCALING_LIST_OFF) ? 0 : 1 );
    #endif
    #if HEVC_USE_INTRA_SMOOTHING_T32 || HEVC_USE_INTRA_SMOOTHING_T64
      sps.setUseStrongIntraSmoothing( m_useStrongIntraSmoothing );
    #endif
    
      sps.setALFEnabledFlag( m_alf );
    
      sps.setVuiParametersPresentFlag(getVuiParametersPresentFlag());
    
      if (sps.getVuiParametersPresentFlag())
      {
        VUI* pcVUI = sps.getVuiParameters();
        pcVUI->setAspectRatioInfoPresentFlag(getAspectRatioInfoPresentFlag());
        pcVUI->setAspectRatioIdc(getAspectRatioIdc());
        pcVUI->setSarWidth(getSarWidth());
        pcVUI->setSarHeight(getSarHeight());
        pcVUI->setOverscanInfoPresentFlag(getOverscanInfoPresentFlag());
        pcVUI->setOverscanAppropriateFlag(getOverscanAppropriateFlag());
        pcVUI->setVideoSignalTypePresentFlag(getVideoSignalTypePresentFlag());
        pcVUI->setVideoFormat(getVideoFormat());
        pcVUI->setVideoFullRangeFlag(getVideoFullRangeFlag());
        pcVUI->setColourDescriptionPresentFlag(getColourDescriptionPresentFlag());
        pcVUI->setColourPrimaries(getColourPrimaries());
        pcVUI->setTransferCharacteristics(getTransferCharacteristics());
        pcVUI->setMatrixCoefficients(getMatrixCoefficients());
        pcVUI->setChromaLocInfoPresentFlag(getChromaLocInfoPresentFlag());
        pcVUI->setChromaSampleLocTypeTopField(getChromaSampleLocTypeTopField());
        pcVUI->setChromaSampleLocTypeBottomField(getChromaSampleLocTypeBottomField());
        pcVUI->setNeutralChromaIndicationFlag(getNeutralChromaIndicationFlag());
        pcVUI->setDefaultDisplayWindow(getDefaultDisplayWindow());
        pcVUI->setFrameFieldInfoPresentFlag(getFrameFieldInfoPresentFlag());
        pcVUI->setFieldSeqFlag(false);
        pcVUI->setHrdParametersPresentFlag(false);
        pcVUI->getTimingInfo()->setPocProportionalToTimingFlag(getPocProportionalToTimingFlag());
        pcVUI->getTimingInfo()->setNumTicksPocDiffOneMinus1   (getNumTicksPocDiffOneMinus1()   );
        pcVUI->setBitstreamRestrictionFlag(getBitstreamRestrictionFlag());
        pcVUI->setTilesFixedStructureFlag(getTilesFixedStructureFlag());
        pcVUI->setMotionVectorsOverPicBoundariesFlag(getMotionVectorsOverPicBoundariesFlag());
        pcVUI->setMinSpatialSegmentationIdc(getMinSpatialSegmentationIdc());
        pcVUI->setMaxBytesPerPicDenom(getMaxBytesPerPicDenom());
        pcVUI->setMaxBitsPerMinCuDenom(getMaxBitsPerMinCuDenom());
        pcVUI->setLog2MaxMvLengthHorizontal(getLog2MaxMvLengthHorizontal());
        pcVUI->setLog2MaxMvLengthVertical(getLog2MaxMvLengthVertical());
      }
    
      sps.setNumLongTermRefPicSPS(NUM_LONG_TERM_REF_PIC_SPS);
      CHECK(!(NUM_LONG_TERM_REF_PIC_SPS <= MAX_NUM_LONG_TERM_REF_PICS), "Unspecified error");
      for (int k = 0; k < NUM_LONG_TERM_REF_PIC_SPS; k++)
      {
        sps.setLtRefPicPocLsbSps(k, 0);
        sps.setUsedByCurrPicLtSPSFlag(k, 0);
      }
    
    #if U0132_TARGET_BITS_SATURATION
      if( getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() || getCpbSaturationEnabled() )
    #else
      if( getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() )
    #endif
      {
        xInitHrdParameters(sps);
      }
      if( getBufferingPeriodSEIEnabled() || getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() )
      {
        sps.getVuiParameters()->setHrdParametersPresentFlag( true );
      }
    
      // Set up SPS range extension settings
      sps.getSpsRangeExtension().setTransformSkipRotationEnabledFlag(m_transformSkipRotationEnabledFlag);
      sps.getSpsRangeExtension().setTransformSkipContextEnabledFlag(m_transformSkipContextEnabledFlag);
      for (uint32_t signallingModeIndex = 0; signallingModeIndex < NUMBER_OF_RDPCM_SIGNALLING_MODES; signallingModeIndex++)
      {
        sps.getSpsRangeExtension().setRdpcmEnabledFlag(RDPCMSignallingMode(signallingModeIndex), m_rdpcmEnabledFlag[signallingModeIndex]);
      }
      sps.getSpsRangeExtension().setExtendedPrecisionProcessingFlag(m_extendedPrecisionProcessingFlag);
      sps.getSpsRangeExtension().setIntraSmoothingDisabledFlag( m_intraSmoothingDisabledFlag );
      sps.getSpsRangeExtension().setHighPrecisionOffsetsEnabledFlag(m_highPrecisionOffsetsEnabledFlag);
      sps.getSpsRangeExtension().setPersistentRiceAdaptationEnabledFlag(m_persistentRiceAdaptationEnabledFlag);
      sps.getSpsRangeExtension().setCabacBypassAlignmentEnabledFlag(m_cabacBypassAlignmentEnabledFlag);
    }
    
    #if U0132_TARGET_BITS_SATURATION
    // calculate scale value of bitrate and initial delay
    int calcScale(int x)
    {
      if (x==0)
      {
        return 0;
      }
      uint32_t iMask = 0xffffffff;
      int ScaleValue = 32;
    
      while ((x&iMask) != 0)
      {
        ScaleValue--;
        iMask = (iMask >> 1);
      }
    
      return ScaleValue;
    }
    #endif
    void EncLib::xInitHrdParameters(SPS &sps)
    {
      bool useSubCpbParams = (getSliceMode() > 0) || (getSliceSegmentMode() > 0);
      int  bitRate         = getTargetBitrate();
      bool isRandomAccess  = getIntraPeriod() > 0;
    # if U0132_TARGET_BITS_SATURATION
      int cpbSize          = getCpbSize();
      CHECK(!(cpbSize!=0), "Unspecified error");  // CPB size may not be equal to zero. ToDo: have a better default and check for level constraints
      if( !getVuiParametersPresentFlag() && !getCpbSaturationEnabled() )
    #else
      if( !getVuiParametersPresentFlag() )
    #endif
      {
        return;
      }
    
      VUI *vui = sps.getVuiParameters();
      HRD *hrd = vui->getHrdParameters();
    
      TimingInfo *timingInfo = vui->getTimingInfo();
      timingInfo->setTimingInfoPresentFlag( true );
      switch( getFrameRate() )
      {
      case 24:
        timingInfo->setNumUnitsInTick( 1125000 );    timingInfo->setTimeScale    ( 27000000 );
        break;
      case 25:
        timingInfo->setNumUnitsInTick( 1080000 );    timingInfo->setTimeScale    ( 27000000 );
        break;
      case 30:
        timingInfo->setNumUnitsInTick( 900900 );     timingInfo->setTimeScale    ( 27000000 );
        break;
      case 50:
        timingInfo->setNumUnitsInTick( 540000 );     timingInfo->setTimeScale    ( 27000000 );
        break;
      case 60:
        timingInfo->setNumUnitsInTick( 450450 );     timingInfo->setTimeScale    ( 27000000 );
        break;
      default:
        timingInfo->setNumUnitsInTick( 1001 );       timingInfo->setTimeScale    ( 60000 );
        break;
      }
    
      if (getTemporalSubsampleRatio()>1)
      {
        uint32_t temporalSubsampleRatio = getTemporalSubsampleRatio();
        if ( double(timingInfo->getNumUnitsInTick()) * temporalSubsampleRatio > std::numeric_limits<uint32_t>::max() )
        {
          timingInfo->setTimeScale( timingInfo->getTimeScale() / temporalSubsampleRatio );
        }
        else
        {
          timingInfo->setNumUnitsInTick( timingInfo->getNumUnitsInTick() * temporalSubsampleRatio );
        }
      }
    
      bool rateCnt = ( bitRate > 0 );
      hrd->setNalHrdParametersPresentFlag( rateCnt );
      hrd->setVclHrdParametersPresentFlag( rateCnt );
      hrd->setSubPicCpbParamsPresentFlag( useSubCpbParams );
    
      if( hrd->getSubPicCpbParamsPresentFlag() )
      {
        hrd->setTickDivisorMinus2( 100 - 2 );                          //
        hrd->setDuCpbRemovalDelayLengthMinus1( 7 );                    // 8-bit precision ( plus 1 for last DU in AU )
        hrd->setSubPicCpbParamsInPicTimingSEIFlag( true );
        hrd->setDpbOutputDelayDuLengthMinus1( 5 + 7 );                 // With sub-clock tick factor of 100, at least 7 bits to have the same value as AU dpb delay
      }
      else
      {
        hrd->setSubPicCpbParamsInPicTimingSEIFlag( false );
      }
    
    #if U0132_TARGET_BITS_SATURATION
      if (calcScale(bitRate) <= 6)
      {
        hrd->setBitRateScale(0);
      }
      else
      {
        hrd->setBitRateScale(calcScale(bitRate) - 6);
      }
    
      if (calcScale(cpbSize) <= 4)
      {
        hrd->setCpbSizeScale(0);
      }
      else
      {
        hrd->setCpbSizeScale(calcScale(cpbSize) - 4);
      }
    #else
      hrd->setBitRateScale( 4 );                                       // in units of 2^( 6 + 4 ) = 1,024 bps
      hrd->setCpbSizeScale( 6 );                                       // in units of 2^( 4 + 6 ) = 1,024 bit
    #endif
    
      hrd->setDuCpbSizeScale( 6 );                                     // in units of 2^( 4 + 6 ) = 1,024 bit
    
      hrd->setInitialCpbRemovalDelayLengthMinus1(15);                  // assuming 0.5 sec, log2( 90,000 * 0.5 ) = 16-bit
      if( isRandomAccess )
      {
        hrd->setCpbRemovalDelayLengthMinus1(5);                        // 32 = 2^5 (plus 1)
        hrd->setDpbOutputDelayLengthMinus1 (5);                        // 32 + 3 = 2^6
      }
      else
      {
        hrd->setCpbRemovalDelayLengthMinus1(9);                        // max. 2^10
        hrd->setDpbOutputDelayLengthMinus1 (9);                        // max. 2^10
      }
    
      // Note: parameters for all temporal layers are initialized with the same values
      int i, j;
      uint32_t bitrateValue, cpbSizeValue;
      uint32_t duCpbSizeValue;
      uint32_t duBitRateValue = 0;
    
      for( i = 0; i < MAX_TLAYER; i ++ )
      {
        hrd->setFixedPicRateFlag( i, 1 );
        hrd->setPicDurationInTcMinus1( i, 0 );
        hrd->setLowDelayHrdFlag( i, 0 );
        hrd->setCpbCntMinus1( i, 0 );
    
        //! \todo check for possible PTL violations
        // BitRate[ i ] = ( bit_rate_value_minus1[ i ] + 1 ) * 2^( 6 + bit_rate_scale )
        bitrateValue = bitRate / (1 << (6 + hrd->getBitRateScale()) );      // bitRate is in bits, so it needs to be scaled down
        // CpbSize[ i ] = ( cpb_size_value_minus1[ i ] + 1 ) * 2^( 4 + cpb_size_scale )
    #if U0132_TARGET_BITS_SATURATION
        cpbSizeValue = cpbSize / (1 << (4 + hrd->getCpbSizeScale()) );      // using bitRate results in 1 second CPB size
    #else
        cpbSizeValue = bitRate / (1 << (4 + hrd->getCpbSizeScale()) );      // using bitRate results in 1 second CPB size
    #endif
    
    
        // DU CPB size could be smaller (i.e. bitrateValue / number of DUs), but we don't know
        // in how many DUs the slice segment settings will result
        duCpbSizeValue = bitrateValue;
        duBitRateValue = cpbSizeValue;
    
        for( j = 0; j < ( hrd->getCpbCntMinus1( i ) + 1 ); j ++ )
        {
          hrd->setBitRateValueMinus1( i, j, 0, ( bitrateValue - 1 ) );
          hrd->setCpbSizeValueMinus1( i, j, 0, ( cpbSizeValue - 1 ) );
          hrd->setDuCpbSizeValueMinus1( i, j, 0, ( duCpbSizeValue - 1 ) );
          hrd->setDuBitRateValueMinus1( i, j, 0, ( duBitRateValue - 1 ) );
          hrd->setCbrFlag( i, j, 0, false );
    
          hrd->setBitRateValueMinus1( i, j, 1, ( bitrateValue - 1) );
          hrd->setCpbSizeValueMinus1( i, j, 1, ( cpbSizeValue - 1 ) );
          hrd->setDuCpbSizeValueMinus1( i, j, 1, ( duCpbSizeValue - 1 ) );
          hrd->setDuBitRateValueMinus1( i, j, 1, ( duBitRateValue - 1 ) );
          hrd->setCbrFlag( i, j, 1, false );
        }
      }
    }
    
    void EncLib::xInitPPS(PPS &pps, const SPS &sps)
    {
      // pps ID already initialised.
      pps.setSPSId(sps.getSPSId());
    
      pps.setConstrainedIntraPred( m_bUseConstrainedIntraPred );
    
      bool bUseDQP = (getCuQpDeltaSubdiv() > 0)? true : false;
    
    
      if((getMaxDeltaQP() != 0 )|| getUseAdaptiveQP())
      {
        bUseDQP = true;
      }
    
    #if SHARP_LUMA_DELTA_QP
      if ( getLumaLevelToDeltaQPMapping().isEnabled() )
      {
        bUseDQP = true;
      }
    #endif
    #if ENABLE_QPA
      if (getUsePerceptQPA() && !bUseDQP)
      {
    
        CHECK( m_cuQpDeltaSubdiv != 0, "max. delta-QP subdiv must be zero!" );
    
        bUseDQP = (getBaseQP() < 38) && (getSourceWidth() > 512 || getSourceHeight() > 320);
    
      }
    #endif
    
      if (m_costMode==COST_SEQUENCE_LEVEL_LOSSLESS || m_costMode==COST_LOSSLESS_CODING)
      {
        bUseDQP=false;
      }
    
    
      if ( m_RCEnableRateControl )
      {
        pps.setUseDQP(true);
    
        pps.setCuQpDeltaSubdiv( 0 );
    
        pps.setCuQpDeltaSubdiv( m_cuQpDeltaSubdiv );
    
        pps.setCuQpDeltaSubdiv( 0 );
    
      if ( m_cuChromaQpOffsetSubdiv >= 0 )
      {
        pps.getPpsRangeExtension().setCuChromaQpOffsetSubdiv(m_cuChromaQpOffsetSubdiv);
    
        pps.getPpsRangeExtension().clearChromaQpOffsetList();
        pps.getPpsRangeExtension().setChromaQpOffsetListEntry(1, 6, 6);
        /* todo, insert table entries from command line (NB, 0 should not be touched) */
      }
      else
      {
    
        pps.getPpsRangeExtension().setCuChromaQpOffsetSubdiv(0);
    
        pps.getPpsRangeExtension().clearChromaQpOffsetList();
      }
      pps.getPpsRangeExtension().setCrossComponentPredictionEnabledFlag(m_crossComponentPredictionEnabledFlag);
      pps.getPpsRangeExtension().setLog2SaoOffsetScale(CHANNEL_TYPE_LUMA,   m_log2SaoOffsetScale[CHANNEL_TYPE_LUMA  ]);
      pps.getPpsRangeExtension().setLog2SaoOffsetScale(CHANNEL_TYPE_CHROMA, m_log2SaoOffsetScale[CHANNEL_TYPE_CHROMA]);
    
      {
        int baseQp = 26;
        if( 16 == getGOPSize() )
        {
          baseQp = getBaseQP()-24;
        }
        else
        {
          baseQp = getBaseQP()-26;
        }
    
        const int minDQP = -26 + sps.getQpBDOffset(CHANNEL_TYPE_LUMA);
    
        pps.setPicInitQPMinus26( std::min( maxDQP, std::max( minDQP, baseQp ) ));
      }
    
    #if ER_CHROMA_QP_WCG_PPS
      if (getWCGChromaQPControl().isEnabled())
      {
        const int baseQp=m_iQP+pps.getPPSId();
        const double chromaQp = m_wcgChromaQpControl.chromaQpScale * baseQp + m_wcgChromaQpControl.chromaQpOffset;
        const double dcbQP = m_wcgChromaQpControl.chromaCbQpScale * chromaQp;
        const double dcrQP = m_wcgChromaQpControl.chromaCrQpScale * chromaQp;
        const int cbQP =(int)(dcbQP + ( dcbQP < 0 ? -0.5 : 0.5) );
        const int crQP =(int)(dcrQP + ( dcrQP < 0 ? -0.5 : 0.5) );
        pps.setQpOffset(COMPONENT_Cb, Clip3( -12, 12, min(0, cbQP) + m_chromaCbQpOffset ));
        pps.setQpOffset(COMPONENT_Cr, Clip3( -12, 12, min(0, crQP) + m_chromaCrQpOffset));
      }
      else
      {
    #endif
      pps.setQpOffset(COMPONENT_Cb, m_chromaCbQpOffset );
      pps.setQpOffset(COMPONENT_Cr, m_chromaCrQpOffset );
    #if ER_CHROMA_QP_WCG_PPS
      }
    #endif
    #if W0038_CQP_ADJ
      bool bChromaDeltaQPEnabled = false;
      {
        bChromaDeltaQPEnabled = ( m_sliceChromaQpOffsetIntraOrPeriodic[0] || m_sliceChromaQpOffsetIntraOrPeriodic[1] );
        if( !bChromaDeltaQPEnabled )
        {
          for( int i=0; i<m_iGOPSize; i++ )
          {
            if( m_GOPList[i].m_CbQPoffset || m_GOPList[i].m_CrQPoffset )
            {
              bChromaDeltaQPEnabled = true;
              break;
            }
          }
        }
      }
    
     #if ENABLE_QPA
      if ((getUsePerceptQPA() || getSliceChromaOffsetQpPeriodicity() > 0) && (getChromaFormatIdc() != CHROMA_400))
      {
        bChromaDeltaQPEnabled = true;
      }
     #endif
    
      pps.setSliceChromaQpFlag(bChromaDeltaQPEnabled);
    #endif
    
        !pps.getSliceChromaQpFlag() && sps.getUseDualITree()
    
        && (getChromaFormatIdc() != CHROMA_400))
    
      {
        pps.setSliceChromaQpFlag(m_chromaCbQpOffsetDualTree != 0 || m_chromaCrQpOffsetDualTree != 0);
      }
    
      pps.setEntropyCodingSyncEnabledFlag( m_entropyCodingSyncEnabledFlag );
      pps.setTilesEnabledFlag( (m_iNumColumnsMinus1 > 0 || m_iNumRowsMinus1 > 0) );
      pps.setUseWP( m_useWeightedPred );
      pps.setWPBiPred( m_useWeightedBiPred );
      pps.setOutputFlagPresentFlag( false );
    
      if ( getDeblockingFilterMetric() )
      {
        pps.setDeblockingFilterOverrideEnabledFlag(true);
        pps.setPPSDeblockingFilterDisabledFlag(false);
      }
      else
      {
        pps.setDeblockingFilterOverrideEnabledFlag( !getLoopFilterOffsetInPPS() );
        pps.setPPSDeblockingFilterDisabledFlag( getLoopFilterDisable() );
      }
    
      if (! pps.getPPSDeblockingFilterDisabledFlag())
      {
        pps.setDeblockingFilterBetaOffsetDiv2( getLoopFilterBetaOffset() );
        pps.setDeblockingFilterTcOffsetDiv2( getLoopFilterTcOffset() );
      }
      else
      {
        pps.setDeblockingFilterBetaOffsetDiv2(0);
        pps.setDeblockingFilterTcOffsetDiv2(0);
      }
    
      // deblockingFilterControlPresentFlag is true if any of the settings differ from the inferred values:
      const bool deblockingFilterControlPresentFlag = pps.getDeblockingFilterOverrideEnabledFlag() ||
                                                      pps.getPPSDeblockingFilterDisabledFlag()     ||
                                                      pps.getDeblockingFilterBetaOffsetDiv2() != 0 ||
                                                      pps.getDeblockingFilterTcOffsetDiv2() != 0;
    
      pps.setDeblockingFilterControlPresentFlag(deblockingFilterControlPresentFlag);
    
      pps.setLog2ParallelMergeLevelMinus2   (m_log2ParallelMergeLevelMinus2 );
      pps.setCabacInitPresentFlag(CABAC_INIT_PRESENT_FLAG);
      pps.setLoopFilterAcrossSlicesEnabledFlag( m_bLFCrossSliceBoundaryFlag );
    
    
      int histogram[MAX_NUM_REF + 1];
      for( int i = 0; i <= MAX_NUM_REF; i++ )
      {
        histogram[i]=0;
      }
      for( int i = 0; i < getGOPSize(); i++)
      {
        CHECK(!(getGOPEntry(i).m_numRefPicsActive >= 0 && getGOPEntry(i).m_numRefPicsActive <= MAX_NUM_REF), "Unspecified error");
        histogram[getGOPEntry(i).m_numRefPicsActive]++;
      }
    
      int maxHist=-1;
      int bestPos=0;
      for( int i = 0; i <= MAX_NUM_REF; i++ )
      {
        if(histogram[i]>maxHist)
        {
          maxHist=histogram[i];
          bestPos=i;
        }
      }
      CHECK(!(bestPos <= 15), "Unspecified error");
    
        pps.setNumRefIdxL0DefaultActive(bestPos);
    
      pps.setNumRefIdxL1DefaultActive(bestPos);
      pps.setTransquantBypassEnabledFlag(getTransquantBypassEnabledFlag());
      pps.setUseTransformSkip( m_useTransformSkip );
      pps.getPpsRangeExtension().setLog2MaxTransformSkipBlockSize( m_log2MaxTransformSkipBlockSize  );
    
    #if HEVC_DEPENDENT_SLICES
      if (m_sliceSegmentMode != NO_SLICES)
      {
        pps.setDependentSliceSegmentsEnabledFlag( true );
      }
    #endif
    
      xInitPPSforTiles(pps);
    
      pps.pcv = new PreCalcValues( sps, pps, true );
    }
    
    
    Hendry's avatar
    Hendry committed
    void EncLib::xInitAPS(APS &aps)
    {
      //Do nothing now
    }
    
    //Function for initializing m_RPSList, a list of ReferencePictureSet, based on the GOPEntry objects read from the config file.
    void EncLib::xInitRPS(SPS &sps, bool isFieldCoding)
    {
      ReferencePictureSet*      rps;
    
      sps.createRPSList(getGOPSize() + m_extraRPSs + 1);
      RPSList* rpsList = sps.getRPSList();
    
      for( int i = 0; i < getGOPSize()+m_extraRPSs; i++)
      {
        const GOPEntry &ge = getGOPEntry(i);
        rps = rpsList->getReferencePictureSet(i);
        rps->setNumberOfPictures(ge.m_numRefPics);
        rps->setNumRefIdc(ge.m_numRefIdc);
        int numNeg = 0;
        int numPos = 0;
        for( int j = 0; j < ge.m_numRefPics; j++)
        {
          rps->setDeltaPOC(j,ge.m_referencePics[j]);
          rps->setUsed(j,ge.m_usedByCurrPic[j]);
          if(ge.m_referencePics[j]>0)
          {
            numPos++;
          }
          else
          {
            numNeg++;
          }
        }
        rps->setNumberOfNegativePictures(numNeg);
        rps->setNumberOfPositivePictures(numPos);
    
        // handle inter RPS intialization from the config file.
        rps->setInterRPSPrediction(ge.m_interRPSPrediction > 0);  // not very clean, converting anything > 0 to true.
        rps->setDeltaRIdxMinus1(0);                               // index to the Reference RPS is always the previous one.
        ReferencePictureSet*     RPSRef = i>0 ? rpsList->getReferencePictureSet(i-1): NULL;  // get the reference RPS
    
        if (ge.m_interRPSPrediction == 2)  // Automatic generation of the inter RPS idc based on the RIdx provided.
        {
          CHECK(!(RPSRef!=NULL), "Unspecified error");
          int deltaRPS = getGOPEntry(i-1).m_POC - ge.m_POC;  // the ref POC - current POC
          int numRefDeltaPOC = RPSRef->getNumberOfPictures();
    
          rps->setDeltaRPS(deltaRPS);           // set delta RPS
          rps->setNumRefIdc(numRefDeltaPOC+1);  // set the numRefIdc to the number of pictures in the reference RPS + 1.
          int count=0;
          for (int j = 0; j <= numRefDeltaPOC; j++ ) // cycle through pics in reference RPS.
          {
            int RefDeltaPOC = (j<numRefDeltaPOC)? RPSRef->getDeltaPOC(j): 0;  // if it is the last decoded picture, set RefDeltaPOC = 0
            rps->setRefIdc(j, 0);
            for (int k = 0; k < rps->getNumberOfPictures(); k++ )  // cycle through pics in current RPS.
            {
              if (rps->getDeltaPOC(k) == ( RefDeltaPOC + deltaRPS))  // if the current RPS has a same picture as the reference RPS.
              {
                  rps->setRefIdc(j, (rps->getUsed(k)?1:2));
                  count++;
                  break;
              }
            }
          }
          if (count != rps->getNumberOfPictures())
          {
            msg( WARNING, "Warning: Unable fully predict all delta POCs using the reference RPS index given in the config file.  Setting Inter RPS to false for this RPS.\n");
            rps->setInterRPSPrediction(0);
          }
        }
        else if (ge.m_interRPSPrediction == 1)  // inter RPS idc based on the RefIdc values provided in config file.
        {
          CHECK(!(RPSRef!=NULL), "Unspecified error");
          rps->setDeltaRPS(ge.m_deltaRPS);
          rps->setNumRefIdc(ge.m_numRefIdc);
          for (int j = 0; j < ge.m_numRefIdc; j++ )
          {
            rps->setRefIdc(j, ge.m_refIdc[j]);
          }
          // the following code overwrite the deltaPOC and Used by current values read from the config file with the ones
          // computed from the RefIdc.  A warning is printed if they are not identical.
          numNeg = 0;
          numPos = 0;
          ReferencePictureSet      RPSTemp;  // temporary variable
    
          for (int j = 0; j < ge.m_numRefIdc; j++ )
          {
            if (ge.m_refIdc[j])
            {
              int deltaPOC = ge.m_deltaRPS + ((j < RPSRef->getNumberOfPictures())? RPSRef->getDeltaPOC(j) : 0);
              RPSTemp.setDeltaPOC((numNeg+numPos),deltaPOC);
              RPSTemp.setUsed((numNeg+numPos),ge.m_refIdc[j]==1?1:0);
              if (deltaPOC<0)
              {
                numNeg++;
              }
              else
              {
                numPos++;
              }
            }
          }
          if (numNeg != rps->getNumberOfNegativePictures())
          {
            msg( WARNING, "Warning: number of negative pictures in RPS is different between intra and inter RPS specified in the config file.\n");
            rps->setNumberOfNegativePictures(numNeg);
            rps->setNumberOfPictures(numNeg+numPos);
          }
          if (numPos != rps->getNumberOfPositivePictures())
          {
            msg( WARNING, "Warning: number of positive pictures in RPS is different between intra and inter RPS specified in the config file.\n");
            rps->setNumberOfPositivePictures(numPos);
            rps->setNumberOfPictures(numNeg+numPos);
          }
          RPSTemp.setNumberOfPictures(numNeg+numPos);
          RPSTemp.setNumberOfNegativePictures(numNeg);
          RPSTemp.sortDeltaPOC();     // sort the created delta POC before comparing
          // check if Delta POC and Used are the same
          // print warning if they are not.
          for (int j = 0; j < ge.m_numRefIdc; j++ )
          {
            if (RPSTemp.getDeltaPOC(j) != rps->getDeltaPOC(j))
            {
              msg( WARNING, "Warning: delta POC is different between intra RPS and inter RPS specified in the config file.\n");
              rps->setDeltaPOC(j,RPSTemp.getDeltaPOC(j));
            }
            if (RPSTemp.getUsed(j) != rps->getUsed(j))
            {
              msg( WARNING, "Warning: Used by Current in RPS is different between intra and inter RPS specified in the config file.\n");
              rps->setUsed(j,RPSTemp.getUsed(j));
            }
          }
        }
      }
      //In case of field coding, we need to set special parameters for the first bottom field of the sequence, since it is not specified in the cfg file.
      //The position = GOPSize + extraRPSs which is (a priori) unused is reserved for this field in the RPS.
      if (isFieldCoding)
      {
        rps = rpsList->getReferencePictureSet(getGOPSize()+m_extraRPSs);
        rps->setNumberOfPictures(1);
        rps->setNumberOfNegativePictures(1);
        rps->setNumberOfPositivePictures(0);
        rps->setNumberOfLongtermPictures(0);
        rps->setDeltaPOC(0,-1);
        rps->setPOC(0,0);
        rps->setUsed(0,true);
        rps->setInterRPSPrediction(false);
        rps->setDeltaRIdxMinus1(0);
        rps->setDeltaRPS(0);
        rps->setNumRefIdc(0);
      }
    }
    
       // This is a function that
       // determines what Reference Picture Set to use
       // for a specific slice (with POC = POCCurr)
    
    void EncLib::selectReferencePictureSet(Slice* slice, int POCCurr, int GOPid
                                          , int ltPoc
    )
    
      bool isEncodeLtRef = (POCCurr == ltPoc);
      if (m_compositeRefEnabled && isEncodeLtRef)
      {
        POCCurr++;
      }
      int rIdx = GOPid;
    
      slice->setRPSidx(GOPid);
    
      for(int extraNum=m_iGOPSize; extraNum<m_extraRPSs+m_iGOPSize; extraNum++)
      {
        if(m_uiIntraPeriod > 0 && getDecodingRefreshType() > 0)
        {
          int POCIndex = POCCurr%m_uiIntraPeriod;
          if(POCIndex == 0)
          {
            POCIndex = m_uiIntraPeriod;
          }
          if(POCIndex == m_GOPList[extraNum].m_POC)
          {
            slice->setRPSidx(extraNum);
    
          }
        }
        else
        {
          if(POCCurr==m_GOPList[extraNum].m_POC)
          {
            slice->setRPSidx(extraNum);
    
          }
        }
      }
    
      if(POCCurr == 1 && slice->getPic()->fieldPic)
      {
        slice->setRPSidx(m_iGOPSize+m_extraRPSs);
    
        rIdx = m_iGOPSize + m_extraRPSs;
    
      ReferencePictureSet *rps = const_cast<ReferencePictureSet *>(slice->getSPS()->getRPSList()->getReferencePictureSet(slice->getRPSidx()));
      if (m_compositeRefEnabled && ltPoc != -1 && !isEncodeLtRef)
      {
        if (ltPoc != -1 && rps->getNumberOfLongtermPictures() != 1 && !isEncodeLtRef)
        {
          int idx = rps->getNumberOfPictures();
          int maxPicOrderCntLSB = 1 << slice->getSPS()->getBitsForPOC();
          int ltPocLsb = ltPoc % maxPicOrderCntLSB;
    
          rps->setNumberOfPictures(rps->getNumberOfPictures() + 1);
          rps->setNumberOfLongtermPictures(1);
          rps->setPOC(idx, ltPoc);
          rps->setPocLSBLT(idx, ltPocLsb);
          rps->setDeltaPOC(idx, -POCCurr + ltPoc);
          rps->setUsed(idx, true);
        }
      }
      else if (m_compositeRefEnabled && isEncodeLtRef)
      {
        ReferencePictureSet* localRPS = slice->getLocalRPS();
        (*localRPS) = ReferencePictureSet();
        int refPics = rps->getNumberOfPictures();
        localRPS->setNumberOfPictures(rps->getNumberOfPictures());
        for (int i = 0; i < refPics; i++)
        {
          localRPS->setDeltaPOC(i, rps->getDeltaPOC(i) + 1);
          localRPS->setUsed(i, rps->getUsed(i));
        }
        localRPS->setNumberOfNegativePictures(rps->getNumberOfNegativePictures());
        localRPS->setNumberOfPositivePictures(rps->getNumberOfPositivePictures());
        localRPS->setInterRPSPrediction(true);
        int deltaRPS = 1;
        int newIdc = 0;
        for (int i = 0; i < refPics; i++)
        {
          int deltaPOC = ((i != refPics) ? rps->getDeltaPOC(i) : 0);  // check if the reference abs POC is >= 0
          int refIdc = 0;
          for (int j = 0; j < localRPS->getNumberOfPictures(); j++) // loop through the  pictures in the new RPS
          {
            if ((deltaPOC + deltaRPS) == localRPS->getDeltaPOC(j))
            {
              if (localRPS->getUsed(j))
              {
                refIdc = 1;
              }
              else
              {
                refIdc = 2;
              }
            }
          }
          localRPS->setRefIdc(i, refIdc);
          newIdc++;
        }
        localRPS->setNumRefIdc(newIdc + 1);
        localRPS->setRefIdc(newIdc, 0);
        localRPS->setDeltaRPS(deltaRPS);
        localRPS->setDeltaRIdxMinus1(slice->getSPS()->getRPSList()->getNumberOfReferencePictureSets() - 1 - rIdx);
        slice->setRPS(localRPS);
        slice->setRPSidx(-1);
        return;
      }
    
      slice->setRPS(rps);
    }
    
    int EncLib::getReferencePictureSetIdxForSOP(int POCCurr, int GOPid )
    {
      int rpsIdx = GOPid;
    
      for(int extraNum=m_iGOPSize; extraNum<m_extraRPSs+m_iGOPSize; extraNum++)
      {
        if(m_uiIntraPeriod > 0 && getDecodingRefreshType() > 0)
        {
          int POCIndex = POCCurr%m_uiIntraPeriod;
          if(POCIndex == 0)
          {
            POCIndex = m_uiIntraPeriod;
          }
          if(POCIndex == m_GOPList[extraNum].m_POC)
          {
            rpsIdx = extraNum;
          }
        }
        else
        {
          if(POCCurr==m_GOPList[extraNum].m_POC)
          {
            rpsIdx = extraNum;
          }
        }
      }
    
      return rpsIdx;
    }
    
    void  EncLib::xInitPPSforTiles(PPS &pps)
    {
      pps.setTileUniformSpacingFlag( m_tileUniformSpacingFlag );
      pps.setNumTileColumnsMinus1( m_iNumColumnsMinus1 );
      pps.setNumTileRowsMinus1( m_iNumRowsMinus1 );
      if( !m_tileUniformSpacingFlag )
      {
        pps.setTileColumnWidth( m_tileColumnWidth );
        pps.setTileRowHeight( m_tileRowHeight );
      }
      pps.setLoopFilterAcrossTilesEnabledFlag( m_loopFilterAcrossTilesEnabledFlag );
    
      // # substreams is "per tile" when tiles are independent.
    }
    
    void  EncCfg::xCheckGSParameters()
    {
      int   iWidthInCU = ( m_iSourceWidth%m_maxCUWidth ) ? m_iSourceWidth/m_maxCUWidth + 1 : m_iSourceWidth/m_maxCUWidth;
      int   iHeightInCU = ( m_iSourceHeight%m_maxCUHeight ) ? m_iSourceHeight/m_maxCUHeight + 1 : m_iSourceHeight/m_maxCUHeight;
      uint32_t  uiCummulativeColumnWidth = 0;
      uint32_t  uiCummulativeRowHeight = 0;
    
      //check the column relative parameters
      if( m_iNumColumnsMinus1 >= (1<<(LOG2_MAX_NUM_COLUMNS_MINUS1+1)) )
      {
        EXIT( "The number of columns is larger than the maximum allowed number of columns." );
      }
    
      if( m_iNumColumnsMinus1 >= iWidthInCU )
      {
        EXIT( "The current picture can not have so many columns." );
      }
    
      if( m_iNumColumnsMinus1 && !m_tileUniformSpacingFlag )
      {
        for(int i=0; i<m_iNumColumnsMinus1; i++)
        {
          uiCummulativeColumnWidth += m_tileColumnWidth[i];
        }
    
        if( uiCummulativeColumnWidth >= iWidthInCU )
        {
          EXIT( "The width of the column is too large." );
        }
      }
    
      //check the row relative parameters
      if( m_iNumRowsMinus1 >= (1<<(LOG2_MAX_NUM_ROWS_MINUS1+1)) )
      {
        EXIT( "The number of rows is larger than the maximum allowed number of rows." );
      }
    
      if( m_iNumRowsMinus1 >= iHeightInCU )
      {
        EXIT( "The current picture can not have so many rows." );
      }
    
      if( m_iNumRowsMinus1 && !m_tileUniformSpacingFlag )
      {
        for(int i=0; i<m_iNumRowsMinus1; i++)
        {
          uiCummulativeRowHeight += m_tileRowHeight[i];
        }
    
        if( uiCummulativeRowHeight >= iHeightInCU )
        {
          EXIT( "The height of the row is too large." );
        }
      }
    }
    
    
    #if JCTVC_Y0038_PARAMS
    void EncLib::setParamSetChanged(int spsId, int ppsId)
    {
      m_ppsMap.setChangedFlag(ppsId);
      m_spsMap.setChangedFlag(spsId);
    }
    #endif
    
    Hendry's avatar
    Hendry committed
    bool EncLib::APSNeedsWriting(int apsId)
    {
    
      bool isChanged = m_apsMap.getChangedFlag(apsId);
    
    Hendry's avatar
    Hendry committed
      m_apsMap.clearChangedFlag(apsId);
    
    Hendry's avatar
    Hendry committed
    }
    
    bool EncLib::PPSNeedsWriting(int ppsId)
    {
      bool bChanged=m_ppsMap.getChangedFlag(ppsId);
      m_ppsMap.clearChangedFlag(ppsId);
      return bChanged;
    }
    
    bool EncLib::SPSNeedsWriting(int spsId)
    {
      bool bChanged=m_spsMap.getChangedFlag(spsId);
      m_spsMap.clearChangedFlag(spsId);
      return bChanged;
    }
    
    #if X0038_LAMBDA_FROM_QP_CAPABILITY
    int EncCfg::getQPForPicture(const uint32_t gopIndex, const Slice *pSlice) const
    {
      const int lumaQpBDOffset = pSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA);
      int qp;
    
      if (getCostMode()==COST_LOSSLESS_CODING)
      {
        qp=LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP;
      }
      else
      {
        const SliceType sliceType=pSlice->getSliceType();
    
        qp = getBaseQP();
    
        // switch at specific qp and keep this qp offset
        static int appliedSwitchDQQ = 0; /* TODO: MT */
        if( pSlice->getPOC() == getSwitchPOC() )
        {
          appliedSwitchDQQ = getSwitchDQP();
        }
        qp += appliedSwitchDQQ;
    
    #if QP_SWITCHING_FOR_PARALLEL
        const int* pdQPs = getdQPs();
        if ( pdQPs )
        {
    
          qp += pdQPs[pSlice->getPOC() / (m_compositeRefEnabled ? 2 : 1)];
    
        }
    #endif
    
        if(sliceType==I_SLICE)
        {
          qp += getIntraQPOffset();
        }
        else
        {
    #if SHARP_LUMA_DELTA_QP
          // Only adjust QP when not lossless
          if (!(( getMaxDeltaQP() == 0 ) && (!getLumaLevelToDeltaQPMapping().isEnabled()) && (qp == -lumaQpBDOffset ) && (pSlice->getPPS()->getTransquantBypassEnabledFlag())))
    #else
          if (!(( getMaxDeltaQP() == 0 ) && (qp == -lumaQpBDOffset ) && (pSlice->getPPS()->getTransquantBypassEnabledFlag())))
    #endif
    
          {
            const GOPEntry &gopEntry=getGOPEntry(gopIndex);
            // adjust QP according to the QP offset for the GOP entry.
            qp +=gopEntry.m_QPOffset;
    
            // adjust QP according to QPOffsetModel for the GOP entry.
            double dqpOffset=qp*gopEntry.m_QPOffsetModelScale+gopEntry.m_QPOffsetModelOffset+0.5;
            int qpOffset = (int)floor(Clip3<double>(0.0, 3.0, dqpOffset));
            qp += qpOffset ;
          }
        }
    
    #if !QP_SWITCHING_FOR_PARALLEL
        // modify QP if a fractional QP was originally specified, cause dQPs to be 0 or 1.
        const int* pdQPs = getdQPs();
        if ( pdQPs )
        {
          qp += pdQPs[ pSlice->getPOC() ];
        }
    #endif
      }
      qp = Clip3( -lumaQpBDOffset, MAX_QP, qp );
      return qp;
    }
    #endif
    
    //! \}