Skip to content
Snippets Groups Projects
EncLib.cpp 95.1 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.
     *
    
    Frank Bossen's avatar
    Frank Bossen committed
     * Copyright (c) 2010-2021, 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     EncLib.cpp
        \brief    encoder class
    */
    #include "EncLib.h"
    
    #include "EncModeCtrl.h"
    #include "AQp.h"
    #include "EncCu.h"
    
    #include "CommonLib/Picture.h"
    #include "CommonLib/CommonDef.h"
    #include "CommonLib/ChromaFormat.h"
    #if ENABLE_SPLIT_PARALLELISM
    #include <omp.h>
    #endif
    
    #include "EncLibCommon.h"
    
    #include "CommonLib/ProfileLevelTier.h"
    
    
    //! \ingroup EncoderLib
    //! \{
    
    // ====================================================================================================================
    // Constructor / destructor / create / destroy
    // ====================================================================================================================
    
    
    EncLib::EncLib( EncLibCommon* encLibCommon )
      : m_cListPic( encLibCommon->getPictureBuffer() )
      , m_cEncALF( encLibCommon->getApsIdStart() )
      , m_spsMap( encLibCommon->getSpsMap() )
      , m_ppsMap( encLibCommon->getPpsMap() )
      , m_apsMap( encLibCommon->getApsMap() )
    
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
      , m_cacheModel()
    #endif
    
      , m_vps( encLibCommon->getVPS() )
    
    {
      m_iPOCLast          = -1;
      m_iNumPicRcvd       =  0;
      m_uiNumAllPicCoded  =  0;
    
      m_iMaxRefPicNum     = 0;
    
    #if ENABLE_SIMD_OPT_BUFFER
      g_pelBufOP.initPelBufOpsX86();
    #endif
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      m_metricTime = std::chrono::milliseconds(0);
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_layerId = NOT_VALID;
    
      m_picIdInGOP = NOT_VALID;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    void EncLib::create( const int layerId )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_layerId = layerId;
    
      m_iPOCLast = m_compositeRefEnabled ? -2 : -1;
    
      // create processing unit classes
      m_cGOPEncoder.        create( );
    
    #if ENABLE_SPLIT_PARALLELISM
    
    #if ENABLE_SPLIT_PARALLELISM
      m_numCuEncStacks  = m_numSplitThreads == 1 ? 1 : NUM_RESERVERD_SPLIT_JOBS;
    #else
      m_numCuEncStacks  = 1;
    #endif
    
      m_cCuEncoder      = new EncCu              [m_numCuEncStacks];
      m_cInterSearch    = new InterSearch        [m_numCuEncStacks];
      m_cIntraSearch    = new IntraSearch        [m_numCuEncStacks];
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_bilateralFilter = new BilateralFilter    [m_numCuEncStacks];
    #endif
    
      m_cTrQuant        = new TrQuant            [m_numCuEncStacks];
      m_CABACEncoder    = new CABACEncoder       [m_numCuEncStacks];
      m_cRdCost         = new RdCost             [m_numCuEncStacks];
      m_CtxCache        = new CtxCache           [m_numCuEncStacks];
    
      for( int jId = 0; jId < m_numCuEncStacks; jId++ )
      {
        m_cCuEncoder[jId].         create( this );
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        m_bilateralFilter[jId].    create();
    #endif
    
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_bilateralFilter.    create();
    #endif
    
    #endif
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
      m_cInterSearch.cacheAssign( &m_cacheModel );
    #endif
    
      m_cLoopFilter.create(floorLog2(m_maxCUWidth) - MIN_CU_LOG2);
    
    Nan Hu's avatar
    Nan Hu committed
      if (!m_bLoopFilterDisable && m_encDbOpt)
    
    Nan Hu's avatar
    Nan Hu committed
        m_cLoopFilter.initEncPicYuvBuffer(m_chromaFormatIDC, Size(getSourceWidth(), getSourceHeight()), getMaxCUWidth());
    
    #if ENABLE_SPLIT_PARALLELISM
    
      m_cReshaper = new EncReshape[m_numCuEncStacks];
    #endif
    
    #if ENABLE_SPLIT_PARALLELISM
    
        for (int jId = 0; jId < m_numCuEncStacks; jId++)
        {
          m_cReshaper[jId].createEnc(getSourceWidth(), getSourceHeight(), m_maxCUWidth, m_maxCUHeight, m_bitDepth[COMPONENT_Y]);
        }
    #else
    
        m_cReshaper.createEnc( getSourceWidth(), getSourceHeight(), m_maxCUWidth, m_maxCUHeight, m_bitDepth[COMPONENT_Y]);
    
    #endif
    
        m_cRateCtrl.init(m_framesToBeEncoded, m_RCTargetBitrate, (int)((double)m_iFrameRate / m_temporalSubsampleRatio + 0.5), m_iGOPSize, m_iSourceWidth, m_iSourceHeight,
          m_maxCUWidth, m_maxCUHeight, getBitDepth(CHANNEL_TYPE_LUMA), m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      if (m_alf)
      {
        m_cEncALF.create(this, m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, m_bitDepth, m_inputBitDepth);
      }
    
    #if JVET_V0094_BILATERAL_FILTER
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #if JVET_W0066_CCSAO
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
      if (m_bUseSAO || m_BIF || m_CCSAO || m_CBIF)
    #else
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
      if (m_bUseSAO || m_BIF || m_CCSAO)
    
    #endif
    #else
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
      if (m_bUseSAO || m_BIF || m_CBIF)
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      if (m_bUseSAO || m_BIF)
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #endif
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #else
    #if JVET_W0066_CCSAO
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
      if (m_bUseSAO || m_CCSAO || m_CBIF)
    #else
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
      if (m_bUseSAO || m_CCSAO)
    
    #endif
    #else
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
      if (m_bUseSAO || m_CBIF)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      if (m_bUseSAO)
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      {
        const uint32_t widthInCtus = (m_iSourceWidth + m_maxCUWidth - 1) / m_maxCUWidth;
        const uint32_t heightInCtus = (m_iSourceHeight + m_maxCUHeight - 1) / m_maxCUHeight;
        const uint32_t numCtuInFrame = widthInCtus * heightInCtus;
        m_cEncSAO.create(m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, (uint32_t)std::max(0, m_bitDepth[CHANNEL_TYPE_LUMA] - MAX_SAO_TRUNCATED_BITDEPTH), (uint32_t)std::max(0, m_bitDepth[CHANNEL_TYPE_CHROMA] - MAX_SAO_TRUNCATED_BITDEPTH));
        m_cEncSAO.createEncData(m_saoCtuBoundary, numCtuInFrame);
      }
    
    }
    
    void EncLib::destroy ()
    {
      // destroy processing unit classes
      m_cGOPEncoder.        destroy();
      m_cSliceEncoder.      destroy();
    
    #if ENABLE_SPLIT_PARALLELISM
    
      for( int jId = 0; jId < m_numCuEncStacks; jId++ )
      {
        m_cCuEncoder[jId].destroy();
      }
    #else
      m_cCuEncoder.         destroy();
    #endif
      if( m_alf )
      {
        m_cEncALF.destroy();
      }
      m_cEncSAO.            destroyEncData();
      m_cEncSAO.            destroy();
      m_cLoopFilter.        destroy();
      m_cRateCtrl.          destroy();
    
    #if ENABLE_SPLIT_PARALLELISM
    
      for (int jId = 0; jId < m_numCuEncStacks; jId++)
      {
        m_cReshaper[jId].   destroy();
      }
    #else
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_cReshaper.          destroy();
    #endif
    
    #if ENABLE_SPLIT_PARALLELISM
    
      for( int jId = 0; jId < m_numCuEncStacks; jId++ )
      {
        m_cInterSearch[jId].   destroy();
        m_cIntraSearch[jId].   destroy();
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        m_bilateralFilter[jId].destroy();
    #endif
    
      }
    #else
      m_cInterSearch.       destroy();
      m_cIntraSearch.       destroy();
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      m_bilateralFilter.    destroy();
    #endif
    
    #if ENABLE_SPLIT_PARALLELISM
    
      delete[] m_cCuEncoder;
      delete[] m_cInterSearch;
      delete[] m_cIntraSearch;
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      delete[] m_bilateralFilter;
    #endif
    
      delete[] m_cTrQuant;
      delete[] m_CABACEncoder;
      delete[] m_cRdCost;
      delete[] m_CtxCache;
    #endif
    
      return;
    }
    
    void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf )
    {
      m_AUWriterIf = auWriterIf;
    
    
      SPS &sps0 = *(m_spsMap.allocatePS( m_vps->getGeneralLayerIdx( m_layerId ) )); // NOTE: implementations that use more than 1 SPS need to be aware of activation issues.
      PPS &pps0 = *( m_ppsMap.allocatePS( m_vps->getGeneralLayerIdx( m_layerId ) ) );
    
      APS &aps0 = *( m_apsMap.allocatePS( SCALING_LIST_APS ) );
      aps0.setAPSId( 0 );
      aps0.setAPSType( SCALING_LIST_APS );
    
      if (getAvoidIntraInDepLayer() && getNumRefLayers(m_vps->getGeneralLayerIdx( getLayerId())) > 0)
      {
        setIDRRefParamListPresent(true);
      }
    
      xInitSPS( sps0 );
      xInitVPS( sps0 );
    
      xInitDCI(m_dci, sps0);
    
    #if ENABLE_SPLIT_PARALLELISM
      if( omp_get_dynamic() )
      {
        omp_set_dynamic( false );
      }
      omp_set_nested( true );
    #endif
    
    
      if (getUseCompositeRef() || getDependentRAPIndicationSEIEnabled())
    
    
    #if U0132_TARGET_BITS_SATURATION
      if (m_RCCpbSaturationEnabled)
      {
    
        m_cRateCtrl.initHrdParam(sps0.getGeneralHrdParameters(), sps0.getOlsHrdParameters(), m_iFrameRate, m_RCInitialCpbFullness);
    
    #if ENABLE_SPLIT_PARALLELISM
    
      for( int jId = 0; jId < m_numCuEncStacks; jId++ )
      {
        m_cRdCost[jId].setCostMode ( m_costMode );
      }
    #else
      m_cRdCost.setCostMode ( m_costMode );
    #endif
    
      // initialize PPS
    
      pps0.setPicWidthInLumaSamples( m_iSourceWidth );
      pps0.setPicHeightInLumaSamples( m_iSourceHeight );
    
    #if JVET_R0068_ASPECT6_ENC_RESTRICTION
      if (pps0.getPicWidthInLumaSamples() == sps0.getMaxPicWidthInLumaSamples() && pps0.getPicHeightInLumaSamples() == sps0.getMaxPicHeightInLumaSamples())
      {
        pps0.setConformanceWindow( sps0.getConformanceWindow() );
        pps0.setConformanceWindowFlag( false );
      }
      else
      {
        pps0.setConformanceWindow( m_conformanceWindow );
        pps0.setConformanceWindowFlag( m_conformanceWindow.getWindowEnabledFlag() );
      }
    #else
    
      pps0.setConformanceWindow( m_conformanceWindow );
    
    Hendry's avatar
    Hendry committed
      // initialize APS
    
    Hendry's avatar
    Hendry committed
      xInitRPL(sps0, isFieldCoding);
    
      if (m_resChangeInClvsEnabled)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        PPS &pps = *( m_ppsMap.allocatePS( ENC_PPS_ID_RPR ) );
    
        Window& inputScalingWindow = pps0.getScalingWindow();
    
        int scaledWidth = int( ( pps0.getPicWidthInLumaSamples() - SPS::getWinUnitX( sps0.getChromaFormatIdc() ) * ( inputScalingWindow.getWindowLeftOffset() + inputScalingWindow.getWindowRightOffset() ) ) / m_scalingRatioHor );
    
        int minSizeUnit = std::max(8, 1 << sps0.getLog2MinCodingBlockSize());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        int temp = scaledWidth / minSizeUnit;
        int width = ( scaledWidth - ( temp * minSizeUnit) > 0 ? temp + 1 : temp ) * minSizeUnit;
    
        int scaledHeight = int( ( pps0.getPicHeightInLumaSamples() - SPS::getWinUnitY( sps0.getChromaFormatIdc() ) * ( inputScalingWindow.getWindowTopOffset() + inputScalingWindow.getWindowBottomOffset() ) ) / m_scalingRatioVer );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        temp = scaledHeight / minSizeUnit;
        int height = ( scaledHeight - ( temp * minSizeUnit) > 0 ? temp + 1 : temp ) * minSizeUnit;
    
    
        pps.setPicWidthInLumaSamples( width );
        pps.setPicHeightInLumaSamples( height );
    
        Window conformanceWindow;
        conformanceWindow.setWindow( 0, ( width - scaledWidth ) / SPS::getWinUnitX( sps0.getChromaFormatIdc() ), 0, ( height - scaledHeight ) / SPS::getWinUnitY( sps0.getChromaFormatIdc() ) );
    
    #if JVET_R0068_ASPECT6_ENC_RESTRICTION
        if (pps.getPicWidthInLumaSamples() == sps0.getMaxPicWidthInLumaSamples() && pps.getPicHeightInLumaSamples() == sps0.getMaxPicHeightInLumaSamples())
        {
          pps.setConformanceWindow( sps0.getConformanceWindow() );
          pps.setConformanceWindowFlag( false );
        }
        else
        {
          pps.setConformanceWindow( conformanceWindow );
          pps.setConformanceWindowFlag( pps.getConformanceWindow().getWindowEnabledFlag() );
        }
    #else
    
        pps.setConformanceWindow( conformanceWindow );
    
        scalingWindow.setWindow( 0, ( width - scaledWidth ) / SPS::getWinUnitX( sps0.getChromaFormatIdc() ), 0, ( height - scaledHeight ) / SPS::getWinUnitY( sps0.getChromaFormatIdc() ) );
    
        pps.setScalingWindow( scalingWindow );
    
    
        //register the width/height of the current pic into reference SPS
        if (!sps0.getPPSValidFlag(pps.getPPSId()))
        {
          sps0.setPPSValidFlag(pps.getPPSId(), true);
          sps0.setScalingWindowSizeInPPS(pps.getPPSId(), scaledWidth, scaledHeight);
        }
        int curSeqMaxPicWidthY = sps0.getMaxPicWidthInLumaSamples();    // pic_width_max_in_luma_samples
        int curSeqMaxPicHeightY = sps0.getMaxPicHeightInLumaSamples();  // pic_height_max_in_luma_samples
        int curPicWidthY = width;                                       // pic_width_in_luma_samples
    
        int curPicHeightY = height;                                     // pic_height_in_luma_samples
    
        int max8MinCbSizeY = std::max((int)8, (1 << sps0.getLog2MinCodingBlockSize())); // Max(8, MinCbSizeY)
    
        //Warning message of potential scaling window size violation
    
        for (int i = 0; i < 64; i++)
        {
          if (sps0.getPPSValidFlag(i))
          {
            if ((scaledWidth * curSeqMaxPicWidthY) < sps0.getScalingWindowSizeInPPS(i).width * (curPicWidthY - max8MinCbSizeY))
              printf("Potential violation: (curScaledWIdth * curSeqMaxPicWidthY) should be greater than or equal to refScaledWidth * (curPicWidthY - max(8, MinCbSizeY)\n");
            if ((scaledHeight * curSeqMaxPicHeightY) < sps0.getScalingWindowSizeInPPS(i).height * (curPicHeightY - max8MinCbSizeY))
              printf("Potential violation: (curScaledHeight * curSeqMaxPicHeightY) should be greater than or equal to refScaledHeight * (curPicHeightY - max(8, MinCbSizeY)\n");
          }
        }
    
    
        // disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution)
        m_noPicPartitionFlag = true;
    
    
        xInitPPS( pps, sps0 ); // will allocate memory for and initialize pps.pcv inside
    
        
        if( pps.getWrapAroundEnabledFlag() )
        {
          int minCbSizeY = (1 << sps0.getLog2MinCodingBlockSize());
    
          pps.setPicWidthMinusWrapAroundOffset      ((pps.getPicWidthInLumaSamples()/minCbSizeY) - (m_wrapAroundOffset * pps.getPicWidthInLumaSamples() / pps0.getPicWidthInLumaSamples() / minCbSizeY) );
          pps.setWrapAroundOffset                   (minCbSizeY * (pps.getPicWidthInLumaSamples() / minCbSizeY - pps.getPicWidthMinusWrapAroundOffset()));
    
    
          pps.setPicWidthMinusWrapAroundOffset      (0);
    
          pps.setWrapAroundOffset                   ( 0 );       
        }
    
    #if ER_CHROMA_QP_WCG_PPS
      if (m_wcgChromaQpControl.isEnabled())
      {
        PPS &pps1=*(m_ppsMap.allocatePS(1));
        xInitPPS(pps1, sps0);
      }
    #endif
    
      if (getUseCompositeRef())
    
      {
        PPS &pps2 = *(m_ppsMap.allocatePS(2));
        xInitPPS(pps2, sps0);
        xInitPPSforLT(pps2);
      }
    
    Brian Heng's avatar
    Brian Heng committed
      xInitPicHeader(m_picHeader, sps0, pps0);
    
    
      // initialize processing unit classes
      m_cGOPEncoder.  init( this );
      m_cSliceEncoder.init( this, sps0 );
    
    #if ENABLE_SPLIT_PARALLELISM
    
      for( int jId = 0; jId < m_numCuEncStacks; jId++ )
      {
        // precache a few objects
        for( int i = 0; i < 10; i++ )
        {
          auto x = m_CtxCache[jId].get();
          m_CtxCache[jId].cache( x );
        }
    
        m_cCuEncoder[jId].init( this, sps0, jId );
    
        // initialize transform & quantization class
        m_cTrQuant[jId].init( jId == 0 ? nullptr : m_cTrQuant[0].getQuant(),
    
                              m_useRDOQ,
                              m_useRDOQTS,
    #if T0196_SELECTIVE_RDOQ
                              m_useSelectiveRDOQ,
    #endif
    
        );
    
        // initialize encoder search class
        CABACWriter* cabacEstimator = m_CABACEncoder[jId].getCABACEstimator( &sps0 );
        m_cIntraSearch[jId].init( this,
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                                 &m_bilateralFilter[jId],
    #endif
    
                                  getCtxCache( jId ), m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize
    
                                , &m_cReshaper[jId]
    
                                , sps0.getBitDepth(CHANNEL_TYPE_LUMA)
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                                 &m_bilateralFilter[jId],
    #endif
    
                                  &m_cTrQuant[jId],
                                  m_iSearchRange,
                                  m_bipredSearchRange,
                                  m_motionEstimationSearchMethod,
    
                                  getUseCompositeRef(),
    
                                  m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, &m_cRdCost[jId], cabacEstimator, getCtxCache( jId )
    
                               , &m_cReshaper[jId]
        );
    
    
        // link temporary buffets from intra search with inter search to avoid unnecessary memory overhead
        m_cInterSearch[jId].setTempBuffers( m_cIntraSearch[jId].getSplitCSBuf(), m_cIntraSearch[jId].getFullCSBuf(), m_cIntraSearch[jId].getSaveCSBuf() );
      }
    #else  // ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
    
      m_cCuEncoder.   init( this, sps0 );
    
    
      // initialize transform & quantization class
      m_cTrQuant.init( nullptr,
    
                       1 << m_log2MaxTbSize,
    
                       m_useRDOQ,
                       m_useRDOQTS,
    #if T0196_SELECTIVE_RDOQ
                       m_useSelectiveRDOQ,
    #endif
    
      );
    
      // initialize encoder search class
      CABACWriter* cabacEstimator = m_CABACEncoder.getCABACEstimator(&sps0);
      m_cIntraSearch.init( this,
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                           &m_bilateralFilter,
    #endif
    
                           getCtxCache(), m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize
    
    Taoran Lu's avatar
    Taoran Lu committed
                         , &m_cReshaper
    
                         , sps0.getBitDepth(CHANNEL_TYPE_LUMA)
    
    #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                           &m_bilateralFilter,
    #endif
    
                           &m_cTrQuant,
                           m_iSearchRange,
                           m_bipredSearchRange,
                           m_motionEstimationSearchMethod,
    
                           getUseCompositeRef(),
    
        m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, &m_cRdCost, cabacEstimator, getCtxCache()
    
    Taoran Lu's avatar
    Taoran Lu committed
                         , &m_cReshaper
      );
    
    
      // link temporary buffets from intra search with inter search to avoid unneccessary memory overhead
      m_cInterSearch.setTempBuffers( m_cIntraSearch.getSplitCSBuf(), m_cIntraSearch.getFullCSBuf(), m_cIntraSearch.getSaveCSBuf() );
    #endif // ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
    
      m_iMaxRefPicNum = 0;
    
    #if ER_CHROMA_QP_WCG_PPS
      if( m_wcgChromaQpControl.isEnabled() )
      {
    
        xInitScalingLists( sps0, *m_apsMap.getPS( 1 ) );
        xInitScalingLists( sps0, aps0 );
    
        xInitScalingLists( sps0, aps0 );
    
      if (m_resChangeInClvsEnabled)
    
        xInitScalingLists( sps0, *m_apsMap.getPS( ENC_PPS_ID_RPR ) );
    
      if (getUseCompositeRef())
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        picBg->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId, m_gopBasedTemporalFilterEnabled );
    
        picBg->finalInit( m_vps, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
    
        picBg->allocateNewSlice();
        picBg->createSpliceIdx(pps0.pcv->sizeInCtus);
        m_cGOPEncoder.setPicBg(picBg);
        Picture *picOrig = new Picture;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        picOrig->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId, m_gopBasedTemporalFilterEnabled );
    
        picOrig->getOrigBuf().fill(0);
        m_cGOPEncoder.setPicOrig(picOrig);
      }
    
    void EncLib::xInitScalingLists( SPS &sps, APS &aps )
    
    {
      // Initialise scaling lists
      // The encoder will only use the SPS scaling lists. The PPS will never be marked present.
      const int maxLog2TrDynamicRange[MAX_NUM_CHANNEL_TYPE] =
      {
    
        sps.getMaxLog2TrDynamicRange(CHANNEL_TYPE_LUMA),
        sps.getMaxLog2TrDynamicRange(CHANNEL_TYPE_CHROMA)
    
      };
    
      Quant* quant = getTrQuant()->getQuant();
    
      if(getUseScalingListId() == SCALING_LIST_OFF)
      {
        quant->setFlatScalingList(maxLog2TrDynamicRange, sps.getBitDepths());
        quant->setUseScalingList(false);
    
    #if ENABLE_SPLIT_PARALLELISM
    
        for( int jId = 1; jId < m_numCuEncStacks; jId++ )
        {
          getTrQuant( jId )->getQuant()->setFlatScalingList( maxLog2TrDynamicRange, sps.getBitDepths() );
          getTrQuant( jId )->getQuant()->setUseScalingList( false );
        }
    
      }
      else if(getUseScalingListId() == SCALING_LIST_DEFAULT)
      {
    
        aps.getScalingList().setDefaultScalingList ();
        quant->setScalingList( &( aps.getScalingList() ), maxLog2TrDynamicRange, sps.getBitDepths() );
    
    #if ENABLE_SPLIT_PARALLELISM
    
        for( int jId = 1; jId < m_numCuEncStacks; jId++ )
        {
          getTrQuant( jId )->getQuant()->setUseScalingList( true );
        }
    
        sps.setDisableScalingMatrixForLfnstBlks(getDisableScalingMatrixForLfnstBlks());
    
    #endif
      }
      else if(getUseScalingListId() == SCALING_LIST_FILE_READ)
      {
    
        aps.getScalingList().setDefaultScalingList();
    
        CHECK( aps.getScalingList().xParseScalingList( getScalingListFileName() ), "Error Parsing Scaling List Input File" );
    
        aps.getScalingList().checkDcOfMatrix();
    
    Kiyofumi Abe's avatar
    Kiyofumi Abe committed
        if( aps.getScalingList().isNotDefaultScalingList() == false )
    
        {
          setUseScalingListId( SCALING_LIST_DEFAULT );
        }
    
        aps.getScalingList().setChromaScalingListPresentFlag((sps.getChromaFormatIdc()!=CHROMA_400));
    
        quant->setScalingList( &( aps.getScalingList() ), maxLog2TrDynamicRange, sps.getBitDepths() );
    
    #if ENABLE_SPLIT_PARALLELISM
    
        for( int jId = 1; jId < m_numCuEncStacks; jId++ )
        {
          getTrQuant( jId )->getQuant()->setUseScalingList( true );
        }
    
    Kai Zhang's avatar
    Kai Zhang committed
    
        sps.setDisableScalingMatrixForLfnstBlks(getDisableScalingMatrixForLfnstBlks());
    
      }
      else
      {
        THROW("error : ScalingList == " << getUseScalingListId() << " not supported\n");
      }
    
    
      if( getUseScalingListId() == SCALING_LIST_FILE_READ )
    
        for (uint32_t scalingListId = 0; scalingListId < 28; scalingListId++)
        {
    
          if (aps.getScalingList().getChromaScalingListPresentFlag()||aps.getScalingList().isLumaScalingList(scalingListId))
    
            aps.getScalingList().checkPredMode(scalingListId);
    
    void EncLib::xInitPPSforLT(PPS& pps)
    {
      pps.setOutputFlagPresentFlag(true);
      pps.setDeblockingFilterControlPresentFlag(true);
      pps.setPPSDeblockingFilterDisabledFlag(true);
    }
    
    
    // ====================================================================================================================
    // Public member functions
    // ====================================================================================================================
    
    void EncLib::deletePicBuffer()
    {
      PicList::iterator iterPic = m_cListPic.begin();
      int iSize = int( m_cListPic.size() );
    
      for ( int i = 0; i < iSize; i++ )
      {
        Picture* pcPic = *(iterPic++);
    
        pcPic->destroy();
    
        // get rid of the qpadaption layer
        while( pcPic->aqlayer.size() )
        {
          delete pcPic->aqlayer.back(); pcPic->aqlayer.pop_back();
        }
    
        delete pcPic;
        pcPic = NULL;
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
      m_cListPic.clear();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYuvTrueOrg, PelStorage* pcPicYuvFilteredOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded )
    
    {
      if( m_compositeRefEnabled && m_cGOPEncoder.getPicBg()->getSpliceFull() && m_iPOCLast >= 10 && m_iNumPicRcvd == 0 && m_cGOPEncoder.getEncodedLTRef() == false )
      {
        Picture* picCurr = NULL;
        xGetNewPicBuffer( rcListPicYuvRecOut, picCurr, 2 );
        const PPS *pps = m_ppsMap.getPS( 2 );
        const SPS *sps = m_spsMap.getPS( pps->getSPSId() );
    
        picCurr->M_BUFS( 0, PIC_ORIGINAL ).copyFrom( m_cGOPEncoder.getPicBg()->getRecoBuf() );
    
        picCurr->finalInit( m_vps, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
    
        picCurr->poc = m_iPOCLast - 1;
        m_iPOCLast -= 2;
        if( getUseAdaptiveQP() )
        {
          AQpPreanalyzer::preanalyze( picCurr );
        }
        if( m_RCEnableRateControl )
        {
          m_cRateCtrl.initRCGOP( m_iNumPicRcvd );
        }
    
    
        m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, false, false, snrCSC, m_printFrameMSE, true, 0 );
    
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
        m_metricTime = m_cGOPEncoder.getMetricTime();
    #endif
        m_cGOPEncoder.setEncodedLTRef( true );
        if( m_RCEnableRateControl )
        {
          m_cRateCtrl.destroyRCGOP();
        }
    
        iNumEncoded = 0;
        m_iNumPicRcvd = 0;
      }
    
      //PROF_ACCUM_AND_START_NEW_SET( getProfilerPic(), P_GOP_LEVEL );
      if( pcPicYuvOrg != NULL )
      {
        // get original YUV
        Picture* pcPicCurr = NULL;
    
        int ppsID = -1; // Use default PPS ID
    #if ER_CHROMA_QP_WCG_PPS
        if( getWCGChromaQPControl().isEnabled() )
        {
          ppsID = getdQPs()[m_iPOCLast / ( m_compositeRefEnabled ? 2 : 1 ) + 1];
          ppsID += ( getSwitchPOC() != -1 && ( m_iPOCLast + 1 >= getSwitchPOC() ) ? 1 : 0 );
        }
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !RPR_ENABLE
    
        if( m_resChangeInClvsEnabled && m_intraPeriod == -1 )
    
    Philippe Bordes's avatar
    Philippe Bordes committed
    #endif
    
        {
          const int poc = m_iPOCLast + ( m_compositeRefEnabled ? 2 : 1 );
    
    
    Philippe Bordes's avatar
    Philippe Bordes committed
    #if RPR_ENABLE
          ppsID = 0;
          bool  bApplyRpr = false;
          bApplyRpr |= (m_switchPocPeriod < 0);                                   // RPR applied for all pictures
          bApplyRpr |= (m_switchPocPeriod > 0) && (poc / m_switchPocPeriod % 2);  // RPR applied for periods RA or LDB
          if( bApplyRpr )
    #else
    
          if( poc / m_switchPocPeriod % 2 )
    
    Philippe Bordes's avatar
    Philippe Bordes committed
    #endif
    
        if( m_vps->getMaxLayers() > 1 )
    
          ppsID = m_vps->getGeneralLayerIdx( m_layerId );
    
        }
    
        xGetNewPicBuffer( rcListPicYuvRecOut, pcPicCurr, ppsID );
    
        const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID );
        const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() );
    
    
        if (m_resChangeInClvsEnabled)
    
        {
          pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Y ) );
          pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cb ) );
          pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cr ) );
    
          pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Y ) );
          pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Cb ) );
          pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Cr ) );
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          if( m_gopBasedTemporalFilterEnabled )
          {
            pcPicCurr->M_BUFS( 0, PIC_FILTERED_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( pcPicYuvFilteredOrg->getBuf( COMPONENT_Y ) );
            pcPicCurr->M_BUFS( 0, PIC_FILTERED_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( pcPicYuvFilteredOrg->getBuf( COMPONENT_Cb ) );
            pcPicCurr->M_BUFS( 0, PIC_FILTERED_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( pcPicYuvFilteredOrg->getBuf( COMPONENT_Cr ) );
          }
    
    
          const ChromaFormat chromaFormatIDC = pSPS->getChromaFormatIdc();
    
          const PPS *refPPS = m_ppsMap.getPS( 0 );
    
          const Window& curScalingWindow = pPPS->getScalingWindow();
    
          int curPicWidth = pPPS->getPicWidthInLumaSamples()   - SPS::getWinUnitX( pSPS->getChromaFormatIdc() ) * ( curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset() );
          int curPicHeight = pPPS->getPicHeightInLumaSamples() - SPS::getWinUnitY( pSPS->getChromaFormatIdc() ) * ( curScalingWindow.getWindowTopOffset()  + curScalingWindow.getWindowBottomOffset() );
    
    
          const Window& refScalingWindow = refPPS->getScalingWindow();
    
          int refPicWidth = refPPS->getPicWidthInLumaSamples()   - SPS::getWinUnitX( pSPS->getChromaFormatIdc() ) * ( refScalingWindow.getWindowLeftOffset() + refScalingWindow.getWindowRightOffset() );
          int refPicHeight = refPPS->getPicHeightInLumaSamples() - SPS::getWinUnitY( pSPS->getChromaFormatIdc() ) * ( refScalingWindow.getWindowTopOffset()  + refScalingWindow.getWindowBottomOffset() );
    
    
          int xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth;
          int yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight;
          std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale );
    
          Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getScalingWindow(), pcPicCurr->getOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true,
            pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() );
          Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getScalingWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true,
            pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
          if( m_gopBasedTemporalFilterEnabled )
          {
            Picture::rescalePicture( scalingRatio, *pcPicYuvFilteredOrg, refPPS->getScalingWindow(), pcPicCurr->getFilteredOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true,
                                     pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() );
          }
    
    
        }
        else
        {
          pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg );
          pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL ).swap( *cPicYuvTrueOrg );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
          if( m_gopBasedTemporalFilterEnabled )
          {
            pcPicCurr->M_BUFS( 0, PIC_FILTERED_ORIGINAL ).swap( *pcPicYuvFilteredOrg );
          }
    
    
    
        pcPicCurr->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
    
    
        pcPicCurr->poc = m_iPOCLast;
    
        // compute image characteristics
        if( getUseAdaptiveQP() )
        {
          AQpPreanalyzer::preanalyze( pcPicCurr );
        }
      }
    
      if( ( m_iNumPicRcvd == 0 ) || ( !flush && ( m_iPOCLast != 0 ) && ( m_iNumPicRcvd != m_iGOPSize ) && ( m_iGOPSize != 0 ) ) )
      {
        iNumEncoded = 0;
        return true;
      }
    
      if( m_RCEnableRateControl )
      {
        m_cRateCtrl.initRCGOP( m_iNumPicRcvd );
      }
    
      m_picIdInGOP = 0;
    
      return false;
    
    /**
     - Application has picture buffer list with size of GOP + 1
     - Picture buffer list acts like as ring buffer
     - End of the list has the latest picture
     .
     \param   flush               cause encoder to encode a partial GOP
     \param   pcPicYuvOrg         original YUV picture
     \param   pcPicYuvTrueOrg
     \param   snrCSC
     \retval  rcListPicYuvRecOut  list of reconstruction YUV pictures
     \retval  accessUnitsOut      list of output access units
     \retval  iNumEncoded         number of encoded pictures
     */
    
    bool EncLib::encode( const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded )
    
      // compress GOP
      m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut,
        false, false, snrCSC, m_printFrameMSE, false, m_picIdInGOP );
    
      m_picIdInGOP++;
    
      // go over all pictures in a GOP excluding the first IRAP
      if( m_picIdInGOP != m_iGOPSize && m_iPOCLast )
      {
        return true;
      }
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      m_metricTime = m_cGOPEncoder.getMetricTime();
    #endif
    
      if( m_RCEnableRateControl )
      {
        m_cRateCtrl.destroyRCGOP();
      }
    
      iNumEncoded = m_iNumPicRcvd;
      m_iNumPicRcvd = 0;
      m_uiNumAllPicCoded += iNumEncoded;
    
      return false;
    }
    
    
    /**------------------------------------------------
     Separate interlaced frame into two fields
     -------------------------------------------------**/
    void separateFields(Pel* org, Pel* dstField, uint32_t stride, uint32_t width, uint32_t height, bool isTop)
    {
      if (!isTop)
      {
        org += stride;
      }
      for (int y = 0; y < height>>1; y++)
      {
        for (int x = 0; x < width; x++)
        {
          dstField[x] = org[x];
        }
    
        dstField += stride;
        org += stride*2;
      }
    
    }
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicYuvTrueOrg, PelStorage* pcPicYuvFilteredOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut,
                             int& iNumEncoded, bool isTff )
    
    {
      iNumEncoded = 0;
      bool keepDoing = true;
    
      for( int fieldNum = 0; fieldNum < 2; fieldNum++ )
      {
        if( pcPicYuvOrg )
        {
          /* -- field initialization -- */
          const bool isTopField = isTff == ( fieldNum == 0 );
    
          Picture *pcField;
          xGetNewPicBuffer( rcListPicYuvRecOut, pcField, -1 );
    
          for( uint32_t comp = 0; comp < ::getNumberValidComponents( pcPicYuvOrg->chromaFormat ); comp++ )
          {
            const ComponentID compID = ComponentID( comp );
            {
              PelBuf compBuf = pcPicYuvOrg->get( compID );
              separateFields( compBuf.buf,
                pcField->getOrigBuf().get( compID ).buf,
                compBuf.stride,
                compBuf.width,
                compBuf.height,
                isTopField );
    
              // to get fields of true original buffer to avoid wrong PSNR calculation in summary
              compBuf = pcPicYuvTrueOrg->get( compID );
              separateFields( compBuf.buf,
                pcField->getTrueOrigBuf().get(compID).buf,
                compBuf.stride,
                compBuf.width,
                compBuf.height,
                isTopField);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
              if( m_gopBasedTemporalFilterEnabled )
              {
                compBuf = pcPicYuvFilteredOrg->get( compID );
                separateFields( compBuf.buf,
                                pcField->getTrueOrigBuf().get( compID ).buf,
                                compBuf.stride,
                                compBuf.width,
                                compBuf.height,
                                isTopField );
              }
    
          int ppsID = -1; // Use default PPS ID
          const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID );
          const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() );
    
          pcField->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
    
    
          pcField->poc = m_iPOCLast;
          pcField->reconstructed = false;
    
          pcField->setBorderExtension( false );// where is this normally?
    
          pcField->topField = isTopField;                  // interlaced requirement
    
          // compute image characteristics
          if( getUseAdaptiveQP() )
          {
            AQpPreanalyzer::preanalyze( pcField );
          }
        }
    
      }
    
    
    Haiwei Sun's avatar
    Haiwei Sun committed
      if( m_iNumPicRcvd && ( flush || m_iPOCLast == 1 || m_iNumPicRcvd == m_iGOPSize ) )
      {
        m_picIdInGOP = 0;
        keepDoing = false;
    
      }
    
      return keepDoing;
    }
    
    bool EncLib::encode( const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded, bool isTff )
    {
      iNumEncoded = 0;
    
    
    Haiwei Sun's avatar
    Haiwei Sun committed
      for( int fieldNum = 0; fieldNum < 2; fieldNum++ )
      {
    
        m_iPOCLast = m_iPOCLast < 2 ? fieldNum : m_iPOCLast;
    
    Haiwei Sun's avatar
    Haiwei Sun committed
    
        // compress GOP