Skip to content
Snippets Groups Projects
EncGOP.cpp 176 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* The copyright in this software is being made available under the BSD
     * License, included below. This software may be subject to other third party
     * and contributor rights, including patent rights, and no such rights are
     * granted under this license.
     *
    
     * Copyright (c) 2010-2019, ITU/ISO/IEC
    
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *  * Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
     *    be used to endorse or promote products derived from this software without
     *    specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     * THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /** \file     EncGOP.cpp
        \brief    GOP encoder class
    */
    
    #include <list>
    #include <algorithm>
    #include <functional>
    
    #include "EncLib.h"
    #include "EncGOP.h"
    #include "Analyze.h"
    #include "libmd5/MD5.h"
    #include "CommonLib/SEI.h"
    #include "CommonLib/NAL.h"
    #include "NALwrite.h"
    
    #include <math.h>
    #include <deque>
    #include <chrono>
    #include <cinttypes>
    
    #include "CommonLib/UnitTools.h"
    #include "CommonLib/dtrace_codingstruct.h"
    #include "CommonLib/dtrace_buffer.h"
    
    #include "DecoderLib/DecLib.h"
    
    #define ENCODE_SUB_SET 0
    
    using namespace std;
    
    //! \ingroup EncoderLib
    //! \{
    
    // ====================================================================================================================
    // Constructor / destructor / initialization / destroy
    // ====================================================================================================================
    int getLSB(int poc, int maxLSB)
    {
      if (poc >= 0)
      {
        return poc % maxLSB;
      }
      else
      {
        return (maxLSB - ((-poc) % maxLSB)) % maxLSB;
      }
    }
    
    
    EncGOP::EncGOP()
    {
      m_iLastIDR            = 0;
      m_iGopSize            = 0;
      m_iNumPicCoded        = 0; //Niko
      m_bFirst              = true;
      m_iLastRecoveryPicPOC = 0;
    
      m_latestDRAPPOC       = MAX_INT;
    
      m_lastRasPoc          = MAX_INT;
    
      m_pcCfg               = NULL;
      m_pcSliceEncoder      = NULL;
      m_pcListPic           = NULL;
      m_HLSWriter           = NULL;
      m_bSeqFirst           = true;
    
      m_bRefreshPending     = 0;
      m_pocCRA              = 0;
      m_numLongTermRefPicSPS = 0;
      ::memset(m_ltRefPicPocLsbSps, 0, sizeof(m_ltRefPicPocLsbSps));
      ::memset(m_ltRefPicUsedByCurrPicFlag, 0, sizeof(m_ltRefPicUsedByCurrPicFlag));
      m_lastBPSEI           = 0;
      m_bufferingPeriodSEIPresentInAU = false;
      m_associatedIRAPType  = NAL_UNIT_CODED_SLICE_IDR_N_LP;
      m_associatedIRAPPOC   = 0;
    #if W0038_DB_OPT
      m_pcDeblockingTempPicYuv = NULL;
    #endif
    
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
    
      m_ppcFrameOrg             = nullptr;
      m_ppcFrameRec             = nullptr;
    
      m_pcConvertFormat         = nullptr;
      m_pcConvertIQuantize      = nullptr;
      m_pcColorTransform        = nullptr;
      m_pcDistortionDeltaE      = nullptr;
      m_pcTransferFct           = nullptr;
    
      m_pcColorTransformParams  = nullptr;
      m_pcFrameFormat           = nullptr;
    
      m_metricTime = std::chrono::milliseconds(0);
    #endif
    
      m_bgPOC = -1;
      m_picBg = NULL;
      m_picOrig = NULL;
      m_isEncodedLTRef = false;
      m_isUseLTRef = false;
      m_isPrepareLTRef = true;
      m_lastLTRefPoc = 0;
    
    }
    
    EncGOP::~EncGOP()
    {
      if( !m_pcCfg->getDecodeBitstream(0).empty() || !m_pcCfg->getDecodeBitstream(1).empty() )
      {
        // reset potential decoder resources
        tryDecodePicture( NULL, 0, std::string("") );
      }
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      delete [] m_ppcFrameOrg;
      delete [] m_ppcFrameRec;
    
      m_ppcFrameOrg = m_ppcFrameRec = nullptr;
    
      delete m_pcConvertFormat;
      delete m_pcConvertIQuantize;
      delete m_pcColorTransform;
      delete m_pcDistortionDeltaE;
      delete m_pcTransferFct;
      delete m_pcColorTransformParams;
      delete m_pcFrameFormat;
    
      m_pcConvertFormat         = nullptr;
      m_pcConvertIQuantize      = nullptr;
      m_pcColorTransform        = nullptr;
      m_pcDistortionDeltaE      = nullptr;
      m_pcTransferFct           = nullptr;
      m_pcColorTransformParams  = nullptr;
      m_pcFrameFormat           = nullptr;
    
    }
    
    /** Create list to contain pointers to CTU start addresses of slice.
     */
    void  EncGOP::create()
    {
      m_bLongtermTestPictureHasBeenCoded = 0;
      m_bLongtermTestPictureHasBeenCoded2 = 0;
    }
    
    void  EncGOP::destroy()
    {
    #if W0038_DB_OPT
      if (m_pcDeblockingTempPicYuv)
      {
        m_pcDeblockingTempPicYuv->destroy();
        delete m_pcDeblockingTempPicYuv;
        m_pcDeblockingTempPicYuv = NULL;
      }
    #endif
    
      if (m_picBg)
      {
        m_picBg->destroy();
        delete m_picBg;
        m_picBg = NULL;
      }
      if (m_picOrig)
      {
        m_picOrig->destroy();
        delete m_picOrig;
        m_picOrig = NULL;
      }
    
    }
    
    void EncGOP::init ( EncLib* pcEncLib )
    {
      m_pcEncLib     = pcEncLib;
      m_pcCfg                = pcEncLib;
      m_seiEncoder.init(m_pcCfg, pcEncLib, this);
      m_pcSliceEncoder       = pcEncLib->getSliceEncoder();
      m_pcListPic            = pcEncLib->getListPic();
      m_HLSWriter            = pcEncLib->getHLSWriter();
      m_pcLoopFilter         = pcEncLib->getLoopFilter();
      m_pcSAO                = pcEncLib->getSAO();
      m_pcALF = pcEncLib->getALF();
      m_pcRateCtrl           = pcEncLib->getRateCtrl();
      m_lastBPSEI          = 0;
      m_totalCoded         = 0;
    
    #if JVET_N0353_INDEP_BUFF_TIME_SEI
      m_HRD                = pcEncLib->getHRD();
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
      if (m_pcCfg->getReshaper())
    
      {
        pcEncLib->getRdCost()->setReshapeInfo(m_pcCfg->getReshapeSignalType(), m_pcCfg->getBitDepth(CHANNEL_TYPE_LUMA));
        pcEncLib->getRdCost()->initLumaLevelToWeightTableReshape();
      }
      else if (m_pcCfg->getLumaLevelToDeltaQPMapping().mode)
      {
    
    Taoran Lu's avatar
    Taoran Lu committed
        pcEncLib->getRdCost()->setReshapeInfo(RESHAPE_SIGNAL_PQ, m_pcCfg->getBitDepth(CHANNEL_TYPE_LUMA));
    
        pcEncLib->getRdCost()->initLumaLevelToWeightTableReshape();
    
      }
      pcEncLib->getALF()->getLumaLevelWeightTable() = pcEncLib->getRdCost()->getLumaLevelWeightTable();
    
    Taoran Lu's avatar
    Taoran Lu committed
      int alfWSSD = 0;
      if (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ )
      {
        alfWSSD = 1;
      }
      pcEncLib->getALF()->setAlfWSSD(alfWSSD);
    
    Taoran Lu's avatar
    Taoran Lu committed
    #endif
      m_pcReshaper = pcEncLib->getReshaper();
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      const bool calculateHdrMetrics = m_pcEncLib->getCalcluateHdrMetrics();
    
      if(calculateHdrMetrics)
      {
        //allocate frame buffers and initialize class members
        int chainNumber = 5;
    
        m_ppcFrameOrg = new hdrtoolslib::Frame* [chainNumber];
        m_ppcFrameRec = new hdrtoolslib::Frame* [chainNumber];
    
        double* whitePointDeltaE = new double[hdrtoolslib::NB_REF_WHITE];
        for (int i=0; i<hdrtoolslib::NB_REF_WHITE; i++)
        {
          whitePointDeltaE[i] = m_pcCfg->getWhitePointDeltaE(i);
        }
    
        double maxSampleValue                       = m_pcCfg->getMaxSampleValue();
        hdrtoolslib::SampleRange sampleRange        = m_pcCfg->getSampleRange();
        hdrtoolslib::ChromaFormat chFmt             = hdrtoolslib::ChromaFormat(m_pcCfg->getChromaFormatIdc());
        int bitDepth = m_pcCfg->getBitDepth(CHANNEL_TYPE_LUMA);
        hdrtoolslib::ColorPrimaries colorPrimaries  = m_pcCfg->getColorPrimaries();
        bool enableTFunctionLUT                     = m_pcCfg->getEnableTFunctionLUT();
        hdrtoolslib::ChromaLocation* chromaLocation = new hdrtoolslib::ChromaLocation[2];
        for (int i=0; i<2; i++)
        {
          chromaLocation[i] = m_pcCfg->getChromaLocation(i);
        }
        int chromaUpFilter  = m_pcCfg->getChromaUPFilter();
        int cropOffsetLeft   = m_pcCfg->getCropOffsetLeft();
        int cropOffsetTop    = m_pcCfg->getCropOffsetTop();
        int cropOffsetRight  = m_pcCfg->getCropOffsetRight();
        int cropOffsetBottom = m_pcCfg->getCropOffsetBottom();
    
        int width  = m_pcCfg->getSourceWidth() - cropOffsetLeft + cropOffsetRight;
        int height = m_pcCfg->getSourceHeight() - cropOffsetTop  + cropOffsetBottom;
    
        m_ppcFrameOrg[0] = new hdrtoolslib::Frame(width, height, false, hdrtoolslib::CM_YCbCr, colorPrimaries, chFmt, sampleRange, bitDepth, false, hdrtoolslib::TF_PQ, 0);
        m_ppcFrameRec[0] = new hdrtoolslib::Frame(width, height, false, hdrtoolslib::CM_YCbCr, colorPrimaries, chFmt, sampleRange, bitDepth, false, hdrtoolslib::TF_PQ, 0);
    
        m_ppcFrameOrg[1] = new hdrtoolslib::Frame(m_ppcFrameOrg[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameOrg[0]->m_height[hdrtoolslib::Y_COMP], false, hdrtoolslib::CM_YCbCr, colorPrimaries, hdrtoolslib::CF_444, sampleRange, bitDepth, false, hdrtoolslib::TF_PQ, 0);
        m_ppcFrameRec[1] = new hdrtoolslib::Frame(m_ppcFrameRec[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameRec[0]->m_height[hdrtoolslib::Y_COMP], false, hdrtoolslib::CM_YCbCr, colorPrimaries, hdrtoolslib::CF_444, sampleRange, bitDepth, false, hdrtoolslib::TF_PQ, 0);                                // 420 to 444 conversion
    
        m_ppcFrameOrg[2] =  new hdrtoolslib::Frame(m_ppcFrameOrg[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameOrg[0]->m_height[hdrtoolslib::Y_COMP], true, hdrtoolslib::CM_YCbCr, colorPrimaries, hdrtoolslib::CF_444, hdrtoolslib::SR_UNKNOWN, 32, false, hdrtoolslib::TF_PQ, 0);
        m_ppcFrameRec[2] =  new hdrtoolslib::Frame(m_ppcFrameRec[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameRec[0]->m_height[hdrtoolslib::Y_COMP], true, hdrtoolslib::CM_YCbCr, colorPrimaries, hdrtoolslib::CF_444, hdrtoolslib::SR_UNKNOWN, 32, false, hdrtoolslib::TF_PQ, 0);                                // 444 to Float conversion
    
        m_ppcFrameOrg[3] = new hdrtoolslib::Frame(m_ppcFrameOrg[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameOrg[0]->m_height[hdrtoolslib::Y_COMP], true, hdrtoolslib::CM_RGB, hdrtoolslib::CP_2020, hdrtoolslib::CF_444, hdrtoolslib::SR_UNKNOWN, 32, false, hdrtoolslib::TF_PQ, 0);
        m_ppcFrameRec[3] = new hdrtoolslib::Frame(m_ppcFrameRec[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameRec[0]->m_height[hdrtoolslib::Y_COMP], true, hdrtoolslib::CM_RGB, hdrtoolslib::CP_2020, hdrtoolslib::CF_444, hdrtoolslib::SR_UNKNOWN, 32, false, hdrtoolslib::TF_PQ, 0);                                // YCbCr to RGB conversion
    
        m_ppcFrameOrg[4] = new hdrtoolslib::Frame(m_ppcFrameOrg[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameOrg[0]->m_height[hdrtoolslib::Y_COMP], true, hdrtoolslib::CM_RGB, hdrtoolslib::CP_2020, hdrtoolslib::CF_444, hdrtoolslib::SR_UNKNOWN, 32, false, hdrtoolslib::TF_NULL, 0);
        m_ppcFrameRec[4] = new hdrtoolslib::Frame(m_ppcFrameRec[0]->m_width[hdrtoolslib::Y_COMP], m_ppcFrameRec[0]->m_height[hdrtoolslib::Y_COMP], true, hdrtoolslib::CM_RGB, hdrtoolslib::CP_2020, hdrtoolslib::CF_444, hdrtoolslib::SR_UNKNOWN, 32, false, hdrtoolslib::TF_NULL, 0);                                // Inverse Transfer Function
    
        m_pcFrameFormat                   = new hdrtoolslib::FrameFormat();
        m_pcFrameFormat->m_isFloat        = true;
        m_pcFrameFormat->m_chromaFormat   = hdrtoolslib::CF_UNKNOWN;
        m_pcFrameFormat->m_colorSpace     = hdrtoolslib::CM_RGB;
        m_pcFrameFormat->m_colorPrimaries = hdrtoolslib::CP_2020;
        m_pcFrameFormat->m_sampleRange    = hdrtoolslib::SR_UNKNOWN;
    
        m_pcConvertFormat     = hdrtoolslib::ConvertColorFormat::create(width, height, chFmt, hdrtoolslib::CF_444, chromaUpFilter, chromaLocation, chromaLocation);
        m_pcConvertIQuantize  = hdrtoolslib::Convert::create(&m_ppcFrameOrg[1]->m_format, &m_ppcFrameOrg[2]->m_format);
        m_pcColorTransform    = hdrtoolslib::ColorTransform::create(m_ppcFrameOrg[2]->m_colorSpace, m_ppcFrameOrg[2]->m_colorPrimaries, m_ppcFrameOrg[3]->m_colorSpace, m_ppcFrameOrg[3]->m_colorPrimaries, true, 1);
        m_pcDistortionDeltaE  = new hdrtoolslib::DistortionMetricDeltaE(m_pcFrameFormat, false, maxSampleValue, whitePointDeltaE, 1);
        m_pcTransferFct       = hdrtoolslib::TransferFunction::create(hdrtoolslib::TF_PQ, true, (float) maxSampleValue, 0, 0.0, 1.0, enableTFunctionLUT);
    
    }
    
    int EncGOP::xWriteVPS (AccessUnit &accessUnit, const VPS *vps)
    {
      OutputNALUnit nalu(NAL_UNIT_VPS);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
      m_HLSWriter->codeVPS( vps );
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    
    int EncGOP::xWriteDPS (AccessUnit &accessUnit, const DPS *dps)
    {
      if (dps->getDecodingParameterSetId() !=0)
      {
        OutputNALUnit nalu(NAL_UNIT_DPS);
        m_HLSWriter->setBitstream( &nalu.m_Bitstream );
        m_HLSWriter->codeDPS( dps );
        accessUnit.push_back(new NALUnitEBSP(nalu));
        return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
      }
      else
      {
        return 0;
      }
    }
    
    
    int EncGOP::xWriteSPS (AccessUnit &accessUnit, const SPS *sps)
    {
      OutputNALUnit nalu(NAL_UNIT_SPS);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
      m_HLSWriter->codeSPS( sps );
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    
    }
    
    
    #if JVET_O1136_TS_BDPCM_SIGNALLING
    int EncGOP::xWritePPS (AccessUnit &accessUnit, const PPS *pps, const SPS *sps)
    #else
    
    int EncGOP::xWritePPS (AccessUnit &accessUnit, const PPS *pps)
    
    {
      OutputNALUnit nalu(NAL_UNIT_PPS);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
    
    #if JVET_O1136_TS_BDPCM_SIGNALLING
      m_HLSWriter->codePPS( pps, sps );
    #else
    
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    
    Hendry's avatar
    Hendry committed
    int EncGOP::xWriteAPS(AccessUnit &accessUnit, APS *aps)
    {
      OutputNALUnit nalu(NAL_UNIT_APS);
      m_HLSWriter->setBitstream(&nalu.m_Bitstream);
      m_HLSWriter->codeAPS(aps);
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    
    int EncGOP::xWriteParameterSets (AccessUnit &accessUnit, Slice *slice, const bool bSeqFirst)
    {
      int actualTotalBits = 0;
    
      if (bSeqFirst)
      {
        actualTotalBits += xWriteVPS(accessUnit, m_pcEncLib->getVPS());
      }
    
      if (bSeqFirst)
      {
        actualTotalBits += xWriteDPS(accessUnit, m_pcEncLib->getDPS());
      }
    
    
      if (m_pcEncLib->SPSNeedsWriting(slice->getSPS()->getSPSId())) // Note this assumes that all changes to the SPS are made at the EncLib level prior to picture creation (EncLib::xGetNewPicBuffer).
      {
        CHECK(!(bSeqFirst), "Unspecified error"); // Implementations that use more than 1 SPS need to be aware of activation issues.
        actualTotalBits += xWriteSPS(accessUnit, slice->getSPS());
      }
      if (m_pcEncLib->PPSNeedsWriting(slice->getPPS()->getPPSId())) // Note this assumes that all changes to the PPS are made at the EncLib level prior to picture creation (EncLib::xGetNewPicBuffer).
      {
    
    #if JVET_O1136_TS_BDPCM_SIGNALLING
        actualTotalBits += xWritePPS(accessUnit, slice->getPPS(), slice->getSPS());
    #else
    
        actualTotalBits += xWritePPS(accessUnit, slice->getPPS());
    
      }
    
      return actualTotalBits;
    }
    
    void EncGOP::xWriteAccessUnitDelimiter (AccessUnit &accessUnit, Slice *slice)
    {
      AUDWriter audWriter;
      OutputNALUnit nalu(NAL_UNIT_ACCESS_UNIT_DELIMITER);
    
      int picType = slice->isIntra() ? 0 : (slice->isInterP() ? 1 : 2);
    
      audWriter.codeAUD(nalu.m_Bitstream, picType);
      accessUnit.push_front(new NALUnitEBSP(nalu));
    }
    
    // write SEI list into one NAL unit and add it to the Access unit at auPos
    void EncGOP::xWriteSEI (NalUnitType naluType, SEIMessages& seiMessages, AccessUnit &accessUnit, AccessUnit::iterator &auPos, int temporalId, const SPS *sps)
    {
      // don't do anything, if we get an empty list
      if (seiMessages.empty())
      {
        return;
      }
      OutputNALUnit nalu(naluType, temporalId);
    
    #if JVET_N0353_INDEP_BUFF_TIME_SEI
      m_seiWriter.writeSEImessages(nalu.m_Bitstream, seiMessages, sps, *m_HRD, false);
    #else
    
      m_seiWriter.writeSEImessages(nalu.m_Bitstream, seiMessages, sps, false);
    
      auPos = accessUnit.insert(auPos, new NALUnitEBSP(nalu));
      auPos++;
    }
    
    void EncGOP::xWriteSEISeparately (NalUnitType naluType, SEIMessages& seiMessages, AccessUnit &accessUnit, AccessUnit::iterator &auPos, int temporalId, const SPS *sps)
    {
      // don't do anything, if we get an empty list
      if (seiMessages.empty())
      {
        return;
      }
      for (SEIMessages::const_iterator sei = seiMessages.begin(); sei!=seiMessages.end(); sei++ )
      {
        SEIMessages tmpMessages;
        tmpMessages.push_back(*sei);
        OutputNALUnit nalu(naluType, temporalId);
    
    #if JVET_N0353_INDEP_BUFF_TIME_SEI
        m_seiWriter.writeSEImessages(nalu.m_Bitstream, tmpMessages, sps, *m_HRD, false);
    #else
    
        m_seiWriter.writeSEImessages(nalu.m_Bitstream, tmpMessages, sps, false);
    
        auPos = accessUnit.insert(auPos, new NALUnitEBSP(nalu));
        auPos++;
      }
    }
    
    void EncGOP::xClearSEIs(SEIMessages& seiMessages, bool deleteMessages)
    {
      if (deleteMessages)
      {
        deleteSEIs(seiMessages);
      }
      else
      {
        seiMessages.clear();
      }
    }
    
    // write SEI messages as separate NAL units ordered
    void EncGOP::xWriteLeadingSEIOrdered (SEIMessages& seiMessages, SEIMessages& duInfoSeiMessages, AccessUnit &accessUnit, int temporalId, const SPS *sps, bool testWrite)
    {
      AccessUnit::iterator itNalu = accessUnit.begin();
    
      while ( (itNalu!=accessUnit.end())&&
        ( (*itNalu)->m_nalUnitType==NAL_UNIT_ACCESS_UNIT_DELIMITER
        || (*itNalu)->m_nalUnitType==NAL_UNIT_VPS
    
        || (*itNalu)->m_nalUnitType==NAL_UNIT_DPS
    
        || (*itNalu)->m_nalUnitType==NAL_UNIT_SPS
        || (*itNalu)->m_nalUnitType==NAL_UNIT_PPS
        ))
      {
        itNalu++;
      }
    
      SEIMessages localMessages = seiMessages;
      SEIMessages currentMessages;
    
    #if ENABLE_TRACING
      g_HLSTraceEnable = !testWrite;
    #endif
      // The case that a specific SEI is not present is handled in xWriteSEI (empty list)
    
    
      // Active parameter sets SEI must always be the first SEI
      currentMessages = extractSeisByType(localMessages, SEI::ACTIVE_PARAMETER_SETS);
      CHECK(!(currentMessages.size() <= 1), "Unspecified error");
      xWriteSEI(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId, sps);
      xClearSEIs(currentMessages, !testWrite);
    
      // Buffering period SEI must always be following active parameter sets
      currentMessages = extractSeisByType(localMessages, SEI::BUFFERING_PERIOD);
      CHECK(!(currentMessages.size() <= 1), "Unspecified error");
      xWriteSEI(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId, sps);
      xClearSEIs(currentMessages, !testWrite);
    
      // Picture timing SEI must always be following buffering period
      currentMessages = extractSeisByType(localMessages, SEI::PICTURE_TIMING);
      CHECK(!(currentMessages.size() <= 1), "Unspecified error");
      xWriteSEI(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId, sps);
      xClearSEIs(currentMessages, !testWrite);
    
      // Decoding unit info SEI must always be following picture timing
      if (!duInfoSeiMessages.empty())
      {
        currentMessages.push_back(duInfoSeiMessages.front());
        if (!testWrite)
        {
          duInfoSeiMessages.pop_front();
        }
        xWriteSEI(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId, sps);
        xClearSEIs(currentMessages, !testWrite);
      }
    
    
      // Scalable nesting SEI must always be the following DU info
      currentMessages = extractSeisByType(localMessages, SEI::SCALABLE_NESTING);
      xWriteSEISeparately(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId, sps);
      xClearSEIs(currentMessages, !testWrite);
    
      // And finally everything else one by one
      xWriteSEISeparately(NAL_UNIT_PREFIX_SEI, localMessages, accessUnit, itNalu, temporalId, sps);
      xClearSEIs(localMessages, !testWrite);
    
      if (!testWrite)
      {
        seiMessages.clear();
      }
    }
    
    
    void EncGOP::xWriteLeadingSEIMessages (SEIMessages& seiMessages, SEIMessages& duInfoSeiMessages, AccessUnit &accessUnit, int temporalId, const SPS *sps, std::deque<DUData> &duData)
    {
      AccessUnit testAU;
      SEIMessages picTimingSEIs = getSeisByType(seiMessages, SEI::PICTURE_TIMING);
      CHECK(!(picTimingSEIs.size() < 2), "Unspecified error");
      SEIPictureTiming * picTiming = picTimingSEIs.empty() ? NULL : (SEIPictureTiming*) picTimingSEIs.front();
    
      // test writing
      xWriteLeadingSEIOrdered(seiMessages, duInfoSeiMessages, testAU, temporalId, sps, true);
      // update Timing and DU info SEI
      xUpdateDuData(testAU, duData);
      xUpdateTimingSEI(picTiming, duData, sps);
      xUpdateDuInfoSEI(duInfoSeiMessages, picTiming);
      // actual writing
      xWriteLeadingSEIOrdered(seiMessages, duInfoSeiMessages, accessUnit, temporalId, sps, false);
    
      // testAU will automatically be cleaned up when losing scope
    }
    
    void EncGOP::xWriteTrailingSEIMessages (SEIMessages& seiMessages, AccessUnit &accessUnit, int temporalId, const SPS *sps)
    {
      // Note: using accessUnit.end() works only as long as this function is called after slice coding and before EOS/EOB NAL units
      AccessUnit::iterator pos = accessUnit.end();
      xWriteSEISeparately(NAL_UNIT_SUFFIX_SEI, seiMessages, accessUnit, pos, temporalId, sps);
      deleteSEIs(seiMessages);
    }
    
    void EncGOP::xWriteDuSEIMessages (SEIMessages& duInfoSeiMessages, AccessUnit &accessUnit, int temporalId, const SPS *sps, std::deque<DUData> &duData)
    {
    
    Virginie Drugeon's avatar
    Virginie Drugeon committed
      const HRDParameters *hrd = sps->getHrdParameters();
    
    #if JVET_O0189_DU
      if( m_pcCfg->getDecodingUnitInfoSEIEnabled() && hrd->getDecodingUnitCpbParamsInPicTimingSeiFlag() )
    #else
    
      if( m_pcCfg->getDecodingUnitInfoSEIEnabled() && hrd->getSubPicCpbParamsPresentFlag() )
    
      {
        int naluIdx = 0;
        AccessUnit::iterator nalu = accessUnit.begin();
    
        // skip over first DU, we have a DU info SEI there already
        while (naluIdx < duData[0].accumNalsDU && nalu!=accessUnit.end())
        {
          naluIdx++;
          nalu++;
        }
    
        SEIMessages::iterator duSEI = duInfoSeiMessages.begin();
        // loop over remaining DUs
        for (int duIdx = 1; duIdx < duData.size(); duIdx++)
        {
          if (duSEI == duInfoSeiMessages.end())
          {
            // if the number of generated SEIs matches the number of DUs, this should not happen
            CHECK(!(false), "Unspecified error");
            return;
          }
          // write the next SEI
          SEIMessages tmpSEI;
          tmpSEI.push_back(*duSEI);
          xWriteSEI(NAL_UNIT_PREFIX_SEI, tmpSEI, accessUnit, nalu, temporalId, sps);
          // nalu points to the position after the SEI, so we have to increase the index as well
          naluIdx++;
          while ((naluIdx < duData[duIdx].accumNalsDU) && nalu!=accessUnit.end())
          {
            naluIdx++;
            nalu++;
          }
          duSEI++;
        }
      }
      deleteSEIs(duInfoSeiMessages);
    }
    
    
    void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS *sps, const PPS *pps)
    {
      OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI);
    
    
      if(m_pcCfg->getActiveParameterSetsSEIEnabled())
      {
        SEIActiveParameterSets *sei = new SEIActiveParameterSets;
        m_seiEncoder.initSEIActiveParameterSets(sei, sps);
        seiMessages.push_back(sei);
      }
    
      if(m_pcCfg->getFramePackingArrangementSEIEnabled())
      {
        SEIFramePacking *sei = new SEIFramePacking;
        m_seiEncoder.initSEIFramePacking (sei, m_iNumPicCoded);
        seiMessages.push_back(sei);
      }
    
      if(m_pcCfg->getSegmentedRectFramePackingArrangementSEIEnabled())
      {
        SEISegmentedRectFramePacking *sei = new SEISegmentedRectFramePacking;
        m_seiEncoder.initSEISegmentedRectFramePacking(sei);
        seiMessages.push_back(sei);
      }
    
      if (m_pcCfg->getDisplayOrientationSEIAngle())
      {
        SEIDisplayOrientation *sei = new SEIDisplayOrientation;
        m_seiEncoder.initSEIDisplayOrientation(sei);
        seiMessages.push_back(sei);
      }
    
      if(m_pcCfg->getToneMappingInfoSEIEnabled())
      {
        SEIToneMappingInfo *sei = new SEIToneMappingInfo;
        m_seiEncoder.initSEIToneMappingInfo (sei);
        seiMessages.push_back(sei);
      }
    
      if(m_pcCfg->getTMCTSSEIEnabled())
      {
        SEITempMotionConstrainedTileSets *sei = new SEITempMotionConstrainedTileSets;
        m_seiEncoder.initSEITempMotionConstrainedTileSets(sei, pps);
        seiMessages.push_back(sei);
      }
    
      if(m_pcCfg->getTimeCodeSEIEnabled())
      {
        SEITimeCode *seiTimeCode = new SEITimeCode;
        m_seiEncoder.initSEITimeCode(seiTimeCode);
        seiMessages.push_back(seiTimeCode);
      }
    
      if(m_pcCfg->getKneeSEIEnabled())
      {
        SEIKneeFunctionInfo *sei = new SEIKneeFunctionInfo;
        m_seiEncoder.initSEIKneeFunctionInfo(sei);
        seiMessages.push_back(sei);
      }
    
      if(m_pcCfg->getMasteringDisplaySEI().colourVolumeSEIEnabled)
      {
        const SEIMasteringDisplay &seiCfg=m_pcCfg->getMasteringDisplaySEI();
        SEIMasteringDisplayColourVolume *sei = new SEIMasteringDisplayColourVolume;
        sei->values = seiCfg;
        seiMessages.push_back(sei);
      }
      if(m_pcCfg->getChromaResamplingFilterHintEnabled())
      {
        SEIChromaResamplingFilterHint *seiChromaResamplingFilterHint = new SEIChromaResamplingFilterHint;
        m_seiEncoder.initSEIChromaResamplingFilterHint(seiChromaResamplingFilterHint, m_pcCfg->getChromaResamplingHorFilterIdc(), m_pcCfg->getChromaResamplingVerFilterIdc());
        seiMessages.push_back(seiChromaResamplingFilterHint);
      }
    #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
      if(m_pcCfg->getSEIAlternativeTransferCharacteristicsSEIEnable())
      {
        SEIAlternativeTransferCharacteristics *seiAlternativeTransferCharacteristics = new SEIAlternativeTransferCharacteristics;
        m_seiEncoder.initSEIAlternativeTransferCharacteristics(seiAlternativeTransferCharacteristics);
        seiMessages.push_back(seiAlternativeTransferCharacteristics);
      }
    #endif
    
    }
    
    void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice)
    {
    
    #if JVET_OO152_BP_SEI_GDR
    
    #if JVET_O0189_DU
      if ((m_pcCfg->getBufferingPeriodSEIEnabled()) && (slice->isIRAP() || slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR) &&
        ( slice->getSPS()->getHrdParametersPresentFlag() ) )
    #else
    
      if ((m_pcCfg->getBufferingPeriodSEIEnabled()) && (slice->isIRAP() || slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR) &&
        (slice->getSPS()->getVuiParametersPresentFlag()) &&
        ((slice->getSPS()->getHrdParameters()->getNalHrdParametersPresentFlag())
          || (slice->getSPS()->getHrdParameters()->getVclHrdParametersPresentFlag())))
    
    #endif
    #else
    #if JVET_O0189_DU
      if( ( m_pcCfg->getBufferingPeriodSEIEnabled() ) && ( slice->getSliceType() == I_SLICE ) &&
        ( slice->getSPS()->getHrdParametersPresentFlag() ) )
    
    Virginie Drugeon's avatar
    Virginie Drugeon committed
      if( ( m_pcCfg->getBufferingPeriodSEIEnabled() ) && ( slice->getSliceType() == I_SLICE ) &&
        ( slice->getSPS()->getVuiParametersPresentFlag() ) &&
        ( ( slice->getSPS()->getHrdParameters()->getNalHrdParametersPresentFlag() )
        || ( slice->getSPS()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) )
    
      {
        SEIBufferingPeriod *bufferingPeriodSEI = new SEIBufferingPeriod();
    
        m_seiEncoder.initSEIBufferingPeriod(bufferingPeriodSEI);
    #if JVET_N0353_INDEP_BUFF_TIME_SEI
        m_HRD->setBufferingPeriodSEI(bufferingPeriodSEI);
    #endif
    
        seiMessages.push_back(bufferingPeriodSEI);
        m_bufferingPeriodSEIPresentInAU = true;
    
    
        if (m_pcCfg->getScalableNestingSEIEnabled())
        {
          SEIBufferingPeriod *bufferingPeriodSEIcopy = new SEIBufferingPeriod();
          bufferingPeriodSEI->copyTo(*bufferingPeriodSEIcopy);
          nestedSeiMessages.push_back(bufferingPeriodSEIcopy);
        }
    
    #if JVET_N0494_DRAP
      if (m_pcEncLib->getDependentRAPIndicationSEIEnabled() && slice->isDRAP())
      {
        SEIDependentRAPIndication *dependentRAPIndicationSEI = new SEIDependentRAPIndication();
        m_seiEncoder.initSEIDependentRAPIndication(dependentRAPIndicationSEI);
        seiMessages.push_back(dependentRAPIndicationSEI);
      }
    #endif
    
    
      if (picInGOP ==0 && m_pcCfg->getSOPDescriptionSEIEnabled() ) // write SOP description SEI (if enabled) at the beginning of GOP
      {
        SEISOPDescription* sopDescriptionSEI = new SEISOPDescription();
        m_seiEncoder.initSEISOPDescription(sopDescriptionSEI, slice, picInGOP, m_iLastIDR, m_iGopSize);
        seiMessages.push_back(sopDescriptionSEI);
      }
    
      if( ( m_pcEncLib->getRecoveryPointSEIEnabled() ) && ( slice->getSliceType() == I_SLICE ) )
      {
        if( m_pcEncLib->getGradualDecodingRefreshInfoEnabled() && !slice->getRapPicFlag() )
        {
          // Gradual decoding refresh SEI
          SEIGradualDecodingRefreshInfo *gradualDecodingRefreshInfoSEI = new SEIGradualDecodingRefreshInfo();
          gradualDecodingRefreshInfoSEI->m_gdrForegroundFlag = true; // Indicating all "foreground"
          seiMessages.push_back(gradualDecodingRefreshInfoSEI);
        }
        // Recovery point SEI
        SEIRecoveryPoint *recoveryPointSEI = new SEIRecoveryPoint();
        m_seiEncoder.initSEIRecoveryPoint(recoveryPointSEI, slice);
        seiMessages.push_back(recoveryPointSEI);
      }
      if (m_pcCfg->getTemporalLevel0IndexSEIEnabled())
      {
        SEITemporalLevel0Index *temporalLevel0IndexSEI = new SEITemporalLevel0Index();
        m_seiEncoder.initTemporalLevel0IndexSEI(temporalLevel0IndexSEI, slice);
        seiMessages.push_back(temporalLevel0IndexSEI);
      }
    
      if( m_pcEncLib->getNoDisplaySEITLayer() && ( slice->getTLayer() >= m_pcEncLib->getNoDisplaySEITLayer() ) )
      {
        SEINoDisplay *seiNoDisplay = new SEINoDisplay;
        seiNoDisplay->m_noDisplay = true;
        seiMessages.push_back(seiNoDisplay);
      }
    
      // insert one Colour Remapping Info SEI for the picture (if the file exists)
      if (!m_pcCfg->getColourRemapInfoSEIFileRoot().empty())
      {
        SEIColourRemappingInfo *seiColourRemappingInfo = new SEIColourRemappingInfo();
        const bool success = m_seiEncoder.initSEIColourRemappingInfo(seiColourRemappingInfo, slice->getPOC() );
    
        if(success)
        {
          seiMessages.push_back(seiColourRemappingInfo);
        }
        else
        {
          delete seiColourRemappingInfo;
        }
      }
    
    void EncGOP::xCreateScalableNestingSEI (SEIMessages& seiMessages, SEIMessages& nestedSeiMessages)
    {
      SEIMessages tmpMessages;
      while (!nestedSeiMessages.empty())
      {
        SEI* sei=nestedSeiMessages.front();
        nestedSeiMessages.pop_front();
        tmpMessages.push_back(sei);
        SEIScalableNesting *nestingSEI = new SEIScalableNesting();
        m_seiEncoder.initSEIScalableNesting(nestingSEI, tmpMessages);
        seiMessages.push_back(nestingSEI);
        tmpMessages.clear();
      }
    }
    
    #if JVET_O0041_FRAME_FIELD_SEI
    void EncGOP::xCreateFrameFieldInfoSEI  (SEIMessages& seiMessages, Slice *slice, bool isField)
    {
      if (m_pcCfg->getFrameFieldInfoSEIEnabled())
      {
        SEIFrameFieldInfo *frameFieldInfoSEI = new SEIFrameFieldInfo();
    
        // encode only very basic information. if more feature are supported, this should be moved to SEIEncoder
        frameFieldInfoSEI->m_fieldPicFlag = isField;
        if (isField)
        {
          frameFieldInfoSEI->m_bottomFieldFlag = !slice->getPic()->topField;
        }
        seiMessages.push_back(frameFieldInfoSEI);
      }
    }
    #endif
    
    
    
    void EncGOP::xCreatePictureTimingSEI  (int IRAPGOPid, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, SEIMessages& duInfoSeiMessages, Slice *slice, bool isField, std::deque<DUData> &duData)
    {
    
    #if JVET_N0353_INDEP_BUFF_TIME_SEI
      // Picture timing depends on buffering period. When either of those is not disabled,
      // initialization would fail. Needs more cleanup after DU timing is integrated.
      if (!(m_pcCfg->getPictureTimingSEIEnabled() && m_pcCfg->getBufferingPeriodSEIEnabled()))
      {
        return;
      }
    #endif
    
    
    Virginie Drugeon's avatar
    Virginie Drugeon committed
      const HRDParameters *hrd = slice->getSPS()->getHrdParameters();
    
    #if JVET_O0189_DU
      if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) )
    #else
    
      if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) &&
        ( slice->getSPS()->getVuiParametersPresentFlag() ) &&
        (  hrd->getNalHrdParametersPresentFlag() || hrd->getVclHrdParametersPresentFlag() ) )
    
      {
        int picSptDpbOutputDuDelay = 0;
        SEIPictureTiming *pictureTimingSEI = new SEIPictureTiming();
    
        // DU parameters
    
    #if JVET_O0189_DU
        if( hrd->getDecodingUnitHrdParamsPresentFlag() )
    #else
    
        {
          uint32_t numDU = (uint32_t) duData.size();
          pictureTimingSEI->m_numDecodingUnitsMinus1     = ( numDU - 1 );
          pictureTimingSEI->m_duCommonCpbRemovalDelayFlag = false;
          pictureTimingSEI->m_numNalusInDuMinus1.resize( numDU );
          pictureTimingSEI->m_duCpbRemovalDelayMinus1.resize( numDU );
        }
    
    #if JVET_N0353_INDEP_BUFF_TIME_SEI
        const uint32_t cpbRemovalDelayLegth = m_HRD->getBufferingPeriodSEI()->m_cpbRemovalDelayLength;
        pictureTimingSEI->m_auCpbRemovalDelay = std::min<int>(std::max<int>(1, m_totalCoded - m_lastBPSEI), static_cast<int>(pow(2, static_cast<double>(cpbRemovalDelayLegth)))); // Syntax element signalled as minus, hence the .
    #else
    
        pictureTimingSEI->m_auCpbRemovalDelay = std::min<int>(std::max<int>(1, m_totalCoded - m_lastBPSEI), static_cast<int>(pow(2, static_cast<double>(hrd->getCpbRemovalDelayLengthMinus1()+1)))); // Syntax element signalled as minus, hence the .
    
        pictureTimingSEI->m_picDpbOutputDelay = slice->getSPS()->getNumReorderPics(slice->getSPS()->getMaxTLayers()-1) + slice->getPOC() - m_totalCoded;
        if(m_pcCfg->getEfficientFieldIRAPEnabled() && IRAPGOPid > 0 && IRAPGOPid < m_iGopSize)
        {
          // if pictures have been swapped there is likely one more picture delay on their tid. Very rough approximation
          pictureTimingSEI->m_picDpbOutputDelay ++;
        }
        int factor = hrd->getTickDivisorMinus2() + 2;
        pictureTimingSEI->m_picDpbOutputDuDelay = factor * pictureTimingSEI->m_picDpbOutputDelay;
        if( m_pcCfg->getDecodingUnitInfoSEIEnabled() )
        {
          picSptDpbOutputDuDelay = factor * pictureTimingSEI->m_picDpbOutputDelay;
        }
        if (m_bufferingPeriodSEIPresentInAU)
        {
          m_lastBPSEI = m_totalCoded;
        }
    
    
        if( m_pcCfg->getPictureTimingSEIEnabled() )
        {
    
    #if !JVET_O0041_FRAME_FIELD_SEI
    
          pictureTimingSEI->m_picStruct = (isField && slice->getPic()->topField)? 1 : isField? 2 : 0;
    
          if ( m_pcCfg->getScalableNestingSEIEnabled() ) // put picture timing SEI into scalable nesting SEI
          {
            SEIPictureTiming *pictureTimingSEIcopy = new SEIPictureTiming();
            pictureTimingSEI->copyTo(*pictureTimingSEIcopy);
            nestedSeiMessages.push_back(pictureTimingSEIcopy);
          }
    
    #if JVET_O0189_DU
        if( m_pcCfg->getDecodingUnitInfoSEIEnabled() && hrd->getDecodingUnitHrdParamsPresentFlag() )
    #else
    
        if( m_pcCfg->getDecodingUnitInfoSEIEnabled() && hrd->getSubPicCpbParamsPresentFlag() )
    
        {
          for( int i = 0; i < ( pictureTimingSEI->m_numDecodingUnitsMinus1 + 1 ); i ++ )
          {
            SEIDecodingUnitInfo *duInfoSEI = new SEIDecodingUnitInfo();
            duInfoSEI->m_decodingUnitIdx = i;
            duInfoSEI->m_duSptCpbRemovalDelay = pictureTimingSEI->m_duCpbRemovalDelayMinus1[i] + 1;
            duInfoSEI->m_dpbOutputDuDelayPresentFlag = false;
            duInfoSEI->m_picSptDpbOutputDuDelay = picSptDpbOutputDuDelay;
    
            duInfoSeiMessages.push_back(duInfoSEI);
          }
        }
    
        if( !m_pcCfg->getPictureTimingSEIEnabled() && pictureTimingSEI )
        {
          delete pictureTimingSEI;
        }
      }
    }
    
    void EncGOP::xUpdateDuData(AccessUnit &testAU, std::deque<DUData> &duData)
    {
      if (duData.empty())
      {
        return;
      }
      // fix first
      uint32_t numNalUnits = (uint32_t)testAU.size();
      uint32_t numRBSPBytes = 0;
      for (AccessUnit::const_iterator it = testAU.begin(); it != testAU.end(); it++)
      {
        numRBSPBytes += uint32_t((*it)->m_nalUnitData.str().size());
      }
      duData[0].accumBitsDU += ( numRBSPBytes << 3 );
      duData[0].accumNalsDU += numNalUnits;
    
      // adapt cumulative sums for all following DUs
      // and add one DU info SEI, if enabled
      for (int i=1; i<duData.size(); i++)
      {
        if (m_pcCfg->getDecodingUnitInfoSEIEnabled())
        {
          numNalUnits  += 1;
          numRBSPBytes += ( 5 << 3 );
        }
        duData[i].accumBitsDU += numRBSPBytes; // probably around 5 bytes
        duData[i].accumNalsDU += numNalUnits;
      }
    
      // The last DU may have a trailing SEI
      if (m_pcCfg->getDecodedPictureHashSEIType()!=HASHTYPE_NONE)
      {
        duData.back().accumBitsDU += ( 20 << 3 ); // probably around 20 bytes - should be further adjusted, e.g. by type
        duData.back().accumNalsDU += 1;
      }
    
    }
    void EncGOP::xUpdateTimingSEI(SEIPictureTiming *pictureTimingSEI, std::deque<DUData> &duData, const SPS *sps)
    {
      if (!pictureTimingSEI)
      {
        return;
      }
    
    Virginie Drugeon's avatar
    Virginie Drugeon committed
      const HRDParameters *hrd = sps->getHrdParameters();
    
    #if JVET_O0189_DU
      if( hrd->getDecodingUnitHrdParamsPresentFlag() )
    #else
    
      {
        int i;
        uint64_t ui64Tmp;
        uint32_t uiPrev = 0;
        uint32_t numDU = ( pictureTimingSEI->m_numDecodingUnitsMinus1 + 1 );
        std::vector<uint32_t> &rDuCpbRemovalDelayMinus1 = pictureTimingSEI->m_duCpbRemovalDelayMinus1;