Skip to content
Snippets Groups Projects
EncGOP.cpp 292 KiB
Newer Older
  • Learn to ignore specific revisions
  •         m_pcSAO->SAOProcess( cs, sliceEnabled, pcSlice->getLambdas(),
    #if ENABLE_QPA
                                 (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP() ? m_pcEncLib->getRdCost (PARL_PARAM0 (0))->getChromaWeight() : 0.0),
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                                 m_pcCfg->getTestSAODisableAtPictureLevel(), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma(), m_pcCfg->getSaoCtuBoundary(), m_pcCfg->getSaoGreedyMergeEnc()
    
    #if JVET_V0094_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                                  , &est
    #endif
                                );
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            if( pcSlice->getSPS()->getSAOEnabledFlag() )
            {
    #endif
    
            for (int s = 0; s < uiNumSliceSegments; s++)
    
    
              if (pcPic->slices[s]->isLossless() && m_pcCfg->getCostMode() == COST_LOSSLESS_CODING)
              {
                pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, false);
                pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, false);
              }
              else
              {
                pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, sliceEnabled[COMPONENT_Y]);
                CHECK(!(sliceEnabled[COMPONENT_Cb] == sliceEnabled[COMPONENT_Cr]), "Unspecified error");
                pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, sliceEnabled[COMPONENT_Cb]);
    
            }
    
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          }
    #endif
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #if JVET_W0066_CCSAO
          if ( pcSlice->getSPS()->getCCSAOEnabledFlag() )
          {
            m_pcSAO->initCABACEstimator( m_pcEncLib->getCABACEncoder(), m_pcEncLib->getCtxCache(), pcSlice );
            m_pcSAO->CCSAOProcess( cs, pcSlice->getLambdas(), m_pcCfg->getIntraPeriod() );
    
            //assign CCSAO slice header
            for (int s = 0; s < uiNumSliceSegments; s++)
            {
              pcPic->slices[s]->m_ccSaoComParam              = m_pcSAO->getCcSaoComParam();
              pcPic->slices[s]->m_ccSaoControl[COMPONENT_Y]  = m_pcSAO->getCcSaoControlIdc(COMPONENT_Y);
              pcPic->slices[s]->m_ccSaoControl[COMPONENT_Cb] = m_pcSAO->getCcSaoControlIdc(COMPONENT_Cb);
              pcPic->slices[s]->m_ccSaoControl[COMPONENT_Cr] = m_pcSAO->getCcSaoControlIdc(COMPONENT_Cr);
            }
          }
          m_pcSAO->jointClipSaoBifCcSao( cs );
    #endif
    
    
          if( pcSlice->getSPS()->getSAOEnabledFlag()
    #if JVET_W0066_CCSAO
           || pcSlice->getSPS()->getCCSAOEnabledFlag()
    #endif
            )
          {
            m_pcSAO->destroyEncData();
          }
    
    
    #if RPR_ENABLE && !JVET_AA0095_ALF_WITH_SAMPLES_BEFORE_DBF
    
    Philippe Bordes's avatar
    Philippe Bordes committed
          // create ALF object based on the picture size
          if ( pcSlice->getSPS()->getALFEnabledFlag() )
          {
            Size alfSize = m_pcALF->getAlfSize();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            if ( alfSize.width != picWidth || alfSize.height != picHeight )
            {
    
    Philippe Bordes's avatar
    Philippe Bordes committed
              m_pcALF->destroy();
              m_pcALF->create( m_pcCfg, picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth, m_pcCfg->getBitDepth(), m_pcCfg->getInputBitDepth() );
            }
          }
    #endif
    
    
          if( pcSlice->getSPS()->getALFEnabledFlag() )
    
            // create ALF encoder data based on the picture size
    
            m_pcALF->create(m_pcCfg, picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth, m_pcCfg->getBitDepth(), m_pcCfg->getInputBitDepth(), true);
    
    
            for (int s = 0; s < uiNumSliceSegments; s++)
            {
              pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, false);
            }
    
            m_pcALF->initCABACEstimator(m_pcEncLib->getCABACEncoder(), m_pcEncLib->getCtxCache(), pcSlice, m_pcEncLib->getApsMap());
    
            m_pcALF->ALFProcess(cs, pcSlice->getLambdas()
    #if ENABLE_QPA
              , (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP() ? m_pcEncLib->getRdCost(PARL_PARAM0(0))->getChromaWeight() : 0.0)
    
    #endif
              , pcPic, uiNumSliceSegments
    
    #if JVET_AC0162_ALF_RESIDUAL_SAMPLES_INPUT
              , m_pcCfg->getIntraPeriod()
    #endif
    
    #if JVET_AK0121_LOOPFILTER_OFFSET_REFINEMENT
            if( cs.sps->getALFEnabledFlag() )
            {
              bool sliceTypeCondition = !cs.slice->isIntra();
              bool alfEnabled = cs.slice->getTileGroupAlfEnabledFlag( COMPONENT_Y );
              bool enableRefinement = false;
              PelUnitBuf alfInput = m_pcALF->callRecAfterSaoBuf();
              PelUnitBuf alfOutput = cs.getRecoBuf();
    
              PelUnitBuf alfOffsetRefine0 = m_pcALF->callRecBeforeDbfBuf();
              PelUnitBuf alfOffsetRefine1 = m_pcALF->callRecBeforeAlfBuf();
    
              int stageIdx = 1;
              int refineIdx = 0;
    
              if( sliceTypeCondition && alfEnabled )
              {
                m_pcALF->calcOffsetRefinement(cs, alfInput, alfOutput, alfOffsetRefine0, stageIdx, 0 );
                m_pcALF->calcOffsetRefinement(cs, alfInput, alfOutput, alfOffsetRefine1, stageIdx, 1 );
                enableRefinement = m_pcALF->calcOffsetRefinementOnOff(cs, alfOutput, alfOffsetRefine0, alfOffsetRefine1, refineIdx );
              }
    
              if( sliceTypeCondition && enableRefinement )
              {
                cs.slice->setOffsetRefinementAlf( true );
                cs.slice->setOffsetRefinementAlfIdx( refineIdx );
                m_pcALF->copyOffsetRefinement(cs, refineIdx ? alfOffsetRefine1 : alfOffsetRefine0, alfOutput);
              }
              else
              {
                cs.slice->setOffsetRefinementAlf( false );
                cs.slice->setOffsetRefinementAlfIdx( false );
              }
            }
    #endif
    
            //assign ALF slice header
            for (int s = 0; s < uiNumSliceSegments; s++)
            {
    
               //For the first slice, even if it is lossless, slice level ALF is not disabled and ALF-APS is signaled so that the later lossy slices can use APS of the first slice. 
               //However, if the first slice is lossless, the ALF process is disabled for all of the CTUs ( m_ctuEnableFlag == 0) of that slice which is implemented in the function void EncAdaptiveLoopFilter::ALFProcess.         
          
              if (pcPic->slices[s]->isLossless() && s && m_pcCfg->getCostMode() == COST_LOSSLESS_CODING)
              {
                pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, false);
                pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, false);
                pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, false);
              }
              else
              {
                pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y));
                pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb));
                pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr));
    
              }
    
              if (pcPic->slices[s]->getTileGroupAlfEnabledFlag(COMPONENT_Y))
              {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ALF_IMPROVEMENT
    
    #if JVET_AG0157_ALF_CHROMA_FIXED_FILTER
                pcPic->slices[s]->setTileGroupAlfFixedFilterSetIdx(COMPONENT_Y, cs.slice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Y));
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                pcPic->slices[s]->setTileGroupAlfFixedFilterSetIdx(cs.slice->getTileGroupAlfFixedFilterSetIdx());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
                pcPic->slices[s]->setTileGroupNumAps(cs.slice->getTileGroupNumAps());
    
                pcPic->slices[s]->setAlfAPSs(cs.slice->getTileGroupApsIdLuma());
    
              if( s < uiNumSliceSegments - 1 )
              {
                pcPic->slices[s]->setAlfAPSs(cs.slice->getAlfAPSs());
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF
                pcPic->slices[s]->setTAlfAPSs(cs.slice->getTAlfAPSs());
    #endif
    
              pcPic->slices[s]->setTileGroupApsIdChroma(cs.slice->getTileGroupApsIdChroma());
    
              pcPic->slices[s]->setTileGroupCcAlfCbApsId(cs.slice->getTileGroupCcAlfCbApsId());
              pcPic->slices[s]->setTileGroupCcAlfCrApsId(cs.slice->getTileGroupCcAlfCrApsId());
    
    #if JVET_AG0157_ALF_CHROMA_FIXED_FILTER
              pcPic->slices[s]->setTileGroupAlfFixedFilterSetIdx(COMPONENT_Cb, cs.slice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Cb));
              pcPic->slices[s]->setTileGroupAlfFixedFilterSetIdx(COMPONENT_Cr, cs.slice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Cr));
    #endif
    
              pcPic->slices[s]->m_ccAlfFilterParam      = m_pcALF->getCcAlfFilterParam();
              pcPic->slices[s]->m_ccAlfFilterControl[0] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cb);
              pcPic->slices[s]->m_ccAlfFilterControl[1] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cr);
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF
              pcPic->slices[s]->setTileGroupTAlfControl(cs.slice->getTileGroupTAlfControl());
              pcPic->slices[s]->m_tAlfCtbControl       = m_pcALF->getTAlfControl();
    #endif
    
          DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) );
    
          if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef())
    
          {
            updateCompositeReference(pcSlice, rcListPic, pocCurr);
          }
    
    #if JVET_AG0145_ADAPTIVE_CLIPPING
          adaptiveClipToRealRange(pcPic);
    #endif
    
        }
        else // skip enc picture
        {
          pcSlice->setSliceQpBase( pcSlice->getSliceQp() );
    
    
    #if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT 
          m_pcSliceEncoder->getCABACDataStore()->updateBufferState( pcSlice );
    #endif
    
    #if JVET_AG0098_AMVP_WITH_SBTMVP
          m_pcSliceEncoder->clearAmvpSbTmvpStatArea(pcSlice);
    
          if (pcSlice->getPicHeader()->getEnableTMVPFlag() && !pcSlice->isIntra())
          {
            int minPoc = abs(pcSlice->getRefPic(RefPicList(1 - pcSlice->getColFromL0Flag()), pcSlice->getColRefIdx())->getPOC() - pcSlice->getPOC());
            if (pcSlice->isInterB() && pcSlice->getCheckLDC())
            {
              int min2ndPoc = abs(pcSlice->getRefPic(RefPicList(1 - pcSlice->getColFromL0Flag2nd()), pcSlice->getColRefIdx2nd())->getPOC() - pcSlice->getPOC());
              minPoc = min(minPoc, min2ndPoc);
            }
            if (minPoc > 4)
            {
              pcSlice->setAmvpSbTmvpEnabledFlag(false);
    
    Jani Lainema's avatar
    Jani Lainema committed
              pcSlice->setAmvpSbTmvpAmvrEnabledFlag(false);
    
            }
            else
            {
              pcSlice->setAmvpSbTmvpEnabledFlag(true);
    
              g_picAmvpSbTmvpEnabledArea = 0;
              uint32_t prevEnabledArea;
              bool isExist = m_pcSliceEncoder->loadAmvpSbTmvpStatArea(pcSlice->getTLayer(), prevEnabledArea);
              if (isExist)
              {
                int ratio = int(prevEnabledArea * 100.0 / (pcSlice->getPic()->getPicWidthInLumaSamples() * pcSlice->getPic()->getPicHeightInLumaSamples()));
                if (ratio < 4)
                {
                  pcSlice->setAmvpSbTmvpNumOffset(1);
                }
                else if (ratio < 7)
                {
                  pcSlice->setAmvpSbTmvpNumOffset(2);
                }
                else
                {
                  pcSlice->setAmvpSbTmvpNumOffset(3);
                }
              }
              else
              {
                pcSlice->setAmvpSbTmvpNumOffset(2);
              }
              if (pcSlice->isInterB() && pcSlice->getCheckLDC())
              {
                if (pcSlice->getRefPic(RefPicList(1 - pcSlice->getColFromL0Flag()), pcSlice->getColRefIdx())->getPOC() == pcSlice->getRefPic(RefPicList(1 - pcSlice->getColFromL0Flag2nd()), pcSlice->getColRefIdx2nd())->getPOC())
                {
                  pcSlice->setAmvpSbTmvpNumColPic(1);
                }
                else
                {
                  pcSlice->setAmvpSbTmvpNumColPic(2);
                }
              }
              else
              {
                pcSlice->setAmvpSbTmvpNumColPic(1);
              }
              pcSlice->setAmvpSbTmvpAmvrEnabledFlag(pcSlice->getPic()->getPicWidthInLumaSamples() * pcSlice->getPic()->getPicHeightInLumaSamples() < 3840 * 2160 ? false : true);
            }
          }
          else
          {
            pcSlice->setAmvpSbTmvpEnabledFlag(false);
          }
    
    #if ENABLE_QPA
          if (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP())
          {
            const double picLambda = pcSlice->getLambdas()[0];
    
            for (uint32_t ctuRsAddr = 0; ctuRsAddr < numberOfCtusInFrame; ctuRsAddr++)
            {
              pcPic->m_uEnerHpCtu[ctuRsAddr] = picLambda;  // initialize to slice lambda (just for safety)
            }
          }
    #endif
    
          if( pcSlice->getSPS()->getSAOEnabledFlag() )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            // This does not need to be run even if BIF=1.
    
            m_pcSAO->disabledRate( *pcPic->cs, pcPic->getSAO(1), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma());
          }
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF
          const TAlfControl talfControl = pcSlice->getTileGroupTAlfControl();
          if ((pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag()))
              || (pcSlice->getSPS()->getUseTAlf() && talfControl.enabledFlag))  // ALF or TALF enabled.
    #else
    
          if (pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag()))
    
    Luhang Xu's avatar
    Luhang Xu committed
    #endif
    
          {
            // IRAP AU: reset APS map
            {
              int layerIdx = pcSlice->getVPS() == nullptr ? 0 : pcSlice->getVPS()->getGeneralLayerIdx( pcSlice->getPic()->layerId );
              if( !layerIdx && ( pcSlice->getPendingRasInit() || pcSlice->isIDRorBLA() ) )
              {
                // We have to reset all APS on IRAP, but in not encoding case we have to keep the parsed APS of current slice
                // Get active ALF APSs from picture/slice header
                const std::vector<int> sliceApsIdsLuma = pcSlice->getTileGroupApsIdLuma();
    
                m_pcALF->setApsIdStart( ALF_CTB_MAX_NUM_APS );
    
                ParameterSetMap<APS>* apsMap = m_pcEncLib->getApsMap();
                apsMap->clear();
    
                for( int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++ )
                {
                  int psId = ( apsId << NUM_APS_TYPE_LEN ) + ALF_APS;
                  APS* aps = apsMap->getPS( psId );
                  if( aps )
                  {
                    // Check if this APS is currently the active one (used in current slice)
                    bool activeAps = false;
                    bool activeApsCcAlf = false;
                    // Luma
                    for( int i = 0; i < sliceApsIdsLuma.size(); i++ )
                    {
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF
                      if( aps->getAPSId() == sliceApsIdsLuma[i] && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) )
    #else
    
                      if( aps->getAPSId() == sliceApsIdsLuma[i] )
    
    Luhang Xu's avatar
    Luhang Xu committed
    #endif
    
                      {
                        activeAps = true;
                        break;
                      }
                    }
                    // Chroma
                    activeAps |= aps->getAPSId() == pcSlice->getTileGroupApsIdChroma();
                    // CC-ALF
                    activeApsCcAlf |= pcSlice->getTileGroupCcAlfCbEnabledFlag() && aps->getAPSId() == pcSlice->getTileGroupCcAlfCbApsId();
                    activeApsCcAlf |= pcSlice->getTileGroupCcAlfCrEnabledFlag() && aps->getAPSId() == pcSlice->getTileGroupCcAlfCrApsId();
                    if( !activeAps && !activeApsCcAlf )
                    {
                      apsMap->clearChangedFlag( psId );
                    }
                    if( !activeAps  )
                    {
                      aps->getAlfAPSParam().reset();
                    }
                    if( !activeApsCcAlf )
                    {
                      aps->getCcAlfAPSParam().reset();
                    }
                  }
                }
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF
                m_pcALF->setApsIdStart2( ALF_CTB_MAX_NUM_APS );
                for( int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++ )
                {
                  int psId = ( apsId << NUM_APS_TYPE_LEN ) + TALF_APS;
                  APS* aps = apsMap->getPS( psId );
                  if( aps )
                  {
                    // Check if this APS is currently the active one (used in current slice)
                    bool activeApsTAlf = false;
                    for (int i = 0; i < talfControl.apsIds.size(); i++)
                    {
                      activeApsTAlf |= (talfControl.enabledFlag && talfControl.apsIds[i] == aps->getAPSId());
                    }
                    if( !activeApsTAlf)
                    {
                      apsMap->clearChangedFlag( psId );
                      aps->getTAlfAPSParam().reset();
                    }
                  }
                }
    #endif
    
              }
            }
    
            // Assign tne correct APS to slice and emulate the setting of ALF start APS ID
            int changedApsId = -1;
            for( int apsId = ALF_CTB_MAX_NUM_APS - 1; apsId >= 0; apsId-- )
            {
              ParameterSetMap<APS>* apsMap = m_pcEncLib->getApsMap();
              int psId = ( apsId << NUM_APS_TYPE_LEN ) + ALF_APS;
              APS* aps = apsMap->getPS( psId );
              if( aps )
              {
                // In slice, replace the old APS (from decoder map) with the APS from encoder map due to later checks while bitstream writing
                if( pcSlice->getAlfAPSs() && pcSlice->getAlfAPSs()[apsId] )
                {
                  pcSlice->getAlfAPSs()[apsId] = aps;
                }
                if( apsMap->getChangedFlag( psId ) )
                  changedApsId = apsId;
              }
            }
            if( changedApsId >= 0 )
              m_pcALF->setApsIdStart( changedApsId );
    
    Luhang Xu's avatar
    Luhang Xu committed
    
    #if JVET_AK0065_TALF
            int changedApsId2 = -1;
            for( int apsId = ALF_CTB_MAX_NUM_APS - 1; apsId >= 0; apsId-- )
            {
              ParameterSetMap<APS>* apsMap = m_pcEncLib->getApsMap();
              int psId = ( apsId << NUM_APS_TYPE_LEN ) + TALF_APS;
              APS* aps = apsMap->getPS( psId );
              if( aps )
              {
                // In slice, replace the old APS (from decoder map) with the APS from encoder map due to later checks while bitstream writing
                if( pcSlice->getTAlfAPSs() && pcSlice->getTAlfAPSs()[apsId] )
                {
                  pcSlice->getTAlfAPSs()[apsId] = aps;
                }
                if (apsMap->getChangedFlag(psId))
                {
                  changedApsId2 = apsId;
                }
              }
            }
            if (changedApsId2 >= 0)
            {
              m_pcALF->setApsIdStart2(changedApsId2);
            }
    #endif
    
        pcSlice->freeScaledRefPicList( scaledRefPic );
    
    
        if( m_pcCfg->getUseAMaxBT() )
        {
          for( const CodingUnit *cu : pcPic->cs->cus )
          {
    
            {
              m_uiBlkSize[pcSlice->getDepth()] += cu->Y().area();
              m_uiNumBlk [pcSlice->getDepth()]++;
            }
          }
        }
    
        if( encPic || decPic )
        {
          pcSlice = pcPic->slices[0];
    
          /////////////////////////////////////////////////////////////////////////////////////////////////// File writing
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if EMBEDDED_APS
          m_aps.clear();
    #endif
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_Z0118_GDR // note : insert SPS/PPS at every GDR picture
    
    Seungwook Hong's avatar
    Seungwook Hong committed
          bool writePS = m_bSeqFirst || (m_pcCfg->getReWriteParamSets() && (pcSlice->isIRAP())) || pcSlice->isInterGDR();
    #else
    
          bool writePS = m_bSeqFirst || (m_pcCfg->getReWriteParamSets() && (pcSlice->isIRAP()));
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
          if (writePS)
          {
            m_pcEncLib->setParamSetChanged(pcSlice->getSPS()->getSPSId(), pcSlice->getPPS()->getPPSId());
          }
    
          int layerIdx = m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx( m_pcEncLib->getLayerId() );
    
          // it is assumed that layerIdx equal to 0 is always present
          m_audIrapOrGdrAuFlag = pcSlice->getPicHeader()->getGdrPicFlag() || (pcSlice->isIRAP() && !pcSlice->getPPS()->getMixedNaluTypesInPicFlag());
          if ((( m_pcEncLib->getVPS()->getMaxLayers() > 1 && m_audIrapOrGdrAuFlag) || m_pcCfg->getAccessUnitDelimiter()) && !layerIdx )
          {
            xWriteAccessUnitDelimiter(accessUnit, pcSlice);
          }
    
    
          // it is assumed that layerIdx equal to 0 is always present
    
    BDChoi's avatar
    BDChoi committed
          actualTotalBits += xWriteParameterSets(accessUnit, pcSlice, writePS, layerIdx);
    
          {
            // create prefix SEI messages at the beginning of the sequence
            CHECK(!(leadingSeiMessages.empty()), "Unspecified error");
            xCreateIRAPLeadingSEIMessages(leadingSeiMessages, pcSlice->getSPS(), pcSlice->getPPS());
    
            m_bSeqFirst = false;
          }
    
    
          //send LMCS APS when LMCSModel is updated. It can be updated even current slice does not enable reshaper.
          //For example, in RA, update is on intra slice, but intra slice may not use reshaper
    
          if (pcSlice->getSPS()->getUseLmcs())
    
          {
            //only 1 LMCS data for 1 picture
    
    Brian Heng's avatar
    Brian Heng committed
            int apsId = picHeader->getLmcsAPSId();
    
            ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
            APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
            bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR // note : insert APS at every GDR picture
            if (aps && apsId >= 0)
            {
              writeAPS |= pcSlice->isInterGDR();
            }
    #endif
    
    #if JVET_R0433
              aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400;
    #endif
    
              actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
    
              apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
              if (!pcSlice->isInterGDR())
              {
                CHECK(aps != picHeader->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP");
              }
    #else
    
    Brian Heng's avatar
    Brian Heng committed
              CHECK(aps != picHeader->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP");
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
          // only 1 SCALING LIST data for 1 picture
    
          if( pcSlice->getSPS()->getScalingListFlag() && ( m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ ) )
          {
    
    Brian Heng's avatar
    Brian Heng committed
            int apsId = picHeader->getScalingListAPSId();
    
            ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
            APS* aps = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
            bool writeAPS = aps && apsMap->getChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR // note : insert APS at every GDR picture
            if (aps && apsId >= 0)
            {
              writeAPS |= pcSlice->isInterGDR();
            }
    #endif
    
    #if JVET_R0433
              aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400;
    #endif
    
              actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
    
              apsMap->clearChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
              if (!pcSlice->isInterGDR())
              {
                CHECK(aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP");
              }
    #else
    
    Brian Heng's avatar
    Brian Heng committed
              CHECK( aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP" );
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
          if (pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag()))
    
            for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++)
    
            {
              ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
    
              APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
              bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
              if (!aps && pcSlice->getAlfAPSs() && pcSlice->getAlfAPSs()[apsId])
              {
                writeAPS = true;
                aps = pcSlice->getAlfAPSs()[apsId]; // use asp from slice header
    
                *apsMap->allocatePS((apsId << NUM_APS_TYPE_LEN) + ALF_APS) = *aps; //allocate and cpy
    
                m_pcALF->setApsIdStart( apsId );
              }
    
              else if (pcSlice->getTileGroupCcAlfCbEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCbApsId())
              {
                writeAPS = true;
                aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCbApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
              }
              else if (pcSlice->getTileGroupCcAlfCrEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCrApsId())
              {
                writeAPS = true;
                aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
              }
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR // note : insert APS at every GDR picture
              if (aps && apsId >= 0)
              {
                writeAPS |= (pcSlice->isInterGDR());
              }
    #endif
    
              if (writeAPS )
    
    #if JVET_R0433
                aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400;
    #endif
    
                actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
    
                apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
                if (!pcSlice->isInterGDR())
                {
                  CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP");
                }
    #else
    
                CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP");
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF  // Write TALF APS.
          const TAlfControl talfControl = pcSlice->getTileGroupTAlfControl();
          if (pcSlice->getSPS()->getUseTAlf() && talfControl.enabledFlag)
          {
            for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++)
            {
              ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
              APS *aps      = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + TALF_APS);
              bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + TALF_APS);
              if (!aps && pcSlice->getTAlfAPSs() && pcSlice->getTAlfAPSs()[apsId])
              {
                writeAPS = true;
                aps      = pcSlice->getTAlfAPSs()[apsId];                             // use asp from slice header
                *apsMap->allocatePS((apsId << NUM_APS_TYPE_LEN) + TALF_APS) = *aps;   // allocate and cpy
                m_pcALF->setApsIdStart2(apsId);
              }
    #if JVET_Z0118_GDR // note : insert APS at every GDR picture
              if (aps && apsId >= 0)
              {
                writeAPS |= (pcSlice->isInterGDR());
              }
    #endif
              if (writeAPS )
              {
    #if JVET_R0433
                aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400;
    #endif
                actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
                apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + TALF_APS);
              }
            }
          }
    #endif
    
          // reset presence of BP SEI indication
          m_bufferingPeriodSEIPresentInAU = false;
          // create prefix SEI associated with a picture
          xCreatePerPictureSEIMessages(iGOPid, leadingSeiMessages, nestedSeiMessages, pcSlice);
    
          // pcSlice is currently slice 0.
          std::size_t binCountsInNalUnits   = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10)
          std::size_t numBytesInVclNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10)
    
    #if JVET_Q0406_CABAC_ZERO
          std::size_t sumZeroWords          = 0; // sum of cabac_zero_word inserted per sub-picture
          std::vector<EncBitstreamParams> subPicStats (pcPic->cs->pps->getNumSubPics());
    #endif
    
          for(uint32_t sliceSegmentIdxCount = 0; sliceSegmentIdxCount < pcPic->cs->pps->getNumSlicesInPic(); sliceSegmentIdxCount++ )
    
          {
            pcSlice = pcPic->slices[sliceSegmentIdxCount];
            if(sliceSegmentIdxCount > 0 && pcSlice->getSliceType()!= I_SLICE)
            {
              pcSlice->checkColRefIdx(sliceSegmentIdxCount, pcPic);
            }
            m_pcSliceEncoder->setSliceSegmentIdx(sliceSegmentIdxCount);
    
    
    Hendry's avatar
    Hendry committed
            pcSlice->setRPL0(pcPic->slices[0]->getRPL0());
            pcSlice->setRPL1(pcPic->slices[0]->getRPL1());
            pcSlice->setRPL0idx(pcPic->slices[0]->getRPL0idx());
            pcSlice->setRPL1idx(pcPic->slices[0]->getRPL1idx());
    
            picHeader->setNoOutputBeforeRecoveryFlag( false );
    
    Brian Heng's avatar
    Brian Heng committed
            if (pcSlice->isIRAP())
            {
              if (pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && pcSlice->getNalUnitType() <= NAL_UNIT_CODED_SLICE_IDR_N_LP)
              {
    
                picHeader->setNoOutputBeforeRecoveryFlag( true );
    
    Brian Heng's avatar
    Brian Heng committed
              }
              //the inference for NoOutputPriorPicsFlag
              // KJS: This cannot happen at the encoder
    
              if( !m_bFirst && ( pcSlice->isIRAP() || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR ) && picHeader->getNoOutputBeforeRecoveryFlag() )
    
    Brian Heng's avatar
    Brian Heng committed
              {
                if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR)
                {
    
    bdchoi's avatar
    bdchoi committed
    #if JVET_S0193_NO_OUTPUT_PRIOR_PIC
                  pcSlice->setNoOutputOfPriorPicsFlag(true);
    #else
    
    Brian Heng's avatar
    Brian Heng committed
                  picHeader->setNoOutputOfPriorPicsFlag(true);
    
    bdchoi's avatar
    bdchoi committed
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
                }
              }
            }
    
            // code picture header before first slice
    
            if(sliceSegmentIdxCount == 0)
    
    Brian Heng's avatar
    Brian Heng committed
            {
              // code RPL in picture header or slice headers
              if( !m_pcCfg->getSliceLevelRpl() && (!pcSlice->getIdrPicFlag() || pcSlice->getSPS()->getIDRRefParamListPresent()) )
              {
                picHeader->setRPL0idx(pcSlice->getRPL0idx());
                picHeader->setRPL1idx(pcSlice->getRPL1idx());
                picHeader->setRPL0(pcSlice->getRPL0());
                picHeader->setRPL1(pcSlice->getRPL1());
                *picHeader->getLocalRPL0() = *pcSlice->getLocalRPL0();
                *picHeader->getLocalRPL1() = *pcSlice->getLocalRPL1();
              }
    
    Brian Heng's avatar
    Brian Heng committed
              // code DBLK in picture header or slice headers
              if( !m_pcCfg->getSliceLevelDblk() )
              {
                picHeader->setDeblockingFilterOverrideFlag   ( pcSlice->getDeblockingFilterOverrideFlag()   );
    
                picHeader->setDeblockingFilterDisable        ( pcSlice->getDeblockingFilterDisable()        );
                picHeader->setDeblockingFilterBetaOffsetDiv2 ( pcSlice->getDeblockingFilterBetaOffsetDiv2() );
    
    Brian Heng's avatar
    Brian Heng committed
                picHeader->setDeblockingFilterTcOffsetDiv2   ( pcSlice->getDeblockingFilterTcOffsetDiv2()   );
    
                picHeader->setDeblockingFilterCbBetaOffsetDiv2( pcSlice->getDeblockingFilterCbBetaOffsetDiv2() );
                picHeader->setDeblockingFilterCbTcOffsetDiv2  ( pcSlice->getDeblockingFilterCbTcOffsetDiv2() );
                picHeader->setDeblockingFilterCrBetaOffsetDiv2( pcSlice->getDeblockingFilterCrBetaOffsetDiv2() );
                picHeader->setDeblockingFilterCrTcOffsetDiv2  ( pcSlice->getDeblockingFilterCrTcOffsetDiv2() );
    
    Hendry's avatar
    Hendry committed
    
              if (!m_pcCfg->getSliceLevelDeltaQp())
              {
                picHeader->setQpDelta(pcSlice->getSliceQp() - (pcSlice->getPPS()->getPicInitQPMinus26() + 26));
              }
    
    
    Brian Heng's avatar
    Brian Heng committed
              // code SAO parameters in picture header or slice headers
              if( !m_pcCfg->getSliceLevelSao() )
              {
                picHeader->setSaoEnabledFlag(CHANNEL_TYPE_LUMA,   pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_LUMA  ));
                picHeader->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_CHROMA));
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #if JVET_W0066_CCSAO
                picHeader->setCcSaoEnabledFlag(COMPONENT_Y,  pcSlice->getCcSaoEnabledFlag(COMPONENT_Y));
                picHeader->setCcSaoEnabledFlag(COMPONENT_Cb, pcSlice->getCcSaoEnabledFlag(COMPONENT_Cb));
                picHeader->setCcSaoEnabledFlag(COMPONENT_Cr, pcSlice->getCcSaoEnabledFlag(COMPONENT_Cr));
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
              // code ALF parameters in picture header or slice headers
              if( !m_pcCfg->getSliceLevelAlf() )
              {
                picHeader->setAlfEnabledFlag(COMPONENT_Y,  pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y ) );
                picHeader->setAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) );
    
                picHeader->setAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ALF_IMPROVEMENT
    
    #if JVET_AG0157_ALF_CHROMA_FIXED_FILTER
                picHeader->setAlfFixedFilterSetIdx(COMPONENT_Y, pcSlice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Y));
                picHeader->setAlfFixedFilterSetIdx(COMPONENT_Cb, pcSlice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Cb));
                picHeader->setAlfFixedFilterSetIdx(COMPONENT_Cr, pcSlice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Cr));
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                picHeader->setAlfFixedFilterSetIdx(pcSlice->getTileGroupAlfFixedFilterSetIdx());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
                picHeader->setNumAlfAps(pcSlice->getTileGroupNumAps());
                picHeader->setAlfAPSs(pcSlice->getTileGroupApsIdLuma());
                picHeader->setAlfApsIdChroma(pcSlice->getTileGroupApsIdChroma());
    
                picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupCcAlfCbEnabledFlag());
                picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupCcAlfCrEnabledFlag());
                picHeader->setCcAlfCbApsId(pcSlice->getTileGroupCcAlfCbApsId());
                picHeader->setCcAlfCrApsId(pcSlice->getTileGroupCcAlfCrApsId());
    
    Luhang Xu's avatar
    Luhang Xu committed
    #if JVET_AK0065_TALF
                picHeader->setTAlfControl(pcSlice->getTileGroupTAlfControl());
    #endif
    
    Hendry's avatar
    Hendry committed
    
              // code WP parameters in picture header or slice headers
              if (!m_pcCfg->getSliceLevelWp())
              {
                picHeader->setWpScaling(pcSlice->getWpScalingAll());
                picHeader->setNumL0Weights(pcSlice->getNumRefIdx(REF_PIC_LIST_0));
                picHeader->setNumL0Weights(pcSlice->getNumRefIdx(REF_PIC_LIST_1));
              }
    
              picHeader->setDisFracMBVD(pcSlice->getPicHeader()->getDisFracMBVD());
    
    
    Brian Heng's avatar
    Brian Heng committed
              pcPic->cs->picHeader->setPic(pcPic);
              pcPic->cs->picHeader->setValid();
    
              if (pcPic->cs->pps->getNumSlicesInPic() > 1 || !m_pcCfg->getEnablePictureHeaderInSliceHeader())
    
                pcSlice->setPictureHeaderInSliceHeader(false);
    
                actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader);
              }
    
    bdchoi's avatar
    bdchoi committed
              if (pcSlice->getSPS()->getProfileTierLevel()->getConstraintInfo()->getPicHeaderInSliceHeaderConstraintFlag())
              {
                CHECK(pcSlice->getPictureHeaderInSliceHeader() == false, "PH shall be present in SH, when pic_header_in_slice_header_constraint_flag is equal to 1");
              }
    
    Brian Heng's avatar
    Brian Heng committed
            }
            pcSlice->setPicHeader( pcPic->cs->picHeader );
    
            pcSlice->setNalUnitLayerId( m_pcEncLib->getLayerId() );
    
            for ( uint32_t ui = 0 ; ui < numSubstreams; ui++ )
            {
              substreamsOut[ui].clear();
            }
    
            /* start slice NALunit */
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            OutputNALUnit nalu( pcSlice->getNalUnitType(), m_pcEncLib->getLayerId(), pcSlice->getTLayer() );
    
            m_HLSWriter->setBitstream( &nalu.m_Bitstream );
    
    
            tmpBitsBeforeWriting = m_HLSWriter->getNumberOfWrittenBits();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
    #if EMBEDDED_APS
            m_HLSWriter->codeSliceHeader( m_aps, pcSlice );
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
            actualHeadBits += ( m_HLSWriter->getNumberOfWrittenBits() - tmpBitsBeforeWriting );
    
            pcSlice->setFinalized(true);
    
    
    Hendry's avatar
    Hendry committed
            pcSlice->resetNumberOfSubstream( );
            pcSlice->setNumSubstream( pcSlice->getSPS(), pcSlice->getPPS() );
    
    #if JVET_Q0406_CABAC_ZERO
            const int subpicIdx = pcPic->cs->pps->getSubPicIdxFromSubPicId(pcSlice->getSliceSubPicId());
    #endif
    
            {
              uint32_t numBinsCoded = 0;
              m_pcSliceEncoder->encodeSlice(pcPic, &(substreamsOut[0]), numBinsCoded);
              binCountsInNalUnits+=numBinsCoded;
    
    #if JVET_Q0406_CABAC_ZERO
              subPicStats[subpicIdx].numBinsWritten += numBinsCoded;
    #endif
    
            }
            {
              // Construct the final bitstream by concatenating substreams.
              // The final bitstream is either nalu.m_Bitstream or pcBitstreamRedirect;
              // Complete the slice header info.
              m_HLSWriter->setBitstream( &nalu.m_Bitstream );
              m_HLSWriter->codeTilesWPPEntryPoint( pcSlice );
    
              // Append substreams...
              OutputBitstream *pcOut = pcBitstreamRedirect;
    
    Hendry's avatar
    Hendry committed
              const int numSubstreamsToCode = pcSlice->getNumberOfSubstream() + 1;
    
    
              for ( uint32_t ui = 0 ; ui < numSubstreamsToCode; ui++ )
              {
    
                pcOut->addSubstream(&(substreamsOut[ui]));
    
              }
            }
    
            // If current NALU is the first NALU of slice (containing slice header) and more NALUs exist (due to multiple dependent slices) then buffer it.
            // If current NALU is the last NALU of slice and a NALU was buffered, then (a) Write current NALU (b) Update an write buffered NALU at approproate location in NALU list.
            bool bNALUAlignedWrittenToList    = false; // used to ensure current NALU is not written more than once to the NALU list.
            xAttachSliceDataToNalUnit(nalu, pcBitstreamRedirect);
            accessUnit.push_back(new NALUnitEBSP(nalu));
            actualTotalBits += uint32_t(accessUnit.back()->m_nalUnitData.str().size()) * 8;
            numBytesInVclNalUnits += (std::size_t)(accessUnit.back()->m_nalUnitData.str().size());
    
    #if JVET_Q0406_CABAC_ZERO
            subPicStats[subpicIdx].numBytesInVclNalUnits += (std::size_t)(accessUnit.back()->m_nalUnitData.str().size());
    #endif
    
            bNALUAlignedWrittenToList = true;
    
            if (!bNALUAlignedWrittenToList)
            {
              nalu.m_Bitstream.writeAlignZero();
              accessUnit.push_back(new NALUnitEBSP(nalu));
            }
    
    
            if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) &&
    
            ((pcSlice->getSPS()->getGeneralHrdParameters()->getGeneralNalHrdParametersPresentFlag())
              || (pcSlice->getSPS()->getGeneralHrdParameters()->getGeneralVclHrdParametersPresentFlag())) &&
              (pcSlice->getSPS()->getGeneralHrdParameters()->getGeneralDecodingUnitHrdParamsPresentFlag()))
    
              uint32_t numRBSPBytes = 0;
              for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++)
              {
                numRBSPBytes += uint32_t((*it)->m_nalUnitData.str().size());
                numNalus ++;
              }
              duData.push_back(DUData());
              duData.back().accumBitsDU = ( numRBSPBytes << 3 );
              duData.back().accumNalsDU = numNalus;
            }
    
    #if JVET_Q0406_CABAC_ZERO
            if (pcSlice->isLastSliceInSubpic())
            {
              // Check picture level encoding constraints/requirements
              ProfileLevelTierFeatures profileLevelTierFeatures;
              profileLevelTierFeatures.extractPTLInformation(*(pcSlice->getSPS()));
              sumZeroWords += cabac_zero_word_padding(pcSlice, pcPic, subPicStats[subpicIdx].numBinsWritten, subPicStats[subpicIdx].numBytesInVclNalUnits, 0,
                                                      accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
            }
    #endif
    
          {
            // Check picture level encoding constraints/requirements
            ProfileLevelTierFeatures profileLevelTierFeatures;
            profileLevelTierFeatures.extractPTLInformation(*(pcSlice->getSPS()));
            validateMinCrRequirements(profileLevelTierFeatures, numBytesInVclNalUnits, pcPic, m_pcCfg);
            // cabac_zero_words processing
    
    #if JVET_Q0406_CABAC_ZERO
            cabac_zero_word_padding(pcSlice, pcPic, binCountsInNalUnits, numBytesInVclNalUnits, sumZeroWords, accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
    #else
    
            cabac_zero_word_padding(pcSlice, pcPic, binCountsInNalUnits, numBytesInVclNalUnits, accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
          pcPic->setCleanDirty(false);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
          pcPic->copyCleanCurPicture();      
    
          //-- For time output for each slice
          auto elapsed = std::chrono::steady_clock::now() - beforeTime;
    
          auto encTime = std::chrono::duration_cast<std::chrono::milliseconds>( elapsed ).count()/1000.0;
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    
    #if JVET_Z0118_GDR
          // note : generate hash sei only for non-gdr pictures
          bool genHash = !(m_pcCfg->getGdrNoHash() && pcSlice->getPicHeader()->getInGdrInterval());
          if (m_pcCfg->getDecodedPictureHashSEIType() != HASHTYPE_NONE && genHash)
    #else
    
          if (m_pcCfg->getDecodedPictureHashSEIType()!=HASHTYPE_NONE)
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
          {
            SEIDecodedPictureHash *decodedPictureHashSei = new SEIDecodedPictureHash();
            PelUnitBuf recoBuf = pcPic->cs->getRecoBuf();
            m_seiEncoder.initDecodedPictureHashSEI(decodedPictureHashSei, recoBuf, digestStr, pcSlice->getSPS()->getBitDepths());
            trailingSeiMessages.push_back(decodedPictureHashSei);
          }
    
    #if JVET_R0294_SUBPIC_HASH
          // create per-subpicture decoded picture hash SEI messages, if more than one subpicture is enabled
          const PPS* pps = pcPic->cs->pps;
          const int numSubpics = pps->getNumSubPics();
          std::string subPicDigest;
          if (numSubpics > 1 && m_pcCfg->getSubpicDecodedPictureHashType() != HASHTYPE_NONE )
          {
            for (int subPicIdx = 0; subPicIdx < numSubpics; subPicIdx++)
            {
              const SubPic& subpic = pps->getSubPic(subPicIdx);
              const UnitArea area = UnitArea(pcSlice->getSPS()->getChromaFormatIdc(), Area(subpic.getSubPicLeft(), subpic.getSubPicTop(), subpic.getSubPicWidthInLumaSample(), subpic.getSubPicHeightInLumaSample()));
              PelUnitBuf recoBuf = pcPic->cs->getRecoBuf(area);
              SEIDecodedPictureHash *decodedPictureHashSEI = new SEIDecodedPictureHash();
              m_seiEncoder.initDecodedPictureHashSEI(decodedPictureHashSEI, recoBuf, subPicDigest, pcSlice->getSPS()->getBitDepths());
              SEIMessages nestedSEI;
              nestedSEI.push_back(decodedPictureHashSEI);
              const std::vector<uint16_t> subPicIds = { (uint16_t)subpic.getSubPicID() };
              std::vector<int> targetOLS;
              std::vector<int> targetLayers = {pcPic->layerId};
              xCreateScalableNestingSEI(trailingSeiMessages, nestedSEI, targetOLS, targetLayers, subPicIds);
            }
          }
    #endif
    
    #if MSSIM_UNIFORM_METRICS_LOG
          xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, printMSSSIM,&PSNR_Y, isEncodeLtRef );
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, &PSNR_Y, isEncodeLtRef );
    
          xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer());
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
          if (!(m_pcCfg->getGdrNoHash() && pcSlice->getPicHeader()->getInGdrInterval()))
          {
              printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
          }
    #else
    
          printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    
          if ( m_pcCfg->getUseRateCtrl() )
          {
            double avgQP     = m_pcRateCtrl->getRCPic()->calAverageQP();
            double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda();
            if ( avgLambda < 0.0 )
            {
              avgLambda = lambda;
            }
    
    
            m_pcRateCtrl->getRCPic()->updateAfterPicture( actualHeadBits, actualTotalBits, avgQP, avgLambda, pcSlice->isIRAP());
    
            m_pcRateCtrl->getRCPic()->addToPictureLsit( m_pcRateCtrl->getPicList() );
    
            m_pcRateCtrl->getRCSeq()->updateAfterPic( actualTotalBits );
    
            if ( !pcSlice->isIRAP() )
    
            {
              m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualTotalBits );
            }
            else    // for intra picture, the estimated bits are used to update the current status in the GOP
            {
              m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits );
            }
      #if U0132_TARGET_BITS_SATURATION
            if (m_pcRateCtrl->getCpbSaturationEnabled())
            {
              m_pcRateCtrl->updateCpbState(actualTotalBits);
              msg( NOTICE, " [CPB %6d bits]", m_pcRateCtrl->getCpbState() );
            }
      #endif
          }
    
          xCreateFrameFieldInfoSEI( leadingSeiMessages, pcSlice, isField );
    
          xCreatePictureTimingSEI( m_pcCfg->getEfficientFieldIRAPEnabled() ? effFieldIRAPMap.GetIRAPGOPid() : 0, leadingSeiMessages, nestedSeiMessages, duInfoSeiMessages, pcSlice, isField, duData );
    
    
          if (m_pcCfg->getScalableNestingSEIEnabled())
    
            const SPS* sps = pcSlice->getSPS();
            const PPS* pps = pcSlice->getPPS();
    
            std::vector<uint16_t> subpicIDs;
            if (sps->getSubPicInfoPresentFlag())
            {