Skip to content
Snippets Groups Projects
DecLib.cpp 97.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.
     *
    
     * Copyright (c) 2010-2020, 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     DecLib.cpp
        \brief    decoder class
    */
    
    #include "NALread.h"
    #include "DecLib.h"
    
    #include "CommonLib/dtrace_next.h"
    #include "CommonLib/dtrace_buffer.h"
    #include "CommonLib/Buffer.h"
    #include "CommonLib/UnitTools.h"
    
    #include <fstream>
    
    #include <stdio.h>
    #include <fcntl.h>
    #include "AnnexBread.h"
    #include "NALread.h"
    
    #if K0149_BLOCK_STATISTICS
    #include "CommonLib/dtrace_blockstatistics.h"
    #endif
    
    
    #if RExt__DECODER_DEBUG_TOOL_STATISTICS
    #include "CommonLib/CodingStatistics.h"
    #endif
    
    
    Tobias Hinz's avatar
    Tobias Hinz committed
    bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::string& bitstreamFileName, bool bDecodeUntilPocFound /* = false */, int debugCTU /* = -1*/, int debugPOC /* = -1*/ )
    
    {
      int      poc;
      PicList* pcListPic = NULL;
    
      static bool bFirstCall      = true;             /* TODO: MT */
    
      static bool loopFiltered[MAX_VPS_LAYERS] = { false };            /* TODO: MT */
    
      static int  iPOCLastDisplay = -MAX_INT;         /* TODO: MT */
    
      static std::ifstream* bitstreamFile = nullptr;  /* TODO: MT */
      static InputByteStream* bytestream  = nullptr;  /* TODO: MT */
      bool bRet = false;
    
      // create & initialize internal classes
      static DecLib *pcDecLib = nullptr;              /* TODO: MT */
    
      if( pcEncPic )
      {
        if( bFirstCall )
        {
          bitstreamFile = new std::ifstream( bitstreamFileName.c_str(), std::ifstream::in | std::ifstream::binary );
          bytestream    = new InputByteStream( *bitstreamFile );
    
          CHECK( !*bitstreamFile, "failed to open bitstream file " << bitstreamFileName.c_str() << " for reading" ) ;
          // create decoder class
          pcDecLib = new DecLib;
          pcDecLib->create();
    
          // initialize decoder class
          pcDecLib->init(
    #if  JVET_J0090_MEMORY_BANDWITH_MEASURE
            ""
    #endif
          );
    
    
    Tobias Hinz's avatar
    Tobias Hinz committed
          pcDecLib->setDebugCTU( debugCTU );
          pcDecLib->setDebugPOC( debugPOC );
    
          pcDecLib->setDecodedPictureHashSEIEnabled( true );
    
          bFirstCall = false;
          msg( INFO, "start to decode %s \n", bitstreamFileName.c_str() );
        }
    
        bool goOn = true;
    
        // main decoder loop
        while( !!*bitstreamFile && goOn )
        {
          /* location serves to work around a design fault in the decoder, whereby
           * the process of reading a new slice that is the first slice of a new frame
           * requires the DecApp::decode() method to be called again with the same
           * nal unit. */
          std::streampos location = bitstreamFile->tellg();
          AnnexBStats stats       = AnnexBStats();
    
          InputNALUnit nalu;
          byteStreamNALUnit( *bytestream, nalu.getBitstream().getFifo(), stats );
    
          // call actual decoding function
          bool bNewPicture = false;
          if( nalu.getBitstream().getFifo().empty() )
          {
            /* this can happen if the following occur:
             *  - empty input file
             *  - two back-to-back start_code_prefixes
             *  - start_code_prefix immediately followed by EOF
             */
            msg( ERROR, "Warning: Attempt to decode an empty NAL unit\n");
          }
          else
          {
            read( nalu );
            int iSkipFrame = 0;
    
    BDChoi's avatar
    BDChoi committed
    
            bNewPicture = pcDecLib->decode(nalu, iSkipFrame, iPOCLastDisplay, 0);
    
            if( bNewPicture )
            {
              bitstreamFile->clear();
              /* location points to the current nalunit payload[1] due to the
                * need for the annexB parser to read three extra bytes.
                * [1] except for the first NAL unit in the file
                *     (but bNewPicture doesn't happen then) */
              bitstreamFile->seekg( location - std::streamoff( 3 ) );
              bytestream->reset();
            }
          }
    
    
          if ((bNewPicture || !*bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS) && !pcDecLib->getFirstSliceInSequence(nalu.m_nuhLayerId))
    
            if (!loopFiltered[nalu.m_nuhLayerId] || *bitstreamFile)
    
            {
              pcDecLib->finishPictureLight( poc, pcListPic );
    
              if( pcListPic )
              {
                for( auto & pic : *pcListPic )
                {
                  if( pic->poc == poc && (!bDecodeUntilPocFound || expectedPoc == poc ) )
                  {
                    CHECK( pcEncPic->slices.size() == 0, "at least one slice should be available" );
    
                    CHECK( expectedPoc != poc, "mismatch in POC - check encoder configuration" );
    
    
    Tobias Hinz's avatar
    Tobias Hinz committed
                    if( debugCTU < 0 || poc != debugPOC )
    
                    for( int i = 0; i < pic->slices.size(); i++ )
                    {
                      if( pcEncPic->slices.size() <= i )
                      {
                        pcEncPic->slices.push_back( new Slice );
                        pcEncPic->slices.back()->initSlice();
    
                        pcEncPic->slices.back()->setPPS( pcEncPic->slices[0]->getPPS() );
                        pcEncPic->slices.back()->setSPS( pcEncPic->slices[0]->getSPS() );
    
                        pcEncPic->slices.back()->setVPS( pcEncPic->slices[0]->getVPS() );
    
                        pcEncPic->slices.back()->setPic( pcEncPic->slices[0]->getPic() );
    
                      }
                      pcEncPic->slices[i]->copySliceInfo( pic->slices[i], false );
                    }
    
    Tobias Hinz's avatar
    Tobias Hinz committed
                    if( debugCTU >= 0 && poc == debugPOC )
                    {
                      pcEncPic->cs->initStructData();
    
                      pcEncPic->cs->copyStructure( *pic->cs, CH_L, true, true );
    
                      if( CS::isDualITree( *pcEncPic->cs ) )
                      {
                        pcEncPic->cs->copyStructure( *pic->cs, CH_C, true, true );
                      }
    
                      for( auto &cu : pcEncPic->cs->cus )
                      {
                        cu->slice = pcEncPic->cs->slice;
                      }
                    }
                    else
                    {
    
                    if ( pic->cs->sps->getSAOEnabledFlag() )
    
                    if( pic->cs->sps->getALFEnabledFlag() )
    
                      std::copy(pic->getAlfCtbFilterIndexVec().begin(), pic->getAlfCtbFilterIndexVec().end(), pcEncPic->getAlfCtbFilterIndexVec().begin());
    
                      for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ )
                      {
                        std::copy( pic->getAlfCtuEnableFlag()[compIdx].begin(), pic->getAlfCtuEnableFlag()[compIdx].end(), pcEncPic->getAlfCtuEnableFlag()[compIdx].begin() );
                      }
    
                      pcEncPic->resizeAlfCtbFilterIndex(pic->cs->pcv->sizeInCtus);
                      memcpy( pcEncPic->getAlfCtbFilterIndex(), pic->getAlfCtbFilterIndex(), sizeof(short)*pic->cs->pcv->sizeInCtus );
    
                      std::copy( pic->getAlfCtuAlternative(COMPONENT_Cb).begin(), pic->getAlfCtuAlternative(COMPONENT_Cb).end(), pcEncPic->getAlfCtuAlternative(COMPONENT_Cb).begin() );
                      std::copy( pic->getAlfCtuAlternative(COMPONENT_Cr).begin(), pic->getAlfCtuAlternative(COMPONENT_Cr).end(), pcEncPic->getAlfCtuAlternative(COMPONENT_Cr).begin() );
    
    
                        pcEncPic->slices[i]->setTileGroupNumAps(pic->slices[i]->getTileGroupNumAps());
    
                        pcEncPic->slices[i]->setAlfAPSs(pic->slices[i]->getTileGroupApsIdLuma());
                        pcEncPic->slices[i]->setAlfAPSs(pic->slices[i]->getAlfAPSs());
    
                        pcEncPic->slices[i]->setTileGroupApsIdChroma(pic->slices[i]->getTileGroupApsIdChroma());
                        pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Y,  pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Y));
                        pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Cb));
                        pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Cr));
    
                        pcEncPic->slices[i]->setTileGroupCcAlfCbApsId(pic->slices[i]->getTileGroupCcAlfCbApsId());
                        pcEncPic->slices[i]->setTileGroupCcAlfCbEnabledFlag(pic->slices[i]->getTileGroupCcAlfCbEnabledFlag());
                        pcEncPic->slices[i]->setTileGroupCcAlfCrApsId(pic->slices[i]->getTileGroupCcAlfCrApsId());
                        pcEncPic->slices[i]->setTileGroupCcAlfCrEnabledFlag(pic->slices[i]->getTileGroupCcAlfCrEnabledFlag());
    
                    if ( pic->cs->sps->getSAOEnabledFlag() )
    
                    pcEncPic->cs->copyStructure( *pic->cs, CH_L, true, true );
    
                    if( CS::isDualITree( *pcEncPic->cs ) )
                    {
                      pcEncPic->cs->copyStructure( *pic->cs, CH_C, true, true );
                    }
    
    Tobias Hinz's avatar
    Tobias Hinz committed
                    }
    
                    goOn = false; // exit the loop return
                    bRet = true;
                    break;
                  }
                }
              }
              // postpone loop filters
              if (!bRet)
              {
                pcDecLib->executeLoopFilters();
              }
    
              pcDecLib->finishPicture( poc, pcListPic, DETAILS );
    
              // write output
              if( ! pcListPic->empty())
              {
                PicList::iterator iterPic   = pcListPic->begin();
                int numPicsNotYetDisplayed = 0;
                int dpbFullness = 0;
                const SPS* activeSPS = (pcListPic->front()->cs->sps);
                uint32_t maxNrSublayers = activeSPS->getMaxTLayers();
                uint32_t numReorderPicsHighestTid = activeSPS->getNumReorderPics(maxNrSublayers-1);
                uint32_t maxDecPicBufferingHighestTid =  activeSPS->getMaxDecPicBuffering(maxNrSublayers-1);
    
                const VPS* referredVPS = pcListPic->front()->cs->vps;
    
                if( referredVPS != nullptr && referredVPS->m_numLayersInOls[referredVPS->m_targetOlsIdx] > 1 )
                {
                  numReorderPicsHighestTid = referredVPS->getNumReorderPics( maxNrSublayers - 1 );
                  maxDecPicBufferingHighestTid = referredVPS->getMaxDecPicBuffering( maxNrSublayers - 1 );
                }
    
    
                while (iterPic != pcListPic->end())
                {
                  Picture* pcCurPic = *(iterPic);
                  if(pcCurPic->neededForOutput && pcCurPic->getPOC() > iPOCLastDisplay)
                  {
                    numPicsNotYetDisplayed++;
                    dpbFullness++;
                  }
                  else if(pcCurPic->referenced)
                  {
                    dpbFullness++;
                  }
                  iterPic++;
                }
    
                iterPic = pcListPic->begin();
    
                if (numPicsNotYetDisplayed>2)
                {
                  iterPic++;
                }
    
                Picture* pcCurPic = *(iterPic);
                if( numPicsNotYetDisplayed>2 && pcCurPic->fieldPic ) //Field Decoding
                {
                  THROW( "no field coding support ");
                }
                else if( !pcCurPic->fieldPic ) //Frame Decoding
                {
                  iterPic = pcListPic->begin();
    
                  while (iterPic != pcListPic->end())
                  {
                    pcCurPic = *(iterPic);
    
                    if(pcCurPic->neededForOutput && pcCurPic->getPOC() > iPOCLastDisplay &&
                      (numPicsNotYetDisplayed >  numReorderPicsHighestTid || dpbFullness > maxDecPicBufferingHighestTid))
                    {
                        numPicsNotYetDisplayed--;
                      if( ! pcCurPic->referenced )
                      {
                        dpbFullness--;
                      }
                      // update POC of display order
                      iPOCLastDisplay = pcCurPic->getPOC();
    
                      // erase non-referenced picture in the reference picture list after display
                      if( ! pcCurPic->referenced && pcCurPic->reconstructed )
                      {
                        pcCurPic->reconstructed = false;
                      }
                      pcCurPic->neededForOutput = false;
                    }
    
                    iterPic++;
                  }
                }
              }
    
    
            }
    
            loopFiltered[nalu.m_nuhLayerId] = (nalu.m_nalUnitType == NAL_UNIT_EOS);
    
              pcDecLib->setFirstSliceInSequence(true, nalu.m_nuhLayerId);
    
          else if ((bNewPicture || !*bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS) && pcDecLib->getFirstSliceInSequence(nalu.m_nuhLayerId))
    
          {
            pcDecLib->setFirstSliceInPicture( true );
          }
        }
      }
    
      if( !bRet )
      {
        CHECK( bDecodeUntilPocFound, " decoding failed - check decodeBitstream2 parameter File: " << bitstreamFileName.c_str() );
        if( pcDecLib )
        {
          pcDecLib->destroy();
          pcDecLib->deletePicBuffer();
          delete pcDecLib;
          pcDecLib = nullptr;
        }
        bFirstCall   = true;
    
        for (int i = 0; i < MAX_VPS_LAYERS; i++)
        {
          loopFiltered[i] = false;
        }
    
        iPOCLastDisplay = -MAX_INT;
    
        if( bytestream )
        {
          delete bytestream;
          bytestream = nullptr;
        }
    
        if( bitstreamFile )
        {
          delete bitstreamFile;
          bitstreamFile = nullptr;
        }
      }
    
      return bRet;
    }
    
    
    //! \ingroup DecoderLib
    //! \{
    
    DecLib::DecLib()
      : m_iMaxRefPicNum(0)
    
      , m_isFirstGeneralHrd(true)
      , m_prevGeneralHrdParams()
    
      , m_associatedIRAPDecodingOrderNumber(0)
    
      , m_pocCRA(0)
      , m_pocRandomAccess(MAX_INT)
      , m_lastRasPoc(MAX_INT)
      , m_cListPic()
      , m_parameterSetManager()
      , m_apcSlicePilot(NULL)
      , m_SEIs()
      , m_cIntraPred()
      , m_cInterPred()
      , m_cTrQuant()
      , m_cSliceDecoder()
    
      , m_cCuDecoder()
      , m_HLSReader()
      , m_seiReader()
      , m_cLoopFilter()
      , m_cSAO()
    
    Taoran Lu's avatar
    Taoran Lu committed
      , m_cReshaper()
    
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
      , m_cacheModel()
    
    Brian Heng's avatar
    Brian Heng committed
      , m_prevLayerID(MAX_INT)
    
      , m_prevPOC(MAX_INT)
      , m_prevTid0POC(0)
      , m_bFirstSliceInPicture(true)
    
      , m_firstSliceInSequence{ true }
      , m_firstSliceInBitstream(true)
    
      , m_prevSliceSkipped(false)
      , m_skippedPOC(0)
      , m_lastPOCNoOutputPriorPics(-1)
      , m_isNoOutputPriorPics(false)
    
      , m_lastNoOutputBeforeRecoveryFlag( false )
    
      , m_pDecodedSEIOutputStream(NULL)
      , m_decodedPictureHashSEIEnabled(false)
      , m_numberOfChecksumErrorsDetected(0)
      , m_warningMessageSkipPicture(false)
      , m_prefixSEINALUs()
    
    Tobias Hinz's avatar
    Tobias Hinz committed
      , m_debugPOC( -1 )
      , m_debugCTU( -1 )
    
      , m_vps( nullptr )
    
      , m_maxDecSubPicIdx(0)
      , m_maxDecSliceAddrInSubPic(-1)
    
    {
    #if ENABLE_SIMD_OPT_BUFFER
      g_pelBufOP.initPelBufOpsX86();
    #endif
    }
    
    DecLib::~DecLib()
    {
      while (!m_prefixSEINALUs.empty())
      {
        delete m_prefixSEINALUs.front();
        m_prefixSEINALUs.pop_front();
      }
    
    }
    
    void DecLib::create()
    {
      m_apcSlicePilot = new Slice;
      m_uiSliceSegmentIdx = 0;
    }
    
    void DecLib::destroy()
    {
      delete m_apcSlicePilot;
      m_apcSlicePilot = NULL;
    
    
      if( m_dci )
      {
        delete m_dci;
        m_dci = NULL;
      }
    
    
      m_cSliceDecoder.destroy();
    }
    
    void DecLib::init(
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
    
      const std::string& cacheCfgFileName
    
    #endif
    )
    {
      m_cSliceDecoder.init( &m_CABACDecoder, &m_cCuDecoder );
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
      m_cacheModel.create( cacheCfgFileName );
      m_cacheModel.clear( );
      m_cInterPred.cacheAssign( &m_cacheModel );
    #endif
      DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
    }
    
    void DecLib::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();
    
        delete pcPic;
        pcPic = NULL;
      }
      m_cALF.destroy();
      m_cSAO.destroy();
      m_cLoopFilter.destroy();
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
      m_cacheModel.reportSequence( );
      m_cacheModel.destroy( );
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_cCuDecoder.destoryDecCuReshaprBuf();
      m_cReshaper.destroy();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_t temporalLayer, const int layerId )
    
      m_iMaxRefPicNum = ( m_vps == nullptr || m_vps->m_numLayersInOls[m_vps->m_targetOlsIdx] == 1 ) ? sps.getMaxDecPicBuffering( temporalLayer ) : m_vps->getMaxDecPicBuffering( temporalLayer );     // m_uiMaxDecPicBuffering has the space for the picture currently being decoded
    
      if (m_cListPic.size() < (uint32_t)m_iMaxRefPicNum)
      {
        pcPic = new Picture();
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true, layerId );
    
    
        m_cListPic.push_back( pcPic );
    
        return pcPic;
      }
    
      bool bBufferIsAvailable = false;
      for(auto * p: m_cListPic)
      {
        pcPic = p;  // workaround because range-based for-loops don't work with existing variables
        if ( pcPic->reconstructed == false && ! pcPic->neededForOutput )
        {
          pcPic->neededForOutput = false;
          bBufferIsAvailable = true;
          break;
        }
    
        if( ! pcPic->referenced  && ! pcPic->neededForOutput )
        {
          pcPic->neededForOutput = false;
          pcPic->reconstructed = false;
          bBufferIsAvailable = true;
          break;
        }
      }
    
      if( ! bBufferIsAvailable )
      {
        //There is no room for this picture, either because of faulty encoder or dropped NAL. Extend the buffer.
        m_iMaxRefPicNum++;
    
        pcPic = new Picture();
    
        m_cListPic.push_back( pcPic );
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true, layerId );
    
        if( !pcPic->Y().Size::operator==( Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ) ) || pps.pcv->maxCUWidth != sps.getMaxCUWidth() || pps.pcv->maxCUHeight != sps.getMaxCUHeight() )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true, layerId );
    
      }
    
      pcPic->setBorderExtension( false );
      pcPic->neededForOutput = false;
      pcPic->reconstructed = false;
    
      return pcPic;
    }
    
    
    void DecLib::executeLoopFilters()
    {
      if( !m_pcPic )
      {
        return; // nothing to deblock
      }
    
    
      m_pcPic->cs->slice->startProcessingTimer();
    
    
      if (cs.sps->getUseLmcs() && cs.picHeader->getLmcsEnabledFlag())
    
          const PreCalcValues& pcv = *cs.pcv;
          for (uint32_t yPos = 0; yPos < pcv.lumaHeight; yPos += pcv.maxCUHeight)
          {
            for (uint32_t xPos = 0; xPos < pcv.lumaWidth; xPos += pcv.maxCUWidth)
            {
              const CodingUnit* cu = cs.getCU(Position(xPos, yPos), CHANNEL_TYPE_LUMA);
              if (cu->slice->getLmcsEnabledFlag())
              {
                const uint32_t width = (xPos + pcv.maxCUWidth > pcv.lumaWidth) ? (pcv.lumaWidth - xPos) : pcv.maxCUWidth;
                const uint32_t height = (yPos + pcv.maxCUHeight > pcv.lumaHeight) ? (pcv.lumaHeight - yPos) : pcv.maxCUHeight;
                const UnitArea area(cs.area.chromaFormat, Area(xPos, yPos, width, height));
                cs.getRecoBuf(area).get(COMPONENT_Y).rspSignal(m_cReshaper.getInvLUT());
              }
            }
          }
    
    Taoran Lu's avatar
    Taoran Lu committed
          m_cReshaper.setRecReshaped(false);
    
    Taoran Lu's avatar
    Taoran Lu committed
          m_cSAO.setReshaper(&m_cReshaper);
    
      // deblocking filter
      m_cLoopFilter.loopFilterPic( cs );
    
      CS::setRefinedMotionField(cs);
    
      if( cs.sps->getSAOEnabledFlag() )
    
      if( cs.sps->getALFEnabledFlag() )
    
        m_cALF.getCcAlfFilterParam() = cs.slice->m_ccAlfFilterParam;
        // ALF decodes the differentially coded coefficients and stores them in the parameters structure.
        // Code could be restructured to do directly after parsing. So far we just pass a fresh non-const
        // copy in case the APS gets used more than once.
        m_cALF.ALFProcess(cs);
    
      for (int i = 0; i < cs.pps->getNumSubPics() && m_targetSubPicIdx; i++)
    
    Biao Wang's avatar
    Biao Wang committed
      {
        // keep target subpic samples untouched, for other subpics mask their output sample value to 0
    
        int targetSubPicIdx = m_targetSubPicIdx - 1;
        if (i != targetSubPicIdx)
    
    Biao Wang's avatar
    Biao Wang committed
        {
          SubPic SubPicNoUse = cs.pps->getSubPics()[i];
          uint32_t left  = SubPicNoUse.getSubPicLeft();
          uint32_t right = SubPicNoUse.getSubPicRight();
          uint32_t top   = SubPicNoUse.getSubPicTop();
          uint32_t bottom= SubPicNoUse.getSubPicBottom();
          for (uint32_t row = top; row <= bottom; row++)
          {
            for (uint32_t col = left; col <= right; col++)
            {
              cs.getRecoBuf().Y().at(col, row) = 0;
              // for test only, hard coding using 4:2:0 chroma format
              cs.getRecoBuf().Cb().at(col>>1, row>>1) = 0;
              cs.getRecoBuf().Cr().at(col>>1, row>>1) = 0;
            }
          }
    
    Biao Wang's avatar
    Biao Wang committed
      }
    
    
      m_pcPic->cs->slice->stopProcessingTimer();
    
    }
    
    void DecLib::finishPictureLight(int& poc, PicList*& rpcListPic )
    {
      Slice*  pcSlice = m_pcPic->cs->slice;
    
    
    Brian Heng's avatar
    Brian Heng committed
      m_pcPic->neededForOutput = (pcSlice->getPicHeader()->getPicOutputFlag() ? true : false);
    
      m_pcPic->reconstructed = true;
    
      Slice::sortPicList( m_cListPic ); // sorting for application output
      poc                 = pcSlice->getPOC();
      rpcListPic          = &m_cListPic;
    }
    
    void DecLib::finishPicture(int& poc, PicList*& rpcListPic, MsgLevel msgl )
    {
    #if RExt__DECODER_DEBUG_TOOL_STATISTICS
      CodingStatistics::StatTool& s = CodingStatistics::GetStatisticTool( STATS__TOOL_TOTAL_FRAME );
      s.count++;
      s.pixels = s.count * m_pcPic->Y().width * m_pcPic->Y().height;
    #endif
    
      Slice*  pcSlice = m_pcPic->cs->slice;
    
      char c = (pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B');
      if (!m_pcPic->referenced)
      {
        c += 32;  // tolower
      }
    
    
      if (pcSlice->isDRAP()) c = 'D';
    
    
      msg( msgl, "POC %4d LId: %2d TId: %1d ( %s, %c-SLICE, QP%3d ) ", pcSlice->getPOC(), pcSlice->getPic()->layerId,
    
             nalUnitTypeToString(pcSlice->getNalUnitType()),
    
             c,
             pcSlice->getSliceQp() );
      msg( msgl, "[DT %6.3f] ", pcSlice->getProcessingTime() );
    
      for (int iRefList = 0; iRefList < 2; iRefList++)
      {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        for (int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx(RefPicList(iRefList)); iRefIndex++)
    
          const std::pair<int, int>& scaleRatio = pcSlice->getScalingRatio( RefPicList( iRefList ), iRefIndex );
    
    Brian Heng's avatar
    Brian Heng committed
          if( pcSlice->getPicHeader()->getEnableTMVPFlag() && pcSlice->getColFromL0Flag() == bool(1 - iRefList) && pcSlice->getColRefIdx() == iRefIndex )
    
            if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
            {
              msg( msgl, " %dc(%1.2lfx, %1.2lfx)", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
            }
    
            {
              msg( msgl, " %dc", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
            }
    
            if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
            {
              msg( msgl, " %d(%1.2lfx, %1.2lfx)", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
            }
    
            {
              msg( msgl, " %d", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
            }
    
    
          if( pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) == pcSlice->getPOC() )
          {
            msg( msgl, ".%d", pcSlice->getRefPic( RefPicList( iRefList ), iRefIndex )->layerId );
    
        }
        msg( msgl, "] ");
      }
      if (m_decodedPictureHashSEIEnabled)
      {
        SEIMessages pictureHashes = getSeisByType(m_pcPic->SEIs, SEI::DECODED_PICTURE_HASH );
        const SEIDecodedPictureHash *hash = ( pictureHashes.size() > 0 ) ? (SEIDecodedPictureHash*) *(pictureHashes.begin()) : NULL;
        if (pictureHashes.size() > 1)
        {
          msg( WARNING, "Warning: Got multiple decoded picture hash SEI messages. Using first.");
        }
        m_numberOfChecksumErrorsDetected += calcAndPrintHashStatus(((const Picture*) m_pcPic)->getRecoBuf(), hash, pcSlice->getSPS()->getBitDepths(), msgl);
      }
    
      msg( msgl, "\n");
    
    
    #if JVET_J0090_MEMORY_BANDWITH_MEASURE
        m_cacheModel.reportFrame();
        m_cacheModel.accumulateFrame();
        m_cacheModel.clear();
    #endif
    
    
    Brian Heng's avatar
    Brian Heng committed
      m_pcPic->neededForOutput = (pcSlice->getPicHeader()->getPicOutputFlag() ? true : false);
    
      m_pcPic->reconstructed = true;
    
    
      Slice::sortPicList( m_cListPic ); // sorting for application output
      poc                 = pcSlice->getPOC();
      rpcListPic          = &m_cListPic;
      m_bFirstSliceInPicture  = true; // TODO: immer true? hier ist irgendwas faul
    
      m_maxDecSubPicIdx = 0;
      m_maxDecSliceAddrInSubPic = -1;
    
    
      m_pcPic->destroyTempBuffers();
      m_pcPic->cs->destroyCoeffs();
      m_pcPic->cs->releaseIntermediateData();
    
    Brian Heng's avatar
    Brian Heng committed
      m_pcPic->cs->picHeader->initPicHeader();
    
    }
    
    void DecLib::checkNoOutputPriorPics (PicList* pcListPic)
    {
      if (!pcListPic || !m_isNoOutputPriorPics)
      {
        return;
      }
    
      PicList::iterator  iterPic   = pcListPic->begin();
    
      while (iterPic != pcListPic->end())
      {
        Picture* pcPicTmp = *(iterPic++);
        if (m_lastPOCNoOutputPriorPics != pcPicTmp->getPOC())
        {
          pcPicTmp->neededForOutput = false;
        }
      }
    }
    
    void DecLib::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();
      }
    }
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    void DecLib::xCreateLostPicture( int iLostPoc, const int layerId )
    
    {
      msg( INFO, "\ninserting lost poc : %d\n",iLostPoc);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      Picture *cFillPic = xGetNewPicBuffer( *( m_parameterSetManager.getFirstSPS() ), *( m_parameterSetManager.getFirstPPS() ), 0, layerId );
    
    
      CHECK( !cFillPic->slices.size(), "No slices in picture" );
    
      cFillPic->slices[0]->initSlice();
    
      PicList::iterator iterPic = m_cListPic.begin();
      int closestPoc = 1000000;
      while ( iterPic != m_cListPic.end())
      {
        Picture * rpcPic = *(iterPic++);
        if(abs(rpcPic->getPOC() -iLostPoc)<closestPoc&&abs(rpcPic->getPOC() -iLostPoc)!=0&&rpcPic->getPOC()!=m_apcSlicePilot->getPOC())
        {
          closestPoc=abs(rpcPic->getPOC() -iLostPoc);
        }
      }
      iterPic = m_cListPic.begin();
      while ( iterPic != m_cListPic.end())
      {
        Picture *rpcPic = *(iterPic++);
        if(abs(rpcPic->getPOC() -iLostPoc)==closestPoc&&rpcPic->getPOC()!=m_apcSlicePilot->getPOC())
        {
          msg( INFO, "copying picture %d to %d (%d)\n",rpcPic->getPOC() ,iLostPoc,m_apcSlicePilot->getPOC());
          cFillPic->getRecoBuf().copyFrom( rpcPic->getRecoBuf() );
          break;
        }
      }
    
    //  for(int ctuRsAddr=0; ctuRsAddr<cFillPic->getNumberOfCtusInFrame(); ctuRsAddr++)  { cFillPic->getCtu(ctuRsAddr)->initCtu(cFillPic, ctuRsAddr); }
      cFillPic->referenced = true;
      cFillPic->slices[0]->setPOC(iLostPoc);
      xUpdatePreviousTid0POC(cFillPic->slices[0]);
      cFillPic->reconstructed = true;
      cFillPic->neededForOutput = true;
      if(m_pocRandomAccess == MAX_INT)
      {
        m_pocRandomAccess = iLostPoc;
      }
    
    }
    
    
    void DecLib::xCreateUnavailablePicture(int iUnavailablePoc, bool longTermFlag, const int layerId, const bool interLayerRefPicFlag)
    
    Philip Cowan's avatar
    Philip Cowan committed
    {
      msg(INFO, "\ninserting unavailable poc : %d\n", iUnavailablePoc);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      Picture* cFillPic = xGetNewPicBuffer( *( m_parameterSetManager.getFirstSPS() ), *( m_parameterSetManager.getFirstPPS() ), 0, layerId );
    
    Philip Cowan's avatar
    Philip Cowan committed
    
      CHECK(!cFillPic->slices.size(), "No slices in picture");
    
      cFillPic->slices[0]->initSlice();
    
      uint32_t yFill = 1 << (m_parameterSetManager.getFirstSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 1);
      uint32_t cFill = 1 << (m_parameterSetManager.getFirstSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
      cFillPic->getRecoBuf().Y().fill(yFill);
      cFillPic->getRecoBuf().Cb().fill(cFill);
      cFillPic->getRecoBuf().Cr().fill(cFill);
    
    Philip Cowan's avatar
    Philip Cowan committed
      //  for(int ctuRsAddr=0; ctuRsAddr<cFillPic->getNumberOfCtusInFrame(); ctuRsAddr++)  { cFillPic->getCtu(ctuRsAddr)->initCtu(cFillPic, ctuRsAddr); }
      cFillPic->referenced = true;
    
      cFillPic->interLayerRefPicFlag = interLayerRefPicFlag;
    
    Philip Cowan's avatar
    Philip Cowan committed
      cFillPic->longTerm = longTermFlag;
      cFillPic->slices[0]->setPOC(iUnavailablePoc);
      xUpdatePreviousTid0POC(cFillPic->slices[0]);
      cFillPic->reconstructed = true;
    
    Brian Heng's avatar
    Brian Heng committed
      cFillPic->neededForOutput = false;
    
    Philip Cowan's avatar
    Philip Cowan committed
      if (m_pocRandomAccess == MAX_INT)
      {
        m_pocRandomAccess = iUnavailablePoc;
      }
    
    }
    
    void DecLib::checkTidLayerIdInAccessUnit()
    {
      int firstPicTid = m_accessUnitPicInfo.begin()->m_temporalId;
      int firstPicLayerId = m_accessUnitPicInfo.begin()->m_nuhLayerId;
    
      bool isPicTidInAuSame = true;
      bool isSeiTidInAuSameAsAuTid = true;
      bool isFdNaluLayerIdSameAsVclNaluLayerId = true;
    
      for (auto pic = m_accessUnitPicInfo.begin(); pic != m_accessUnitPicInfo.end(); pic++)
      {
        if (pic->m_temporalId != firstPicTid)
        {
          isPicTidInAuSame = false;
          break;
        }
      }
      CHECK(!isPicTidInAuSame, "All pictures in an AU shall have the same value of TemporalId");
    
      for (auto tid = m_accessUnitSeiTids.begin(); tid != m_accessUnitSeiTids.end(); tid++)
      {
        if ((*tid) != firstPicTid)
        {
          isSeiTidInAuSameAsAuTid = false;
          break;
        }
      }
    
    Xiang Ma's avatar
    Xiang Ma committed
      CHECK(!isSeiTidInAuSameAsAuTid, "The TemporalId of an SEI NAL unit shall be equal to the TemporalId of the AU containing the NAL unit");
    
    
      for (auto tempNalu = m_accessUnitNals.begin(); tempNalu != m_accessUnitNals.end(); tempNalu++)
      {
        if ((tempNalu->first == NAL_UNIT_FD) && (tempNalu->second != firstPicLayerId))
        {
    
    Xiang Ma's avatar
    Xiang Ma committed
          isFdNaluLayerIdSameAsVclNaluLayerId = false;
    
    Xiang Ma's avatar
    Xiang Ma committed
      CHECK(!isFdNaluLayerIdSameAsVclNaluLayerId, "The nuh_layer_id of a filler data NAL unit shall be equal to the nuh_layer_id of associated VCL NAL unit");
    
    Philip Cowan's avatar
    Philip Cowan committed
    
    
    void DecLib::checkSEIInAccessUnit()
    {
      for (auto &sei : m_accessUnitSeiPayLoadTypes)
      {
        enum NalUnitType         naluType = std::get<0>(sei);
        int                    nuhLayerId = std::get<1>(sei);
        enum SEI::PayloadType payloadType = std::get<2>(sei);
    
        if (m_vps != nullptr && naluType == NAL_UNIT_PREFIX_SEI && ((payloadType == SEI::BUFFERING_PERIOD || payloadType == SEI::PICTURE_TIMING || payloadType == SEI::DECODING_UNIT_INFO)))
    
        {
          int numlayersInZeroOls = m_vps->getNumLayersInOls(0);
          bool inZeroOls = true;
          for (int i = 0; i < numlayersInZeroOls; i++)
          {
            uint32_t layerIdInZeroOls = m_vps->getLayerIdInOls(0, i);
            if (layerIdInZeroOls != nuhLayerId)
            {
              inZeroOls = false;
            }
          }
          CHECK(!inZeroOls, "non-scalable-nested timing related SEI shall apply only to the 0-th OLS");
    
          int layerId = m_vps->getLayerId(0);
          CHECK(nuhLayerId != layerId, "the nuh_layer_id of non-scalable-nested timing related SEI shall be equal to vps_layer_id[0]");
        }
      }
    }
    
    
    Brian Heng's avatar
    Brian Heng committed
    /**
     - Determine if the first VCL NAL unit of a picture is also the first VCL NAL of an Access Unit
     */
    bool DecLib::isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu )
    {
      // can only be the start of an AU if this is the start of a new picture
      if( newPicture == false )
      {
        return false;
      }
    
      // should only be called for slice NALU types
      if( nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_TRAIL &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_STSA &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_RASL &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_RADL &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR_W_RADL &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR_N_LP &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_CRA &&
          nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_GDR )
      {
        return false;
      }
    
    Brian Heng's avatar
    Brian Heng committed
      // check for layer ID less than or equal to previous picture's layer ID
      if( nalu.m_nuhLayerId <= m_prevLayerID )
      {
        return true;
      }
    
      // get slice POC
      m_apcSlicePilot->setPicHeader( &m_picHeader );
    
      m_apcSlicePilot->initSlice();
    
    Brian Heng's avatar
    Brian Heng committed
      m_HLSReader.setBitstream( &nalu.getBitstream() );
    
      m_HLSReader.getSlicePoc( m_apcSlicePilot, &m_picHeader, &m_parameterSetManager, m_prevTid0POC );
    
    Brian Heng's avatar
    Brian Heng committed
    
      // check for different POC
      return (m_apcSlicePilot->getPOC() != m_prevPOC);
    }
    
    
    Brian Heng's avatar
    Brian Heng committed
    void activateAPS(PicHeader* picHeader, Slice* pSlice, ParameterSetManager& parameterSetManager, APS** apss, APS* lmcsAPS, APS* scalingListAPS)
    
    #if JVET_R0232_CCALF_APS_CONSTRAINT
      const SPS *sps = parameterSetManager.getSPS(picHeader->getSPSId());
    #endif
    
      if (pSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
    
        for (int i = 0; i < pSlice->getTileGroupApsIdLuma().size(); i++)
        {
          int apsId = pSlice->getTileGroupApsIdLuma()[i];
          APS* aps = parameterSetManager.getAPS(apsId, ALF_APS);
    
          if (aps)
          {
            apss[apsId] = aps;
            if (false == parameterSetManager.activateAPS(apsId, ALF_APS))
            {
              THROW("APS activation failed!");
            }