Skip to content
Snippets Groups Projects
EncGOP.cpp 283 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-2023, 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 "CommonLib/ProfileLevelTier.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));
    
      ::memset(m_lastBPSEI, 0, sizeof(m_lastBPSEI));
      m_rapWithLeading      = false;
    
      for (int i = 0; i < MAX_VPS_LAYERS; i++)
      {
        m_associatedIRAPType[i] = NAL_UNIT_CODED_SLICE_IDR_N_LP;
      }
      ::memset(m_associatedIRAPPOC, 0, sizeof(m_associatedIRAPPOC));
    
    #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;
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_cBilateralFilter.create();
    #endif
    
    }
    
    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;
      }
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_cBilateralFilter.destroy();
    #endif
    
    }
    
    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();
    
    #if JVET_AA0096_MC_BOUNDARY_PADDING
      m_pcFrameMcPadPrediction = pcEncLib->getFrameMcPadPredSearch();
    #endif
    
      ::memset(m_lastBPSEI, 0, sizeof(m_lastBPSEI));
      ::memset(m_totalCoded, 0, sizeof(m_totalCoded));
    
      {
        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->getLmcs() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ )
    
    Taoran Lu's avatar
    Taoran Lu committed
      {
        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);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
      m_lastGdrIntervalPoc = -1;
    #endif
    
    }
    
    int EncGOP::xWriteVPS (AccessUnit &accessUnit, const VPS *vps)
    {
      OutputNALUnit nalu(NAL_UNIT_VPS);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
    
      CHECK( nalu.m_temporalId, "The value of TemporalId of VPS NAL units shall be equal to 0" );
    
      m_HLSWriter->codeVPS( vps );
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    int EncGOP::xWriteDCI(AccessUnit& accessUnit, const DCI* dci)
    {
      OutputNALUnit nalu(NAL_UNIT_DCI);
      m_HLSWriter->setBitstream(&nalu.m_Bitstream);
    
      CHECK(nalu.m_temporalId, "The value of TemporalId of DCI NAL units shall be equal to 0");
    
      m_HLSWriter->codeDCI(dci);
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    int EncGOP::xWriteSPS( AccessUnit &accessUnit, const SPS *sps, const int layerId )
    
    {
      OutputNALUnit nalu(NAL_UNIT_SPS);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
    
      nalu.m_nuhLayerId = layerId;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      CHECK( nalu.m_temporalId, "The value of TemporalId of SPS NAL units shall be equal to 0" );
    
      m_HLSWriter->codeSPS( sps );
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    
    }
    
    
    int EncGOP::xWritePPS( AccessUnit &accessUnit, const PPS *pps, const int layerId )
    
    {
      OutputNALUnit nalu(NAL_UNIT_PPS);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
    
    Philippe Bordes's avatar
    Philippe Bordes committed
    #if RPR_ENABLE
      nalu.m_temporalId = accessUnit.temporalId;
    #endif
    
      CHECK( nalu.m_temporalId < accessUnit.temporalId, "TemporalId shall be greater than or equal to the TemporalId of the layer access unit containing the NAL unit" );
    
      m_HLSWriter->codePPS( pps );
    
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    
    int EncGOP::xWriteAPS( AccessUnit &accessUnit, APS *aps, const int layerId, const bool isPrefixNUT )
    {
      OutputNALUnit nalu( isPrefixNUT ? NAL_UNIT_PREFIX_APS : NAL_UNIT_SUFFIX_APS );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      aps->setLayerId( layerId );
    #if EMBEDDED_APS 
      m_aps.push_back( *aps );
      return 0;
    #endif
    
    Hendry's avatar
    Hendry committed
      m_HLSWriter->setBitstream(&nalu.m_Bitstream);
    
      nalu.m_nuhLayerId = layerId;
      nalu.m_temporalId = aps->getTemporalId();
      CHECK( nalu.m_temporalId < accessUnit.temporalId, "TemporalId shall be greater than or equal to the TemporalId of the layer access unit containing the NAL unit" );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if EMBEDDED_APS
      m_HLSWriter->codeAPS( aps, true );
    #else
      m_HLSWriter->codeAPS( aps );
    #endif
    
    Hendry's avatar
    Hendry committed
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    BDChoi's avatar
    BDChoi committed
    int EncGOP::xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool bSeqFirst, const int layerIdx)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      if( bSeqFirst )
      {
    
    BDChoi's avatar
    BDChoi committed
        if (layerIdx == 0)
        {
    
    Kai Zhang's avatar
    Kai Zhang committed
          if (m_pcCfg->getDCIEnabled())
          {
            actualTotalBits += xWriteDCI(accessUnit, m_pcEncLib->getDCI());
          }
    
    BDChoi's avatar
    BDChoi committed
          if (slice->getSPS()->getVPSId() != 0)
          {
            actualTotalBits += xWriteVPS(accessUnit, m_pcEncLib->getVPS());
          }
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        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(), m_pcEncLib->getLayerId() );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        }
      }
    
      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_AC0096
        if (m_pcEncLib->getRprPopulatePPSatIntraFlag())
        {
          if (slice->isIntra())
          {
            actualTotalBits += xWritePPS(accessUnit, slice->getPPS(), m_pcEncLib->getLayerId());
            if (!(slice->getPPS()->getPPSId() == 0))
            {
              const PPS* pPPS = m_pcEncLib->getPPS(0);
              actualTotalBits += xWritePPS(accessUnit, pPPS, m_pcEncLib->getLayerId());
            }
            if (!(slice->getPPS()->getPPSId() == ENC_PPS_ID_RPR))
            {
              const PPS* pPPS = m_pcEncLib->getPPS(ENC_PPS_ID_RPR);
              actualTotalBits += xWritePPS(accessUnit, pPPS, m_pcEncLib->getLayerId());
            }
            if (!(slice->getPPS()->getPPSId() == ENC_PPS_ID_RPR2))
            {
              const PPS* pPPS = m_pcEncLib->getPPS(ENC_PPS_ID_RPR2);
              actualTotalBits += xWritePPS(accessUnit, pPPS, m_pcEncLib->getLayerId());
            }
            if (!(slice->getPPS()->getPPSId() == ENC_PPS_ID_RPR3))
            {
              const PPS* pPPS = m_pcEncLib->getPPS(ENC_PPS_ID_RPR3);
              actualTotalBits += xWritePPS(accessUnit, pPPS, m_pcEncLib->getLayerId());
            }
          }
          else
          {
            if (!(slice->getPPS()->getPPSId() == 0) && !(slice->getPPS()->getPPSId() == ENC_PPS_ID_RPR) && !(slice->getPPS()->getPPSId() == ENC_PPS_ID_RPR2) && !(slice->getPPS()->getPPSId() == ENC_PPS_ID_RPR3))
            {
              const PPS* pPPS = m_pcEncLib->getPPS(0);
              actualTotalBits += xWritePPS(accessUnit, pPPS, m_pcEncLib->getLayerId());
            }
          }
        }
        else
        {
          actualTotalBits += xWritePPS(accessUnit, slice->getPPS(), m_pcEncLib->getLayerId());
        }
    #else
    
        actualTotalBits += xWritePPS( accessUnit, slice->getPPS(), m_pcEncLib->getLayerId() );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      }
    
    Brian Heng's avatar
    Brian Heng committed
    int EncGOP::xWritePicHeader( AccessUnit &accessUnit, PicHeader *picHeader )
    {
      OutputNALUnit nalu(NAL_UNIT_PH);
      m_HLSWriter->setBitstream( &nalu.m_Bitstream );
      nalu.m_temporalId = accessUnit.temporalId;
    
      nalu.m_nuhLayerId = m_pcEncLib->getLayerId();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
    #if EMBEDDED_APS
      m_HLSWriter->codePictureHeader( picHeader, true, m_aps );
    #else
    
      m_HLSWriter->codePictureHeader( picHeader, true );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
      accessUnit.push_back(new NALUnitEBSP(nalu));
      return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
    }
    
    
    void EncGOP::xWriteAccessUnitDelimiter (AccessUnit &accessUnit, Slice *slice)
    {
      AUDWriter audWriter;
      OutputNALUnit nalu(NAL_UNIT_ACCESS_UNIT_DELIMITER);
    
      int vpsId = slice->getSPS()->getVPSId();
    
        nalu.m_nuhLayerId = slice->getVPS()->getLayerId(0);
    
      }
      CHECK( nalu.m_temporalId != accessUnit.temporalId, "TemporalId shall be equal to the TemporalId of the AU containing the NAL unit" );
    
      int picType = slice->isIntra() ? 0 : (slice->isInterP() ? 1 : 2);
    
      audWriter.codeAUD(nalu.m_Bitstream, m_audIrapOrGdrAuFlag, 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)
    
    {
      // don't do anything, if we get an empty list
      if (seiMessages.empty())
      {
        return;
      }
    
      OutputNALUnit nalu( naluType, m_pcEncLib->getLayerId(), temporalId );
    
      m_seiWriter.writeSEImessages(nalu.m_Bitstream, seiMessages, *m_HRD, false, temporalId);
    
      auPos = accessUnit.insert(auPos, new NALUnitEBSP(nalu));
      auPos++;
    }
    
    
    void EncGOP::xWriteSEISeparately (NalUnitType naluType, SEIMessages& seiMessages, AccessUnit &accessUnit, AccessUnit::iterator &auPos, int temporalId)
    
    {
      // 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, m_pcEncLib->getLayerId(), temporalId );
    
        m_seiWriter.writeSEImessages(nalu.m_Bitstream, tmpMessages, *m_HRD, false, temporalId);
    
        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, bool testWrite)
    
      while ((itNalu != accessUnit.end()) &&
        ((*itNalu)->m_nalUnitType == NAL_UNIT_ACCESS_UNIT_DELIMITER
          || (*itNalu)->m_nalUnitType == NAL_UNIT_VPS
          || (*itNalu)->m_nalUnitType == NAL_UNIT_DCI
          || (*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)
    
    
      // 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);
    
      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);
    
      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);
    
      if (m_pcCfg->getScalableNestingSEIEnabled())
      {
        // 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);
    
        xClearSEIs(currentMessages, !testWrite);
      }
    
      xWriteSEISeparately(NAL_UNIT_PREFIX_SEI, localMessages, accessUnit, itNalu, temporalId);
    
      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, true);
    
      // update Timing and DU info SEI
      xUpdateDuData(testAU, duData);
      xUpdateTimingSEI(picTiming, duData, sps);
    
      xUpdateDuInfoSEI(duInfoSeiMessages, picTiming, sps->getMaxTLayers());
    
      xWriteLeadingSEIOrdered(seiMessages, duInfoSeiMessages, accessUnit, temporalId, false);
    
    
      // testAU will automatically be cleaned up when losing scope
    }
    
    
    void EncGOP::xWriteTrailingSEIMessages (SEIMessages& seiMessages, AccessUnit &accessUnit, int temporalId)
    
    {
      // 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);
    
    void EncGOP::xWriteDuSEIMessages (SEIMessages& duInfoSeiMessages, AccessUnit &accessUnit, int temporalId, std::deque<DUData> &duData)
    
      if( m_pcCfg->getDecodingUnitInfoSEIEnabled() && m_HRD->getBufferingPeriodSEI()->m_decodingUnitCpbParamsInPicTimingSeiFlag )
    
      {
        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);
    
          // 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->getFramePackingArrangementSEIEnabled())
      {
        SEIFramePacking *sei = new SEIFramePacking;
        m_seiEncoder.initSEIFramePacking (sei, m_iNumPicCoded);
        seiMessages.push_back(sei);
      }
    
    
      if (m_pcCfg->getParameterSetsInclusionIndicationSEIEnabled())
      {
        SEIParameterSetsInclusionIndication* sei = new SEIParameterSetsInclusionIndication;
        m_seiEncoder.initSEIParameterSetsInclusionIndication(sei);
        seiMessages.push_back(sei);
      }
    
    
    #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
      if(m_pcCfg->getSEIAlternativeTransferCharacteristicsSEIEnable())
      {
        SEIAlternativeTransferCharacteristics *seiAlternativeTransferCharacteristics = new SEIAlternativeTransferCharacteristics;
        m_seiEncoder.initSEIAlternativeTransferCharacteristics(seiAlternativeTransferCharacteristics);
        seiMessages.push_back(seiAlternativeTransferCharacteristics);
      }
    
      if (m_pcCfg->getErpSEIEnabled())
      {
        SEIEquirectangularProjection *sei = new SEIEquirectangularProjection;
        m_seiEncoder.initSEIErp(sei);
        seiMessages.push_back(sei);
      }
    
      if (m_pcCfg->getSphereRotationSEIEnabled())
      {
        SEISphereRotation *sei = new SEISphereRotation;
        m_seiEncoder.initSEISphereRotation(sei);
        seiMessages.push_back(sei);
      }
    
      if (m_pcCfg->getOmniViewportSEIEnabled())
      {
        SEIOmniViewport *sei = new SEIOmniViewport;
        m_seiEncoder.initSEIOmniViewport(sei);
        seiMessages.push_back(sei);
      }
      if (m_pcCfg->getRwpSEIEnabled())
      {
        SEIRegionWisePacking *seiRegionWisePacking = new SEIRegionWisePacking;
        m_seiEncoder.initSEIRegionWisePacking(seiRegionWisePacking);
        seiMessages.push_back(seiRegionWisePacking);
      }
    
      if (m_pcCfg->getGcmpSEIEnabled())
      {
        SEIGeneralizedCubemapProjection *sei = new SEIGeneralizedCubemapProjection;
        m_seiEncoder.initSEIGcmp(sei);
        seiMessages.push_back(sei);
      }
    
      if (m_pcCfg->getSubpicureLevelInfoSEICfg().m_enabled)
    
      {
        SEISubpicureLevelInfo *seiSubpicureLevelInfo = new SEISubpicureLevelInfo;
        m_seiEncoder.initSEISubpictureLevelInfo(seiSubpicureLevelInfo, sps);
        seiMessages.push_back(seiSubpicureLevelInfo);
      }
    
      if (m_pcCfg->getSampleAspectRatioInfoSEIEnabled())
      {
        SEISampleAspectRatioInfo *seiSampleAspectRatioInfo = new SEISampleAspectRatioInfo;
        m_seiEncoder.initSEISampleAspectRatioInfo(seiSampleAspectRatioInfo);
        seiMessages.push_back(seiSampleAspectRatioInfo);
      }
    
    Taoran Lu's avatar
    Taoran Lu committed
      // film grain
      if (m_pcCfg->getFilmGrainCharactersticsSEIEnabled())
      {
        SEIFilmGrainCharacteristics *sei = new SEIFilmGrainCharacteristics;
        m_seiEncoder.initSEIFilmGrainCharacteristics(sei);
        seiMessages.push_back(sei);
      }
    
      // mastering display colour volume
      if (m_pcCfg->getMasteringDisplaySEI().colourVolumeSEIEnabled)
      {
        SEIMasteringDisplayColourVolume *sei = new SEIMasteringDisplayColourVolume;
        m_seiEncoder.initSEIMasteringDisplayColourVolume(sei);
        seiMessages.push_back(sei);
      }
    
      // content light level
      if (m_pcCfg->getCLLSEIEnabled())
      {
        SEIContentLightLevelInfo *seiCLL = new SEIContentLightLevelInfo;
        m_seiEncoder.initSEIContentLightLevel(seiCLL);
        seiMessages.push_back(seiCLL);
      }
    
    
    Taoran Lu's avatar
    Taoran Lu committed
      // ambient viewing environment
    
    Taoran Lu's avatar
    Taoran Lu committed
      if (m_pcCfg->getAmbientViewingEnvironmentSEIEnabled())
      {
        SEIAmbientViewingEnvironment *seiAVE = new SEIAmbientViewingEnvironment;
        m_seiEncoder.initSEIAmbientViewingEnvironment(seiAVE);
        seiMessages.push_back(seiAVE);
      }
    
      // content colour volume
      if (m_pcCfg->getCcvSEIEnabled())
      {
        SEIContentColourVolume *seiContentColourVolume = new SEIContentColourVolume;
        m_seiEncoder.initSEIContentColourVolume(seiContentColourVolume);
        seiMessages.push_back(seiContentColourVolume);
      }
    
    }
    
    void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice)
    {
    
      if ((m_pcCfg->getBufferingPeriodSEIEnabled()) && (slice->isIRAP() || slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR) &&
    
        slice->getNalUnitLayerId()==slice->getVPS()->getLayerId(0) &&
    
      (slice->getSPS()->getGeneralHrdParametersPresentFlag()))
    
      {
        SEIBufferingPeriod *bufferingPeriodSEI = new SEIBufferingPeriod();
    
        bool noLeadingPictures = ( (slice->getNalUnitType()!= NAL_UNIT_CODED_SLICE_IDR_W_RADL) && (slice->getNalUnitType()!= NAL_UNIT_CODED_SLICE_CRA) )?(true):(false);
        m_seiEncoder.initSEIBufferingPeriod(bufferingPeriodSEI,noLeadingPictures);
    
        m_HRD->setBufferingPeriodSEI(bufferingPeriodSEI);
    
        seiMessages.push_back(bufferingPeriodSEI);
        m_bufferingPeriodSEIPresentInAU = true;
    
        if (m_pcCfg->getScalableNestingSEIEnabled())
        {
          SEIBufferingPeriod *bufferingPeriodSEIcopy = new SEIBufferingPeriod();
          bufferingPeriodSEI->copyTo(*bufferingPeriodSEIcopy);
          nestedSeiMessages.push_back(bufferingPeriodSEIcopy);
        }
    
      if (m_pcEncLib->getDependentRAPIndicationSEIEnabled() && slice->isDRAP())
      {
        SEIDependentRAPIndication *dependentRAPIndicationSEI = new SEIDependentRAPIndication();
        m_seiEncoder.initSEIDependentRAPIndication(dependentRAPIndicationSEI);
        seiMessages.push_back(dependentRAPIndicationSEI);
      }
    
    
    #if JVET_R0294_SUBPIC_HASH
    void EncGOP::xCreateScalableNestingSEI(SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, const std::vector<int> &targetOLSs, const std::vector<int> &targetLayers, const std::vector<uint16_t>& subpicIDs)
    #else
    
    void EncGOP::xCreateScalableNestingSEI(SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, const std::vector<uint16_t>& subpicIDs)
    
    {
      SEIMessages tmpMessages;
      while (!nestedSeiMessages.empty())
      {
    
        SEI* sei = nestedSeiMessages.front();
    
        nestedSeiMessages.pop_front();
        tmpMessages.push_back(sei);
        SEIScalableNesting *nestingSEI = new SEIScalableNesting();
    
    #if JVET_R0294_SUBPIC_HASH
        m_seiEncoder.initSEIScalableNesting(nestingSEI, tmpMessages, targetOLSs, targetLayers, subpicIDs);
    #else
    
        m_seiEncoder.initSEIScalableNesting(nestingSEI, tmpMessages, subpicIDs);
    
    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);
      }
    }
    
    
    
    void EncGOP::xCreatePictureTimingSEI  (int IRAPGOPid, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, SEIMessages& duInfoSeiMessages, Slice *slice, bool isField, std::deque<DUData> &duData)
    {
    
      // 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;
      }
    
    
      const GeneralHrdParams *hrd = slice->getSPS()->getGeneralHrdParameters();
    
      if ((m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled()) && slice->getNalUnitLayerId() == slice->getVPS()->getLayerId(0))
    
      {
        int picSptDpbOutputDuDelay = 0;
        SEIPictureTiming *pictureTimingSEI = new SEIPictureTiming();
    
        // DU parameters
    
        if( hrd->getGeneralDecodingUnitHrdParamsPresentFlag() )
    
        {
          uint32_t numDU = (uint32_t) duData.size();
          pictureTimingSEI->m_numDecodingUnitsMinus1     = ( numDU - 1 );
          pictureTimingSEI->m_duCommonCpbRemovalDelayFlag = false;
          pictureTimingSEI->m_numNalusInDuMinus1.resize( numDU );
    
          const uint32_t maxNumSubLayers = slice->getSPS()->getMaxTLayers();
          pictureTimingSEI->m_duCpbRemovalDelayMinus1.resize( numDU * maxNumSubLayers );
    
        const uint32_t cpbRemovalDelayLegth = m_HRD->getBufferingPeriodSEI()->m_cpbRemovalDelayLength;
    
        const uint32_t maxNumSubLayers = slice->getSPS()->getMaxTLayers();
        pictureTimingSEI->m_auCpbRemovalDelay[maxNumSubLayers-1] = std::min<int>(std::max<int>(1, m_totalCoded[maxNumSubLayers-1] - m_lastBPSEI[maxNumSubLayers-1]), static_cast<int>(pow(2, static_cast<double>(cpbRemovalDelayLegth)))); // Syntax element signalled as minus, hence the .
        CHECK( (m_totalCoded[maxNumSubLayers-1] - m_lastBPSEI[maxNumSubLayers-1]) > pow(2, static_cast<double>(cpbRemovalDelayLegth)), " cpbRemovalDelayLegth too small for m_auCpbRemovalDelay[pt_max_sub_layers_minus1] at picture timing SEI " );
        const uint32_t temporalId = slice->getTLayer();
        for( int i = temporalId ; i < maxNumSubLayers - 1 ; i ++ )
        {
          int indexWithinGOP = (m_totalCoded[maxNumSubLayers - 1] - m_lastBPSEI[maxNumSubLayers - 1]) % m_pcCfg->getGOPSize();
    
          pictureTimingSEI->m_ptSubLayerDelaysPresentFlag[i] = true;
    
    Virginie Drugeon's avatar
    Virginie Drugeon committed
          if( ((m_rapWithLeading == true) && (indexWithinGOP == 0)) || (m_totalCoded[maxNumSubLayers - 1] == 0) || m_bufferingPeriodSEIPresentInAU || (slice->getPOC() + m_pcCfg->getGOPSize()) > m_pcCfg->getFramesToBeEncoded() )
    
          {
            pictureTimingSEI->m_cpbRemovalDelayDeltaEnabledFlag[i] = false;
          }
          else
          {
            pictureTimingSEI->m_cpbRemovalDelayDeltaEnabledFlag[i] = m_HRD->getBufferingPeriodSEI()->m_cpbRemovalDelayDeltasPresentFlag;
          }
          if( pictureTimingSEI->m_cpbRemovalDelayDeltaEnabledFlag[i] )
          {
            if( m_rapWithLeading == false )
            {
              switch (m_pcCfg->getGOPSize())
              {
                case 8:
                {
                  if((indexWithinGOP == 1 && i == 2))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 0;
                  }
                  else if((indexWithinGOP == 2 && i == 2) || (indexWithinGOP == 6 && i == 2))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 1;
                  }
                  else if((indexWithinGOP == 1 && i == 1) || (indexWithinGOP == 3 && i == 2))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 2;
                  }
                  else if(indexWithinGOP == 2 && i == 1)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 3;
                  }
                  else if(indexWithinGOP == 1 && i == 0)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 4;
                  }
                  else
                  {
    
                    THROW("m_cpbRemovalDelayDeltaIdx not applicable for the sub-layer and GOP size");
    
                  }
                }
                  break;
                case 16:
                {
                  if((indexWithinGOP == 1 && i == 3))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 0;
                  }
                  else if((indexWithinGOP == 2 && i == 3) || (indexWithinGOP == 10 && i == 3) || (indexWithinGOP == 14 && i == 3))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 1;
                  }
                  else if((indexWithinGOP == 1 && i == 2) || (indexWithinGOP == 3 && i == 3) || (indexWithinGOP == 7 && i == 3) || (indexWithinGOP == 11 && i == 3))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 2;
                  }
                  else if(indexWithinGOP == 4 && i == 3)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 3;
                  }
                  else if((indexWithinGOP == 2 && i == 2) || (indexWithinGOP == 10 && i == 2))
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 4;
                  }
                  else if(indexWithinGOP == 1 && i == 1)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 5;
                  }
                  else if(indexWithinGOP == 3 && i == 2)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 6;
                  }
                  else if(indexWithinGOP == 2 && i == 1)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 7;
                  }
                  else if(indexWithinGOP == 1 && i == 0)
                  {
                    pictureTimingSEI->m_cpbRemovalDelayDeltaIdx[i] = 8;
                  }
                  else
                  {
    
                    THROW("m_cpbRemovalDelayDeltaIdx not applicable for the sub-layer and GOP size");
    
                  THROW("m_cpbRemovalDelayDeltaIdx not supported for the current GOP size");