Skip to content
Snippets Groups Projects
EncGOP.cpp 265 KiB
Newer Older
  • Learn to ignore specific revisions
  • Seungwook Hong's avatar
    Seungwook Hong committed
        if (m % n == 0)
        {
          return NAL_UNIT_CODED_SLICE_GDR;
        }
      }
    #endif
    
    
        return NAL_UNIT_CODED_SLICE_IDR_N_LP;
    
      if (m_pcCfg->getEfficientFieldIRAPEnabled() && isField && pocCurr == (m_pcCfg->getUseCompositeRef() ? 2: 1))
    
        return NAL_UNIT_CODED_SLICE_TRAIL;
    
      if (m_pcCfg->getDecodingRefreshType() != 3 && (pocCurr - isField) % (m_pcCfg->getIntraPeriod() * (m_pcCfg->getUseCompositeRef() ? 2 : 1)) == 0)
    
      {
        if (m_pcCfg->getDecodingRefreshType() == 1)
        {
          return NAL_UNIT_CODED_SLICE_CRA;
        }
        else if (m_pcCfg->getDecodingRefreshType() == 2)
        {
          return NAL_UNIT_CODED_SLICE_IDR_W_RADL;
        }
      }
      if(m_pocCRA>0)
      {
        if(pocCurr<m_pocCRA)
        {
          // All leading pictures are being marked as TFD pictures here since current encoder uses all
          // reference pictures while encoding leading pictures. An encoder can ensure that a leading
          // picture can be still decodable when random accessing to a CRA/CRANT/BLA/BLANT picture by
          // controlling the reference pictures used for encoding that leading picture. Such a leading
          // picture need not be marked as a TFD picture.
    
          return NAL_UNIT_CODED_SLICE_RASL;
    
          return NAL_UNIT_CODED_SLICE_RADL;
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
      if (m_pcCfg->getGdrEnabled() && pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % m_pcCfg->getGdrPeriod() == 0))
      {
        return NAL_UNIT_CODED_SLICE_GDR;
      }
    
    Seungwook Hong's avatar
    Seungwook Hong committed
      else if (m_pcCfg->getGdrEnabled() && (pocCurr != 0) && (pocCurr < m_pcCfg->getGdrPocStart()))
      {
        return NAL_UNIT_CODED_SLICE_TRAIL;
      }
    
    
    Seungwook Hong's avatar
    Seungwook Hong committed
      else
      {
        return NAL_UNIT_CODED_SLICE_TRAIL;
      }
    #else
    
      return NAL_UNIT_CODED_SLICE_TRAIL;
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    }
    
    void EncGOP::xUpdateRasInit(Slice* slice)
    {
      slice->setPendingRasInit( false );
      if ( slice->getPOC() > m_lastRasPoc )
      {
        m_lastRasPoc = MAX_INT;
        slice->setPendingRasInit( true );
      }
      if ( slice->isIRAP() )
      {
        m_lastRasPoc = slice->getPOC();
      }
    }
    
    double EncGOP::xCalculateRVM()
    {
      double dRVM = 0;
    
      if( m_pcCfg->getGOPSize() == 1 && m_pcCfg->getIntraPeriod() != 1 && m_pcCfg->getFramesToBeEncoded() > RVM_VCEGAM10_M * 2 )
      {
        // calculate RVM only for lowdelay configurations
        std::vector<double> vRL , vB;
        size_t N = m_vRVM_RP.size();
        vRL.resize( N );
        vB.resize( N );
    
        int i;
        double dRavg = 0 , dBavg = 0;
        vB[RVM_VCEGAM10_M] = 0;
        for( i = RVM_VCEGAM10_M + 1 ; i < N - RVM_VCEGAM10_M + 1 ; i++ )
        {
          vRL[i] = 0;
          for( int j = i - RVM_VCEGAM10_M ; j <= i + RVM_VCEGAM10_M - 1 ; j++ )
          {
            vRL[i] += m_vRVM_RP[j];
          }
          vRL[i] /= ( 2 * RVM_VCEGAM10_M );
          vB[i] = vB[i-1] + m_vRVM_RP[i] - vRL[i];
          dRavg += m_vRVM_RP[i];
          dBavg += vB[i];
        }
    
        dRavg /= ( N - 2 * RVM_VCEGAM10_M );
        dBavg /= ( N - 2 * RVM_VCEGAM10_M );
    
        double dSigamB = 0;
        for( i = RVM_VCEGAM10_M + 1 ; i < N - RVM_VCEGAM10_M + 1 ; i++ )
        {
          double tmp = vB[i] - dBavg;
          dSigamB += tmp * tmp;
        }
        dSigamB = sqrt( dSigamB / ( N - 2 * RVM_VCEGAM10_M ) );
    
        double f = sqrt( 12.0 * ( RVM_VCEGAM10_M - 1 ) / ( RVM_VCEGAM10_M + 1 ) );
    
        dRVM = dSigamB / dRavg * f;
      }
    
      return( dRVM );
    }
    
    /** Attaches the input bitstream to the stream in the output NAL unit
        Updates rNalu to contain concatenated bitstream. rpcBitstreamRedirect is cleared at the end of this function call.
     *  \param codedSliceData contains the coded slice data (bitstream) to be concatenated to rNalu
     *  \param rNalu          target NAL unit
     */
    void EncGOP::xAttachSliceDataToNalUnit (OutputNALUnit& rNalu, OutputBitstream* codedSliceData)
    {
      // Byte-align
      rNalu.m_Bitstream.writeByteAlignment();   // Slice header byte-alignment
    
      // Perform bitstream concatenation
      if (codedSliceData->getNumberOfWrittenBits() > 0)
      {
        rNalu.m_Bitstream.addSubstream(codedSliceData);
      }
      codedSliceData->clear();
    }
    
    
    
    void EncGOP::arrangeCompositeReference(Slice* pcSlice, PicList& rcListPic, int pocCurr)
    {
      Picture* curPic = NULL;
      PicList::iterator  iterPic = rcListPic.begin();
      const PreCalcValues *pcv = pcSlice->getPPS()->pcv;
      m_bgPOC = pocCurr + 1;
      if (m_picBg->getSpliceFull())
      {
        return;
      }
      while (iterPic != rcListPic.end())
      {
        curPic = *(iterPic++);
        if (curPic->getPOC() == pocCurr)
        {
          break;
        }
      }
    
      if (pcSlice->isIRAP())
    
      {
        return;
      }
    
      int width = pcv->lumaWidth;
      int height = pcv->lumaHeight;
      int stride = curPic->getOrigBuf().get(COMPONENT_Y).stride;
      int cStride = curPic->getOrigBuf().get(COMPONENT_Cb).stride;
      Pel* curLumaAddr = curPic->getOrigBuf().get(COMPONENT_Y).buf;
      Pel* curCbAddr = curPic->getOrigBuf().get(COMPONENT_Cb).buf;
      Pel* curCrAddr = curPic->getOrigBuf().get(COMPONENT_Cr).buf;
      Pel* bgOrgLumaAddr = m_picOrig->getOrigBuf().get(COMPONENT_Y).buf;
      Pel* bgOrgCbAddr = m_picOrig->getOrigBuf().get(COMPONENT_Cb).buf;
      Pel* bgOrgCrAddr = m_picOrig->getOrigBuf().get(COMPONENT_Cr).buf;
      int cuMaxWidth = pcv->maxCUWidth;
      int cuMaxHeight = pcv->maxCUHeight;
      int maxReplace = (pcv->sizeInCtus) / 2;
      maxReplace = maxReplace < 1 ? 1 : maxReplace;
      typedef struct tagCostStr
      {
        double cost;
        int ctuIdx;
      }CostStr;
      CostStr* minCtuCost = new CostStr[maxReplace];
      for (int i = 0; i < maxReplace; i++)
      {
        minCtuCost[i].cost = 1e10;
        minCtuCost[i].ctuIdx = -1;
      }
      int bitIncrementY = pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8;
      int bitIncrementUV = pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 8;
      for (int y = 0; y < height; y += cuMaxHeight)
      {
        for (int x = 0; x < width; x += cuMaxWidth)
        {
          double lcuDist = 0.0;
          double lcuDistCb = 0.0;
          double lcuDistCr = 0.0;
          int    realPixelCnt = 0;
          double lcuCost = 1e10;
          int largeDist = 0;
    
          for (int tmpy = 0; tmpy < cuMaxHeight; tmpy++)
          {
            if (y + tmpy >= height)
            {
              break;
            }
            for (int tmpx = 0; tmpx < cuMaxWidth; tmpx++)
            {
              if (x + tmpx >= width)
              {
                break;
              }
    
              realPixelCnt++;
              lcuDist += abs(curLumaAddr[(y + tmpy)*stride + x + tmpx] - bgOrgLumaAddr[(y + tmpy)*stride + x + tmpx]);
              if (abs(curLumaAddr[(y + tmpy)*stride + x + tmpx] - bgOrgLumaAddr[(y + tmpy)*stride + x + tmpx]) >(20 << bitIncrementY))
              {
                largeDist++;
              }
    
              if (tmpy % 2 == 0 && tmpx % 2 == 0)
              {
                lcuDistCb += abs(curCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] - bgOrgCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2]);
                lcuDistCr += abs(curCrAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] - bgOrgCrAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2]);
              }
            }
          }
    
          //Test the vertical or horizontal edge for background patches candidates
          int yInLCU = y / cuMaxHeight;
          int xInLCU = x / cuMaxWidth;
          int iLCUIdx = yInLCU * pcv->widthInCtus + xInLCU;
          if ((largeDist / (double)realPixelCnt < 0.01 &&lcuDist / realPixelCnt < (3.5 * (1 << bitIncrementY)) && lcuDistCb / realPixelCnt < (0.5 * (1 << bitIncrementUV)) && lcuDistCr / realPixelCnt < (0.5 * (1 << bitIncrementUV)) && m_picBg->getSpliceIdx(iLCUIdx) == 0))
          {
            lcuCost = lcuDist / realPixelCnt + lcuDistCb / realPixelCnt + lcuDistCr / realPixelCnt;
            //obtain the maxReplace smallest cost
            //1) find the largest cost in the maxReplace candidates
            for (int i = 0; i < maxReplace - 1; i++)
            {
              if (minCtuCost[i].cost > minCtuCost[i + 1].cost)
              {
                swap(minCtuCost[i].cost, minCtuCost[i + 1].cost);
                swap(minCtuCost[i].ctuIdx, minCtuCost[i + 1].ctuIdx);
              }
            }
            // 2) compare the current cost with the largest cost
            if (lcuCost < minCtuCost[maxReplace - 1].cost)
            {
              minCtuCost[maxReplace - 1].cost = lcuCost;
              minCtuCost[maxReplace - 1].ctuIdx = iLCUIdx;
            }
          }
        }
      }
    
      // modify QP for background CTU
      {
        for (int i = 0; i < maxReplace; i++)
        {
          if (minCtuCost[i].ctuIdx != -1)
          {
            m_picBg->setSpliceIdx(minCtuCost[i].ctuIdx, pocCurr);
          }
        }
      }
      delete[]minCtuCost;
    }
    
    void EncGOP::updateCompositeReference(Slice* pcSlice, PicList& rcListPic, int pocCurr)
    {
      Picture* curPic = NULL;
      const PreCalcValues *pcv = pcSlice->getPPS()->pcv;
      PicList::iterator  iterPic = rcListPic.begin();
      iterPic = rcListPic.begin();
      while (iterPic != rcListPic.end())
      {
        curPic = *(iterPic++);
        if (curPic->getPOC() == pocCurr)
        {
          break;
        }
      }
      assert(curPic->getPOC() == pocCurr);
    
      int width = pcv->lumaWidth;
      int height = pcv->lumaHeight;
      int stride = curPic->getRecoBuf().get(COMPONENT_Y).stride;
      int cStride = curPic->getRecoBuf().get(COMPONENT_Cb).stride;
    
      Pel* bgLumaAddr = m_picBg->getRecoBuf().get(COMPONENT_Y).buf;
      Pel* bgCbAddr = m_picBg->getRecoBuf().get(COMPONENT_Cb).buf;
      Pel* bgCrAddr = m_picBg->getRecoBuf().get(COMPONENT_Cr).buf;
      Pel* curLumaAddr = curPic->getRecoBuf().get(COMPONENT_Y).buf;
      Pel* curCbAddr = curPic->getRecoBuf().get(COMPONENT_Cb).buf;
      Pel* curCrAddr = curPic->getRecoBuf().get(COMPONENT_Cr).buf;
    
      int maxCuWidth = pcv->maxCUWidth;
      int maxCuHeight = pcv->maxCUHeight;
    
      // Update background reference
    
      if (pcSlice->isIRAP())//(pocCurr == 0)
    
        curPic->extendPicBorder( pcSlice->getPPS() );
    
        curPic->setBorderExtension(true);
    
        m_picBg->getRecoBuf().copyFrom(curPic->getRecoBuf());
        m_picOrig->getOrigBuf().copyFrom(curPic->getOrigBuf());
      }
      else
      {
        //cout << "update B" << pocCurr << endl;
        for (int y = 0; y < height; y += maxCuHeight)
        {
          for (int x = 0; x < width; x += maxCuWidth)
          {
            if (m_picBg->getSpliceIdx((y / maxCuHeight)*pcv->widthInCtus + x / maxCuWidth) == pocCurr)
            {
              for (int tmpy = 0; tmpy < maxCuHeight; tmpy++)
              {
                if (y + tmpy >= height)
                {
                  break;
                }
                for (int tmpx = 0; tmpx < maxCuWidth; tmpx++)
                {
                  if (x + tmpx >= width)
                  {
                    break;
                  }
                  bgLumaAddr[(y + tmpy)*stride + x + tmpx] = curLumaAddr[(y + tmpy)*stride + x + tmpx];
                  if (tmpy % 2 == 0 && tmpx % 2 == 0)
                  {
                    bgCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] = curCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2];
                    bgCrAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] = curCrAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2];
                  }
                }
              }
            }
          }
        }
        m_picBg->setBorderExtension(false);
    
        m_picBg->extendPicBorder( pcSlice->getPPS() );
    
        curPic->extendPicBorder( pcSlice->getPPS() );
    
        curPic->setBorderExtension(true);
        m_picOrig->getOrigBuf().copyFrom(curPic->getOrigBuf());
    
        m_picBg->setBorderExtension(false);
    
        m_picBg->extendPicBorder( pcSlice->getPPS() );
    
    void EncGOP::applyDeblockingFilterMetric( Picture* pcPic, uint32_t uiNumSlices )
    {
      PelBuf cPelBuf = pcPic->getRecoBuf().get( COMPONENT_Y );
      Pel* Rec    = cPelBuf.buf;
      const int  stride = cPelBuf.stride;
      const uint32_t picWidth = cPelBuf.width;
      const uint32_t picHeight = cPelBuf.height;
    
      Pel* tempRec = Rec;
      const Slice* pcSlice = pcPic->slices[0];
    
      const uint32_t log2maxTB = pcSlice->getSPS()->getLog2MaxTbSize();
      const uint32_t maxTBsize = (1<<log2maxTB);
    
      const uint32_t minBlockArtSize = 8;
      const uint32_t noCol = (picWidth>>log2maxTB);
      const uint32_t noRows = (picHeight>>log2maxTB);
      CHECK(!(noCol > 1), "Unspecified error");
      CHECK(!(noRows > 1), "Unspecified error");
      std::vector<uint64_t> colSAD(noCol,  uint64_t(0));
      std::vector<uint64_t> rowSAD(noRows, uint64_t(0));
      uint32_t colIdx = 0;
      uint32_t rowIdx = 0;
      Pel p0, p1, p2, q0, q1, q2;
    
      int qp = pcSlice->getSliceQp();
      const int bitDepthLuma=pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA);
      int bitdepthScale = 1 << (bitDepthLuma-8);
      int beta = LoopFilter::getBeta( qp ) * bitdepthScale;
      const int thr2 = (beta>>2);
      const int thr1 = 2*bitdepthScale;
      uint32_t a = 0;
    
      if (maxTBsize > minBlockArtSize)
      {
        // Analyze vertical artifact edges
        for(int c = maxTBsize; c < picWidth; c += maxTBsize)
        {
          for(int r = 0; r < picHeight; r++)
          {
            p2 = Rec[c-3];
            p1 = Rec[c-2];
            p0 = Rec[c-1];
            q0 = Rec[c];
            q1 = Rec[c+1];
            q2 = Rec[c+2];
            a = ((abs(p2-(p1<<1)+p0)+abs(q0-(q1<<1)+q2))<<1);
            if ( thr1 < a && a < thr2)
            {
              colSAD[colIdx] += abs(p0 - q0);
            }
            Rec += stride;
          }
          colIdx++;
          Rec = tempRec;
        }
    
        // Analyze horizontal artifact edges
        for(int r = maxTBsize; r < picHeight; r += maxTBsize)
        {
          for(int c = 0; c < picWidth; c++)
          {
            p2 = Rec[c + (r-3)*stride];
            p1 = Rec[c + (r-2)*stride];
            p0 = Rec[c + (r-1)*stride];
            q0 = Rec[c + r*stride];
            q1 = Rec[c + (r+1)*stride];
            q2 = Rec[c + (r+2)*stride];
            a = ((abs(p2-(p1<<1)+p0)+abs(q0-(q1<<1)+q2))<<1);
            if (thr1 < a && a < thr2)
            {
              rowSAD[rowIdx] += abs(p0 - q0);
            }
          }
          rowIdx++;
        }
      }
    
      uint64_t colSADsum = 0;
      uint64_t rowSADsum = 0;
      for(int c = 0; c < noCol-1; c++)
      {
        colSADsum += colSAD[c];
      }
      for(int r = 0; r < noRows-1; r++)
      {
        rowSADsum += rowSAD[r];
      }
    
      colSADsum <<= 10;
      rowSADsum <<= 10;
      colSADsum /= (noCol-1);
      colSADsum /= picHeight;
      rowSADsum /= (noRows-1);
      rowSADsum /= picWidth;
    
      uint64_t avgSAD = ((colSADsum + rowSADsum)>>1);
      avgSAD >>= (bitDepthLuma-8);
    
      if ( avgSAD > 2048 )
      {
        avgSAD >>= 9;
        int offset = Clip3(2,6,(int)avgSAD);
        for (int i=0; i<uiNumSlices; i++)
        {
          Slice* pcLocalSlice = pcPic->slices[i];
          pcLocalSlice->setDeblockingFilterOverrideFlag   ( true);
          pcLocalSlice->setDeblockingFilterDisable        ( false);
          pcLocalSlice->setDeblockingFilterBetaOffsetDiv2 ( offset );
          pcLocalSlice->setDeblockingFilterTcOffsetDiv2   ( offset );
    
          pcLocalSlice->setDeblockingFilterCbBetaOffsetDiv2 ( offset );
          pcLocalSlice->setDeblockingFilterCbTcOffsetDiv2   ( offset );
          pcLocalSlice->setDeblockingFilterCrBetaOffsetDiv2 ( offset );
          pcLocalSlice->setDeblockingFilterCrTcOffsetDiv2   ( offset );
    
        }
      }
      else
      {
        for (int i=0; i<uiNumSlices; i++)
        {
          Slice* pcLocalSlice = pcPic->slices[i];
          const PPS* pcPPS = pcSlice->getPPS();
          pcLocalSlice->setDeblockingFilterOverrideFlag  ( false);
          pcLocalSlice->setDeblockingFilterDisable       ( pcPPS->getPPSDeblockingFilterDisabledFlag() );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if DB_PARAM_TID
          int betaIdx = Clip3(0, (int)pcPPS->getDeblockingFilterBetaOffsetDiv2().size() - 1, (int)pcLocalSlice->getTLayer() + (pcLocalSlice->isIntra() ? 0 : 1));
          int tcIdx = Clip3(0, (int)pcPPS->getDeblockingFilterTcOffsetDiv2().size() - 1, (int)pcLocalSlice->getTLayer() + (pcLocalSlice->isIntra() ? 0 : 1));
          pcLocalSlice->setDeblockingFilterBetaOffsetDiv2( pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx] );
          pcLocalSlice->setDeblockingFilterTcOffsetDiv2  ( pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]   );
    
          pcLocalSlice->setDeblockingFilterCbBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
          pcLocalSlice->setDeblockingFilterCbTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
          pcLocalSlice->setDeblockingFilterCrBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
          pcLocalSlice->setDeblockingFilterCrTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
    #else
    
          pcLocalSlice->setDeblockingFilterBetaOffsetDiv2( pcPPS->getDeblockingFilterBetaOffsetDiv2() );
          pcLocalSlice->setDeblockingFilterTcOffsetDiv2  ( pcPPS->getDeblockingFilterTcOffsetDiv2()   );
    
          pcLocalSlice->setDeblockingFilterCbBetaOffsetDiv2 ( pcPPS->getDeblockingFilterCbBetaOffsetDiv2() );
          pcLocalSlice->setDeblockingFilterCbTcOffsetDiv2   ( pcPPS->getDeblockingFilterCbTcOffsetDiv2() );
          pcLocalSlice->setDeblockingFilterCrBetaOffsetDiv2 ( pcPPS->getDeblockingFilterCrBetaOffsetDiv2() );
          pcLocalSlice->setDeblockingFilterCrTcOffsetDiv2   ( pcPPS->getDeblockingFilterCrTcOffsetDiv2() );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if DB_PARAM_TID
    void EncGOP::applyDeblockingFilterParameterSelection( Picture* pcPic, Slice* pcSlice, const uint32_t numSlices, const int gopID )
    {
      const PPS* pcPPS = pcPic->slices[0]->getPPS();
      for (int i = 0; i<numSlices; i++)
      {
        Slice*      pcSlice = pcPic->slices[i];
        pcSlice->setDeblockingFilterOverrideFlag(false);
        pcSlice->setDeblockingFilterDisable(pcPPS->getPPSDeblockingFilterDisabledFlag());
        int betaIdx = Clip3(0, (int)pcPPS->getDeblockingFilterBetaOffsetDiv2().size() - 1, (int)pcSlice->getTLayer() + (pcSlice->isIntra() ? 0 : 1));
        int tcIdx = Clip3(0, (int)pcPPS->getDeblockingFilterTcOffsetDiv2().size() - 1, (int)pcSlice->getTLayer() + (pcSlice->isIntra() ? 0 : 1));
        pcSlice->setDeblockingFilterBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
        pcSlice->setDeblockingFilterTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
    
        pcSlice->setDeblockingFilterCbBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
        pcSlice->setDeblockingFilterCbTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
        pcSlice->setDeblockingFilterCrBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
        pcSlice->setDeblockingFilterCrTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
      }
    }
    #endif
    
    
    #if W0038_DB_OPT
    void EncGOP::applyDeblockingFilterParameterSelection( Picture* pcPic, const uint32_t numSlices, const int gopID )
    {
      enum DBFltParam
      {
        DBFLT_PARAM_AVAILABLE = 0,
        DBFLT_DISABLE_FLAG,
        DBFLT_BETA_OFFSETD2,
        DBFLT_TC_OFFSETD2,
        //NUM_DBFLT_PARAMS
      };
      const int MAX_BETA_OFFSET = 3;
      const int MIN_BETA_OFFSET = -3;
      const int MAX_TC_OFFSET = 3;
      const int MIN_TC_OFFSET = -3;
    
      PelUnitBuf reco = pcPic->getRecoBuf();
    
    
      const int currQualityLayer = (!pcPic->slices[0]->isIRAP()) ? m_pcCfg->getGOPEntry(gopID).m_temporalId+1 : 0;
    
      CHECK(!(currQualityLayer <MAX_ENCODER_DEBLOCKING_QUALITY_LAYERS), "Unspecified error");
    
      CodingStructure& cs = *pcPic->cs;
    
      if(!m_pcDeblockingTempPicYuv)
      {
        m_pcDeblockingTempPicYuv = new PelStorage;
        m_pcDeblockingTempPicYuv->create( cs.area );
        memset(m_DBParam, 0, sizeof(m_DBParam));
      }
    
      //preserve current reconstruction
      m_pcDeblockingTempPicYuv->copyFrom ( reco );
    
      const bool bNoFiltering      = m_DBParam[currQualityLayer][DBFLT_PARAM_AVAILABLE] && m_DBParam[currQualityLayer][DBFLT_DISABLE_FLAG]==false /*&& pcPic->getTLayer()==0*/;
      const int  maxBetaOffsetDiv2 = bNoFiltering? Clip3(MIN_BETA_OFFSET, MAX_BETA_OFFSET, m_DBParam[currQualityLayer][DBFLT_BETA_OFFSETD2]+1) : MAX_BETA_OFFSET;
      const int  minBetaOffsetDiv2 = bNoFiltering? Clip3(MIN_BETA_OFFSET, MAX_BETA_OFFSET, m_DBParam[currQualityLayer][DBFLT_BETA_OFFSETD2]-1) : MIN_BETA_OFFSET;
      const int  maxTcOffsetDiv2   = bNoFiltering? Clip3(MIN_TC_OFFSET, MAX_TC_OFFSET, m_DBParam[currQualityLayer][DBFLT_TC_OFFSETD2]+2)       : MAX_TC_OFFSET;
      const int  minTcOffsetDiv2   = bNoFiltering? Clip3(MIN_TC_OFFSET, MAX_TC_OFFSET, m_DBParam[currQualityLayer][DBFLT_TC_OFFSETD2]-2)       : MIN_TC_OFFSET;
    
      uint64_t distBetaPrevious      = std::numeric_limits<uint64_t>::max();
      uint64_t distMin               = std::numeric_limits<uint64_t>::max();
      bool   bDBFilterDisabledBest = true;
      int    betaOffsetDiv2Best    = 0;
      int    tcOffsetDiv2Best      = 0;
    
      for(int betaOffsetDiv2=maxBetaOffsetDiv2; betaOffsetDiv2>=minBetaOffsetDiv2; betaOffsetDiv2--)
      {
        uint64_t distTcMin = std::numeric_limits<uint64_t>::max();
        for(int tcOffsetDiv2=maxTcOffsetDiv2; tcOffsetDiv2 >= minTcOffsetDiv2; tcOffsetDiv2--)
        {
          for (int i=0; i<numSlices; i++)
          {
            Slice* pcSlice = pcPic->slices[i];
            pcSlice->setDeblockingFilterOverrideFlag  ( true);
            pcSlice->setDeblockingFilterDisable       ( false);
            pcSlice->setDeblockingFilterBetaOffsetDiv2( betaOffsetDiv2 );
            pcSlice->setDeblockingFilterTcOffsetDiv2  ( tcOffsetDiv2 );
    
            pcSlice->setDeblockingFilterCbBetaOffsetDiv2( betaOffsetDiv2 );
            pcSlice->setDeblockingFilterCbTcOffsetDiv2  ( tcOffsetDiv2 );
            pcSlice->setDeblockingFilterCrBetaOffsetDiv2( betaOffsetDiv2 );
            pcSlice->setDeblockingFilterCrTcOffsetDiv2  ( tcOffsetDiv2 );
    
          }
    
          // restore reconstruction
          reco.copyFrom( *m_pcDeblockingTempPicYuv );
    
          const uint64_t dist = preLoopFilterPicAndCalcDist( pcPic );
    
          if(dist < distMin)
          {
            distMin = dist;
            bDBFilterDisabledBest = false;
            betaOffsetDiv2Best  = betaOffsetDiv2;
            tcOffsetDiv2Best = tcOffsetDiv2;
          }
          if(dist < distTcMin)
          {
            distTcMin = dist;
          }
          else if(tcOffsetDiv2 <-2)
          {
            break;
          }
        }
        if(betaOffsetDiv2<-1 && distTcMin >= distBetaPrevious)
        {
          break;
        }
        distBetaPrevious = distTcMin;
      }
    
      //update:
      m_DBParam[currQualityLayer][DBFLT_PARAM_AVAILABLE] = 1;
      m_DBParam[currQualityLayer][DBFLT_DISABLE_FLAG]    = bDBFilterDisabledBest;
      m_DBParam[currQualityLayer][DBFLT_BETA_OFFSETD2]   = betaOffsetDiv2Best;
      m_DBParam[currQualityLayer][DBFLT_TC_OFFSETD2]     = tcOffsetDiv2Best;
    
      // restore reconstruction
      reco.copyFrom( *m_pcDeblockingTempPicYuv );
    
      const PPS* pcPPS = pcPic->slices[0]->getPPS();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if DB_PARAM_TID
      int betaIdx = Clip3(0, (int)pcPPS->getDeblockingFilterBetaOffsetDiv2().size() - 1, (int)pcPic->slices[0]->getTLayer() + (pcPic->slices[0]->isIntra() ? 0 : 1));
      int tcIdx = Clip3(0, (int)pcPPS->getDeblockingFilterTcOffsetDiv2().size() - 1, (int)pcPic->slices[0]->getTLayer()) + (pcPic->slices[0]->isIntra() ? 0 : 1);
    #endif
    
      if(bDBFilterDisabledBest)
      {
        for (int i=0; i<numSlices; i++)
        {
          Slice* pcSlice = pcPic->slices[i];
          pcSlice->setDeblockingFilterOverrideFlag( true);
          pcSlice->setDeblockingFilterDisable     ( true);
        }
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if DB_PARAM_TID
      else if (betaOffsetDiv2Best == pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx] && tcOffsetDiv2Best == pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx])
    #else
    
      else if(betaOffsetDiv2Best == pcPPS->getDeblockingFilterBetaOffsetDiv2() &&  tcOffsetDiv2Best == pcPPS->getDeblockingFilterTcOffsetDiv2())
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
      {
        for (int i=0; i<numSlices; i++)
        {
          Slice*      pcSlice = pcPic->slices[i];
          pcSlice->setDeblockingFilterOverrideFlag   ( false);
          pcSlice->setDeblockingFilterDisable        ( pcPPS->getPPSDeblockingFilterDisabledFlag() );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if DB_PARAM_TID
          pcSlice->setDeblockingFilterBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
          pcSlice->setDeblockingFilterTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
          pcSlice->setDeblockingFilterCbBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
          pcSlice->setDeblockingFilterCbTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
          pcSlice->setDeblockingFilterCrBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2()[betaIdx]);
          pcSlice->setDeblockingFilterCrTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2()[tcIdx]);
    #else
    
          pcSlice->setDeblockingFilterBetaOffsetDiv2 ( pcPPS->getDeblockingFilterBetaOffsetDiv2() );
          pcSlice->setDeblockingFilterTcOffsetDiv2   ( pcPPS->getDeblockingFilterTcOffsetDiv2()   );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          pcSlice->setDeblockingFilterCbBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2());
          pcSlice->setDeblockingFilterCbTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2());
          pcSlice->setDeblockingFilterCrBetaOffsetDiv2(pcPPS->getDeblockingFilterBetaOffsetDiv2());
          pcSlice->setDeblockingFilterCrTcOffsetDiv2(pcPPS->getDeblockingFilterTcOffsetDiv2());
    #endif
    
        }
      }
      else
      {
        for (int i=0; i<numSlices; i++)
        {
          Slice* pcSlice = pcPic->slices[i];
          pcSlice->setDeblockingFilterOverrideFlag   ( true);
          pcSlice->setDeblockingFilterDisable        ( false );
          pcSlice->setDeblockingFilterBetaOffsetDiv2 ( betaOffsetDiv2Best);
          pcSlice->setDeblockingFilterTcOffsetDiv2   ( tcOffsetDiv2Best);
    
          pcSlice->setDeblockingFilterCbBetaOffsetDiv2 ( betaOffsetDiv2Best);
          pcSlice->setDeblockingFilterCbTcOffsetDiv2   ( tcOffsetDiv2Best);
          pcSlice->setDeblockingFilterCrBetaOffsetDiv2 ( betaOffsetDiv2Best);
          pcSlice->setDeblockingFilterCrTcOffsetDiv2   ( tcOffsetDiv2Best);
    
    bool EncGOP::xCheckMaxTidILRefPics(Picture* refPic, bool currentPicIsIRAP)
    {
      const int maxTidILRefPicsPlus1 = m_pcCfg->getVPSParameters().m_maxTidILRefPicsPlus1;
    
      // -1 means not set
      if (maxTidILRefPicsPlus1 < 0)
      {
        return true;
      }
    
      // 0 allows only IRAP pictures to use inter-layer prediction
      if (maxTidILRefPicsPlus1 == 0)
      {
        return currentPicIsIRAP;
      }
    
      // all other cases filter by temporalID
      return ( refPic->temporalId < maxTidILRefPicsPlus1 );
    }
    
    
    void EncGOP::xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicList& rcListPic, const ReferencePictureList *rpl0, const ReferencePictureList *rpl1 )
    {
      Picture* rpcPic;
      int pocCycle = 0;
    
      Picture* pic = slice->getPic();
      const VPS* vps = slice->getPic()->cs->vps;
      int layerIdx = vps == nullptr ? 0 : vps->getGeneralLayerIdx( pic->layerId );
    
      bool isIntraLayerPredAllowed = vps->getIndependentLayerFlag(layerIdx) || (vps->getPredDirection(slice->getTLayer()) != 1);
      bool isInterLayerPredAllowed = !vps->getIndependentLayerFlag(layerIdx) && (vps->getPredDirection(slice->getTLayer()) != 2);
    
      ReferencePictureList* pLocalRPL0 = slice->getLocalRPL0();
      *pLocalRPL0 = ReferencePictureList( slice->getSPS()->getInterLayerPresentFlag() );
    
      uint32_t numOfSTRPL0 = 0;
      uint32_t numOfLTRPL0 = 0;
      uint32_t numOfILRPL0 = 0;
      uint32_t numOfRefPic = rpl0->getNumberOfShorttermPictures() + rpl0->getNumberOfLongtermPictures();
      uint32_t refPicIdxL0 = 0;
    
    
        for (int ii = 0; ii < numOfRefPic; ii++)
    
          // loop through all pictures in the reference picture buffer
          PicList::iterator iterPic = rcListPic.begin();
          bool isAvailable = false;
    
          pocCycle = 1 << (slice->getSPS()->getBitsForPOC());
          while (iterPic != rcListPic.end())
    
            rpcPic = *(iterPic++);
    
            if (rpcPic->layerId == pic->layerId)
    
    #if JVET_S0045_SIGN
              if (!rpl0->isRefPicLongterm(ii) && rpcPic->referenced
                  && rpcPic->getPOC() == slice->getPOC() + rpl0->getRefPicIdentifier(ii)
                  && !slice->isPocRestrictedByDRAP(rpcPic->getPOC(), rpcPic->precedingDRAP))
    #else
    
              if (!rpl0->isRefPicLongterm(ii) && rpcPic->referenced && rpcPic->getPOC() == slice->getPOC() - rpl0->getRefPicIdentifier(ii) && !slice->isPocRestrictedByDRAP(rpcPic->getPOC(), rpcPic->precedingDRAP))
    
              {
                isAvailable = true;
                break;
              }
              else if (rpl0->isRefPicLongterm(ii) && rpcPic->referenced && (rpcPic->getPOC() & (pocCycle - 1)) == rpl0->getRefPicIdentifier(ii) && !slice->isPocRestrictedByDRAP(rpcPic->getPOC(), rpcPic->precedingDRAP))
              {
                isAvailable = true;
                break;
              }
    
          if (isAvailable)
          {
            pLocalRPL0->setRefPicIdentifier(refPicIdxL0, rpl0->getRefPicIdentifier(ii), rpl0->isRefPicLongterm(ii), false, NOT_VALID);
            refPicIdxL0++;
            numOfSTRPL0 = numOfSTRPL0 + ((rpl0->isRefPicLongterm(ii)) ? 0 : 1);
            numOfLTRPL0 += (rpl0->isRefPicLongterm(ii) && !rpl0->isInterLayerRefPic(ii)) ? 1 : 0;
            isAvailable = false;
          }
    
        }
      }
    
      // inter-layer reference pictures are added to the end of the reference picture list
    
      if (layerIdx && vps && !vps->getAllIndependentLayersFlag() && isInterLayerPredAllowed)
    
      {
        numOfRefPic = rpl0->getNumberOfInterLayerPictures() ? rpl0->getNumberOfInterLayerPictures() : m_pcEncLib->getNumRefLayers( layerIdx );
    
        for( int ii = 0; ii < numOfRefPic; ii++ )
        {
          // loop through all pictures in the reference picture buffer
          PicList::iterator iterPic = rcListPic.begin();
    
    
          while( iterPic != rcListPic.end() && ii < numOfRefPic )
    
          {
            rpcPic = *( iterPic++ );
            int refLayerIdx = vps->getGeneralLayerIdx( rpcPic->layerId );
    
            if (rpcPic->referenced && rpcPic->getPOC() == pic->getPOC() && vps->getDirectRefLayerFlag(layerIdx, refLayerIdx)
                && xCheckMaxTidILRefPics(rpcPic, slice->isIRAP()) )
    
              pLocalRPL0->setRefPicIdentifier( refPicIdxL0, 0, true, true, vps->getInterLayerRefIdc( layerIdx, refLayerIdx ) );
              refPicIdxL0++;
              numOfILRPL0++;
    
            }
          }
        }
      }
    
      if( slice->getEnableDRAPSEI() )
      {
        pLocalRPL0->setNumberOfShorttermPictures( numOfSTRPL0 );
        pLocalRPL0->setNumberOfLongtermPictures( numOfLTRPL0 );
        pLocalRPL0->setNumberOfInterLayerPictures( numOfILRPL0 );
    
        if( !slice->isIRAP() && !slice->isPOCInRefPicList( pLocalRPL0, slice->getAssociatedIRAPPOC() ) )
        {
          if( slice->getUseLTforDRAP() && !slice->isPOCInRefPicList( rpl1, slice->getAssociatedIRAPPOC() ) )
          {
            // Adding associated IRAP as longterm picture
            pLocalRPL0->setRefPicIdentifier( refPicIdxL0, slice->getAssociatedIRAPPOC(), true, false, 0 );
            refPicIdxL0++;
            numOfLTRPL0++;
          }
          else
          {
            // Adding associated IRAP as shortterm picture
    
    #if JVET_S0045_SIGN
            pLocalRPL0->setRefPicIdentifier(refPicIdxL0, slice->getAssociatedIRAPPOC() - slice->getPOC(), false, false, 0);
    #else
    
            pLocalRPL0->setRefPicIdentifier( refPicIdxL0, slice->getPOC() - slice->getAssociatedIRAPPOC(), false, false, 0 );
    
            refPicIdxL0++;
            numOfSTRPL0++;
          }
        }
      }
    
      ReferencePictureList* pLocalRPL1 = slice->getLocalRPL1();
      *pLocalRPL1 = ReferencePictureList( slice->getSPS()->getInterLayerPresentFlag() );
    
      uint32_t numOfSTRPL1 = 0;
      uint32_t numOfLTRPL1 = 0;
      uint32_t numOfILRPL1 = 0;
      numOfRefPic = rpl1->getNumberOfShorttermPictures() + rpl1->getNumberOfLongtermPictures();
      uint32_t refPicIdxL1 = 0;
    
    
        for (int ii = 0; ii < numOfRefPic; ii++)
    
          // loop through all pictures in the reference picture buffer
          PicList::iterator iterPic = rcListPic.begin();
          bool isAvailable = false;
          pocCycle = 1 << (slice->getSPS()->getBitsForPOC());
          while (iterPic != rcListPic.end())
    
            rpcPic = *(iterPic++);
            if (rpcPic->layerId == pic->layerId)
    
    #if JVET_S0045_SIGN
              if (!rpl1->isRefPicLongterm(ii) && rpcPic->referenced
                  && rpcPic->getPOC() == slice->getPOC() + rpl1->getRefPicIdentifier(ii)
                  && !slice->isPocRestrictedByDRAP(rpcPic->getPOC(), rpcPic->precedingDRAP))
    #else
    
              if (!rpl1->isRefPicLongterm(ii) && rpcPic->referenced && rpcPic->getPOC() == slice->getPOC() - rpl1->getRefPicIdentifier(ii) && !slice->isPocRestrictedByDRAP(rpcPic->getPOC(), rpcPic->precedingDRAP))
    
              {
                isAvailable = true;
                break;
              }
              else if (rpl1->isRefPicLongterm(ii) && rpcPic->referenced && (rpcPic->getPOC() & (pocCycle - 1)) == rpl1->getRefPicIdentifier(ii) && !slice->isPocRestrictedByDRAP(rpcPic->getPOC(), rpcPic->precedingDRAP))
              {
                isAvailable = true;
                break;
              }
    
          if (isAvailable)
          {
            pLocalRPL1->setRefPicIdentifier(refPicIdxL1, rpl1->getRefPicIdentifier(ii), rpl1->isRefPicLongterm(ii), false, NOT_VALID);
            refPicIdxL1++;
            numOfSTRPL1 = numOfSTRPL1 + ((rpl1->isRefPicLongterm(ii)) ? 0 : 1);
            numOfLTRPL1 += (rpl1->isRefPicLongterm(ii) && !rpl1->isInterLayerRefPic(ii)) ? 1 : 0;
            isAvailable = false;
          }
    
      // inter-layer reference pictures are added to the end of the reference picture list
    
      if (layerIdx && vps && !vps->getAllIndependentLayersFlag() && isInterLayerPredAllowed)
    
      {
        numOfRefPic = rpl1->getNumberOfInterLayerPictures() ? rpl1->getNumberOfInterLayerPictures() : m_pcEncLib->getNumRefLayers( layerIdx );
    
        for( int ii = 0; ii < numOfRefPic; ii++ )
        {
          // loop through all pictures in the reference picture buffer
          PicList::iterator iterPic = rcListPic.begin();
    
    
          while( iterPic != rcListPic.end() && ii < numOfRefPic )
    
          {
            rpcPic = *( iterPic++ );
            int refLayerIdx = vps->getGeneralLayerIdx( rpcPic->layerId );
    
            if (rpcPic->referenced && rpcPic->getPOC() == pic->getPOC() && vps->getDirectRefLayerFlag(layerIdx, refLayerIdx)
                && xCheckMaxTidILRefPics( rpcPic, slice->isIRAP() ) )
    
            {
              pLocalRPL1->setRefPicIdentifier( refPicIdxL1, 0, true, true, vps->getInterLayerRefIdc( layerIdx, refLayerIdx ) );
              refPicIdxL1++;
              numOfILRPL1++;
    
            }
          }
        }
      }
    
      //Copy from L1 if we have less than active ref pic
      int numOfNeedToFill = rpl0->getNumberOfActivePictures() - (numOfLTRPL0 + numOfSTRPL0);
      bool isDisallowMixedRefPic = ( slice->getSPS()->getAllActiveRplEntriesHasSameSignFlag() ) ? true : false;
      int originalL0StrpNum = numOfSTRPL0;
      int originalL0LtrpNum = numOfLTRPL0;
      int originalL0IlrpNum = numOfILRPL0;
    
      for( int ii = 0; numOfNeedToFill > 0 && ii < ( pLocalRPL1->getNumberOfLongtermPictures() + pLocalRPL1->getNumberOfShorttermPictures() + pLocalRPL1->getNumberOfInterLayerPictures() ); ii++ )
      {
        if( ii <= ( numOfLTRPL1 + numOfSTRPL1 + numOfILRPL1 - 1 ) )
        {
          //Make sure this copy is not already in L0
          bool canIncludeThis = true;
          for( int jj = 0; jj < refPicIdxL0; jj++ )
          {
            if( ( pLocalRPL1->getRefPicIdentifier( ii ) == pLocalRPL0->getRefPicIdentifier( jj ) ) && ( pLocalRPL1->isRefPicLongterm( ii ) == pLocalRPL0->isRefPicLongterm( jj ) ) && pLocalRPL1->getInterLayerRefPicIdx( ii ) == pLocalRPL0->getInterLayerRefPicIdx( jj ) )
            {
              canIncludeThis = false;
            }
    
            bool sameSign = ( pLocalRPL1->getRefPicIdentifier( ii ) > 0 ) == ( pLocalRPL0->getRefPicIdentifier( 0 ) > 0 );
    
            if( isDisallowMixedRefPic && canIncludeThis && !pLocalRPL1->isRefPicLongterm( ii ) && !sameSign )
            {
              canIncludeThis = false;
            }
          }
          if( canIncludeThis )
          {
            pLocalRPL0->setRefPicIdentifier( refPicIdxL0, pLocalRPL1->getRefPicIdentifier( ii ), pLocalRPL1->isRefPicLongterm( ii ), pLocalRPL1->isInterLayerRefPic( ii ), pLocalRPL1->getInterLayerRefPicIdx( ii ) );
            refPicIdxL0++;
            numOfSTRPL0 = numOfSTRPL0 + ( ( pLocalRPL1->isRefPicLongterm( ii ) ) ? 0 : 1 );
            numOfLTRPL0 += ( pLocalRPL1->isRefPicLongterm( ii ) && !pLocalRPL1->isInterLayerRefPic( ii ) ) ? 1 : 0;
            numOfILRPL0 += pLocalRPL1->isInterLayerRefPic( ii ) ? 1 : 0;
            numOfNeedToFill--;
          }
        }
      }
      pLocalRPL0->setNumberOfLongtermPictures( numOfLTRPL0 );
      pLocalRPL0->setNumberOfShorttermPictures( numOfSTRPL0 );
      pLocalRPL0->setNumberOfInterLayerPictures( numOfILRPL0 );
      int numPics = numOfLTRPL0 + numOfSTRPL0;
    
      pLocalRPL0->setNumberOfActivePictures( ( numPics < rpl0->getNumberOfActivePictures() ? numPics : rpl0->getNumberOfActivePictures() ) + numOfILRPL0 );
    
      pLocalRPL0->setLtrpInSliceHeaderFlag( 1 );
    
      slice->setRPL0idx( -1 );
      slice->setRPL0( pLocalRPL0 );
    
      //Copy from L0 if we have less than active ref pic
      numOfNeedToFill = pLocalRPL0->getNumberOfActivePictures() - ( numOfLTRPL1 + numOfSTRPL1 );
    
      for( int ii = 0; numOfNeedToFill > 0 && ii < ( pLocalRPL0->getNumberOfLongtermPictures() + pLocalRPL0->getNumberOfShorttermPictures() + pLocalRPL0->getNumberOfInterLayerPictures() ); ii++ )
      {
        if( ii <= ( originalL0StrpNum + originalL0LtrpNum + originalL0IlrpNum - 1 ) )
        {
          //Make sure this copy is not already in L0
          bool canIncludeThis = true;
          for( int jj = 0; jj < refPicIdxL1; jj++ )
          {
            if( ( pLocalRPL0->getRefPicIdentifier( ii ) == pLocalRPL1->getRefPicIdentifier( jj ) ) && ( pLocalRPL0->isRefPicLongterm( ii ) == pLocalRPL1->isRefPicLongterm( jj ) ) && pLocalRPL0->getInterLayerRefPicIdx( ii ) == pLocalRPL1->getInterLayerRefPicIdx( jj ) )
            {
              canIncludeThis = false;
            }
    
            bool sameSign = ( pLocalRPL0->getRefPicIdentifier( ii ) > 0 ) == ( pLocalRPL1->getRefPicIdentifier( 0 ) > 0 );
    
            if( isDisallowMixedRefPic && canIncludeThis && !pLocalRPL0->isRefPicLongterm( ii ) && !sameSign )
            {
              canIncludeThis = false;
            }
          }
          if( canIncludeThis )
          {
            pLocalRPL1->setRefPicIdentifier( refPicIdxL1, pLocalRPL0->getRefPicIdentifier( ii ), pLocalRPL0->isRefPicLongterm( ii ), pLocalRPL0->isInterLayerRefPic( ii ), pLocalRPL0->getInterLayerRefPicIdx( ii ) );
            refPicIdxL1++;
            numOfSTRPL1 = numOfSTRPL1 + ( ( pLocalRPL0->isRefPicLongterm( ii ) ) ? 0 : 1 );
            numOfLTRPL1 += ( pLocalRPL0->isRefPicLongterm( ii ) && !pLocalRPL0->isInterLayerRefPic( ii ) ) ? 1 : 0;
            numOfLTRPL1 += pLocalRPL0->isInterLayerRefPic( ii ) ? 1 : 0;
            numOfNeedToFill--;
          }
        }
      }
      pLocalRPL1->setNumberOfLongtermPictures( numOfLTRPL1 );
      pLocalRPL1->setNumberOfShorttermPictures( numOfSTRPL1 );
      pLocalRPL1->setNumberOfInterLayerPictures( numOfILRPL1 );
      numPics = numOfLTRPL1 + numOfSTRPL1;
    
      pLocalRPL1->setNumberOfActivePictures( ( isDisallowMixedRefPic ? numPics : ( numPics < rpl1->getNumberOfActivePictures() ? numPics : rpl1->getNumberOfActivePictures() ) ) + numOfILRPL1 );
    
      pLocalRPL1->setLtrpInSliceHeaderFlag( 1 );
    
      slice->setRPL1idx( -1 );
      slice->setRPL1( pLocalRPL1 );
    }