Skip to content
Snippets Groups Projects
DecLib.cpp 61.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* The copyright in this software is being made available under the BSD
     * License, included below. This software may be subject to other third party
     * and contributor rights, including patent rights, and no such rights are
     * granted under this license.
     *
    
     * Copyright (c) 2010-2019, ITU/ISO/IEC
    
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *  * Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
     *    be used to endorse or promote products derived from this software without
     *    specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     * THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /** \file     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    = 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;
            bNewPicture = pcDecLib->decode( nalu, iSkipFrame, iPOCLastDisplay );
            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() )
          {
            if( !loopFiltered || *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()->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 );
    
    #if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
                      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() );
    
    #endif
    
                        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));
    
                    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);
    
                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_nalUnitType == NAL_UNIT_EOS );
            if( nalu.m_nalUnitType == NAL_UNIT_EOS )
            {
              pcDecLib->setFirstSliceInSequence( true );
            }
    
          }
          else if( ( bNewPicture || !*bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS ) && pcDecLib->getFirstSliceInSequence() )
          {
            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;
        loopFiltered = 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_associatedIRAPType(NAL_UNIT_INVALID)
      , 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()
    
    #endif
      , m_pcPic(NULL)
      , m_prevPOC(MAX_INT)
      , m_prevTid0POC(0)
      , m_bFirstSliceInPicture(true)
      , m_bFirstSliceInSequence(true)
      , m_prevSliceSkipped(false)
      , m_skippedPOC(0)
      , m_bFirstSliceInBitstream(true)
      , m_lastPOCNoOutputPriorPics(-1)
      , m_isNoOutputPriorPics(false)
    
    #if JVET_N0865_NONSYNTAX
      , m_lastNoIncorrectPicOutputFlag(false)
    #else
    
    #endif
    #if JVET_O0428_LMCS_CLEANUP
      , m_sliceLmcsApsId(-1)
    
      , 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 )
    
    {
    #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;
    
      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();
    
    }
    
    Picture* DecLib::xGetNewPicBuffer ( const SPS &sps, const PPS &pps, const uint32_t temporalLayer )
    {
      Picture * pcPic = nullptr;
      m_iMaxRefPicNum = sps.getMaxDecPicBuffering(temporalLayer);     // m_uiMaxDecPicBuffering has the space for the picture currently being decoded
      if (m_cListPic.size() < (uint32_t)m_iMaxRefPicNum)
      {
        pcPic = new Picture();
    
    
    #if JVET_O1164_PS
        pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true );
    #else
    
        pcPic->create( sps.getChromaFormatIdc(), Size( sps.getPicWidthInLumaSamples(), sps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true );
    
    
        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 );
    
    
    #if JVET_O1164_PS
        pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true );
    #else
    
        pcPic->create( sps.getChromaFormatIdc(), Size( sps.getPicWidthInLumaSamples(), sps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true );
    
    #if JVET_O1164_PS
        if( !pcPic->Y().Size::operator==( Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ) ) || pcPic->cs->pcv->maxCUWidth != sps.getMaxCUWidth() || pcPic->cs->pcv->maxCUHeight != sps.getMaxCUHeight() )
        {
          pcPic->destroy();
          pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true );
        }
    #else
    
        if( !pcPic->Y().Size::operator==( Size( sps.getPicWidthInLumaSamples(), sps.getPicHeightInLumaSamples() ) ) || pcPic->cs->pcv->maxCUWidth != sps.getMaxCUWidth() || pcPic->cs->pcv->maxCUHeight != sps.getMaxCUHeight() )
        {
          pcPic->destroy();
          pcPic->create( sps.getChromaFormatIdc(), Size( sps.getPicWidthInLumaSamples(), sps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true );
        }
    
      }
    
      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();
    
    
    Taoran Lu's avatar
    Taoran Lu committed
      if (cs.sps->getUseReshaper() && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper())
      {
          CHECK((m_cReshaper.getRecReshaped() == false), "Rec picture is not reshaped!");
          m_pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_cReshaper.getInvLUT());
          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() )
    
        if (cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
    
        {
          // 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_pcPic->cs->slice->stopProcessingTimer();
    
    }
    
    void DecLib::finishPictureLight(int& poc, PicList*& rpcListPic )
    {
      Slice*  pcSlice = m_pcPic->cs->slice;
    
      m_pcPic->neededForOutput = (pcSlice->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
      }
    
      //-- For time output for each slice
      msg( msgl, "POC %4d TId: %1d ( %c-SLICE, QP%3d ) ", pcSlice->getPOC(),
             pcSlice->getTLayer(),
             c,
             pcSlice->getSliceQp() );
      msg( msgl, "[DT %6.3f] ", pcSlice->getProcessingTime() );
    
      for (int iRefList = 0; iRefList < 2; iRefList++)
      {
        msg( msgl, "[L%d ", 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 );
    
    
          if( pcSlice->getEnableTMVPFlag() && pcSlice->getColFromL0Flag() == bool(1 - iRefList) && pcSlice->getColRefIdx() == iRefIndex )
          {
    
            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, "%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));
    
        }
        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");
    
      m_pcPic->neededForOutput = (pcSlice->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_pcPic->destroyTempBuffers();
      m_pcPic->cs->destroyCoeffs();
      m_pcPic->cs->releaseIntermediateData();
    }
    
    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();
      }
    }
    
    void DecLib::xCreateLostPicture(int iLostPoc)
    {
      msg( INFO, "\ninserting lost poc : %d\n",iLostPoc);
      Picture *cFillPic = xGetNewPicBuffer(*(m_parameterSetManager.getFirstSPS()), *(m_parameterSetManager.getFirstPPS()), 0);
    
      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::xActivateParameterSets()
    {
      if (m_bFirstSliceInPicture)
      {
    
        APS** apss = m_parameterSetManager.getAPSs();
    
    #if JVET_O_MAX_NUM_ALF_APS_8
        memset(apss, 0, sizeof(*apss) * ALF_CTB_MAX_NUM_APS);
    #else
    
        memset(apss, 0, sizeof(*apss) * MAX_NUM_APS);
    
        const PPS *pps = m_parameterSetManager.getPPS(m_apcSlicePilot->getPPSId()); // this is a temporary PPS object. Do not store this value
        CHECK(pps == 0, "No PPS present");
    
        const SPS *sps = m_parameterSetManager.getSPS(pps->getSPSId());             // this is a temporary SPS object. Do not store this value
        CHECK(sps == 0, "No SPS present");
    
        if (NULL == pps->pcv)
        {
          m_parameterSetManager.getPPS( m_apcSlicePilot->getPPSId() )->pcv = new PreCalcValues( *sps, *pps, false );
        }
        m_parameterSetManager.clearSPSChangedFlag(sps->getSPSId());
        m_parameterSetManager.clearPPSChangedFlag(pps->getPPSId());
    
        if (false == m_parameterSetManager.activatePPS(m_apcSlicePilot->getPPSId(),m_apcSlicePilot->isIRAP()))
        {
          THROW("Parameter set activation failed!");
        }
    
        m_parameterSetManager.getApsMap()->clear();
        //luma APSs
        for (int i = 0; i < m_apcSlicePilot->getTileGroupApsIdLuma().size(); i++)
        {
          int apsId = m_apcSlicePilot->getTileGroupApsIdLuma()[i];
    
          APS* aps = m_parameterSetManager.getAPS(apsId, ALF_APS);
    
            m_parameterSetManager.clearAPSChangedFlag(apsId, ALF_APS);
    
            if (false == m_parameterSetManager.activateAPS(apsId, ALF_APS))
    
    
        //chroma APS
        int apsId = m_apcSlicePilot->getTileGroupApsIdChroma();
    
        APS* aps = m_parameterSetManager.getAPS(apsId, ALF_APS);
    
          m_parameterSetManager.clearAPSChangedFlag(apsId, ALF_APS);
    
          if (false == m_parameterSetManager.activateAPS(apsId, ALF_APS))
    
          {
            THROW("APS activation failed!");
          }
        }
    
    
        APS* lmcsAPS = NULL;
        if (m_apcSlicePilot->getLmcsAPSId() != -1)
        {
          lmcsAPS = m_parameterSetManager.getAPS(m_apcSlicePilot->getLmcsAPSId(), LMCS_APS);
          CHECK(lmcsAPS == 0, "No LMCS APS present");
        }
    
        if (lmcsAPS)
        {
          m_parameterSetManager.clearAPSChangedFlag(m_apcSlicePilot->getLmcsAPSId(), LMCS_APS);
          if (false == m_parameterSetManager.activateAPS(m_apcSlicePilot->getLmcsAPSId(), LMCS_APS))
          {
            THROW("LMCS APS activation failed!");
          }
        }
    
    
    #if JVET_O0299_APS_SCALINGLIST
        APS* scalinglistAPS = NULL;
        if( m_apcSlicePilot->getscalingListAPSId() != -1 )
        {
          scalinglistAPS = m_parameterSetManager.getAPS( m_apcSlicePilot->getscalingListAPSId(), SCALING_LIST_APS );
          CHECK( scalinglistAPS == 0, "No SCALING LIST APS present" );
        }
    
        if( scalinglistAPS )
        {
          m_parameterSetManager.clearAPSChangedFlag( m_apcSlicePilot->getscalingListAPSId(), SCALING_LIST_APS );
          if( false == m_parameterSetManager.activateAPS( m_apcSlicePilot->getscalingListAPSId(), SCALING_LIST_APS ) )
          {
            THROW( "SCALING LIST APS activation failed!" );
          }
        }
    #endif
    
    
        xParsePrefixSEImessages();
    
    #if RExt__HIGH_BIT_DEPTH_SUPPORT==0
        if (sps->getSpsRangeExtension().getExtendedPrecisionProcessingFlag() || sps->getBitDepth(CHANNEL_TYPE_LUMA)>12 || sps->getBitDepth(CHANNEL_TYPE_CHROMA)>12 )
        {
          THROW("High bit depth support must be enabled at compile-time in order to decode this bitstream\n");
        }
    #endif
    
        //  Get a new picture buffer. This will also set up m_pcPic, and therefore give us a SPS and PPS pointer that we can use.
        m_pcPic = xGetNewPicBuffer (*sps, *pps, m_apcSlicePilot->getTLayer());
    
    
    Hendry's avatar
    Hendry committed
        m_apcSlicePilot->applyReferencePictureListBasedMarking(m_cListPic, m_apcSlicePilot->getRPL0(), m_apcSlicePilot->getRPL1());
    
    #if JVET_O0299_APS_SCALINGLIST
        m_pcPic->finalInit( *sps, *pps, apss, *lmcsAPS, *scalinglistAPS );
    #else
    
        m_pcPic->finalInit(*sps, *pps, apss, *lmcsAPS);
    
        m_parameterSetManager.getPPS(m_apcSlicePilot->getPPSId())->setNumBricksInPic((int)m_pcPic->brickMap->bricks.size());
    
        m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth );
        m_pcPic->cs->createCoeffs();
    
        m_pcPic->allocateNewSlice();
        // make the slice-pilot a real slice, and set up the slice-pilot for the next slice
        CHECK(m_pcPic->slices.size() != (m_uiSliceSegmentIdx + 1), "Invalid number of slices");
        m_apcSlicePilot = m_pcPic->swapSliceObject(m_apcSlicePilot, m_uiSliceSegmentIdx);
    
        // we now have a real slice:
        Slice *pSlice = m_pcPic->slices[m_uiSliceSegmentIdx];
    
        // Update the PPS and SPS pointers with the ones of the picture.
        pps=pSlice->getPPS();
        sps=pSlice->getSPS();
    
        // fix Parameter Sets, now that we have the real slice
        m_pcPic->cs->slice = pSlice;
        m_pcPic->cs->sps   = sps;
        m_pcPic->cs->pps   = pps;
    
        memcpy(m_pcPic->cs->alfApss, apss, sizeof(m_pcPic->cs->alfApss));
        m_pcPic->cs->lmcsAps = lmcsAPS;
    
    #if JVET_O0299_APS_SCALINGLIST
        m_pcPic->cs->scalinglistAps = scalinglistAPS;
    #endif
    
        m_pcPic->cs->pcv   = pps->pcv;
    
        // Initialise the various objects for the new set of settings
    
    #if JVET_O1164_PS
        m_cSAO.create( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), sps->getMaxCodingDepth(), pps->getPpsRangeExtension().getLog2SaoOffsetScale( CHANNEL_TYPE_LUMA ), pps->getPpsRangeExtension().getLog2SaoOffsetScale( CHANNEL_TYPE_CHROMA ) );
    #else
    
        m_cSAO.create( sps->getPicWidthInLumaSamples(), sps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), sps->getMaxCodingDepth(), pps->getPpsRangeExtension().getLog2SaoOffsetScale(CHANNEL_TYPE_LUMA), pps->getPpsRangeExtension().getLog2SaoOffsetScale(CHANNEL_TYPE_CHROMA) );
    
        m_cLoopFilter.create( sps->getMaxCodingDepth() );
        m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth( CHANNEL_TYPE_LUMA ) );
    
    #if JVET_O1170_IBC_VIRTUAL_BUFFER
        m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc(), sps->getMaxCUHeight() );
    #else
    
        m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc() );
    
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
        if (sps->getUseReshaper())
        {
    
          m_cReshaper.createDec(sps->getBitDepth(CHANNEL_TYPE_LUMA));
    
    
        bool isField = false;
        bool isTopField = false;
    
        if(!m_SEIs.empty())
        {
    
    #if !JVET_O0041_FRAME_FIELD_SEI
    
          // Check if any new Picture Timing SEI has arrived
          SEIMessages pictureTimingSEIs = getSeisByType(m_SEIs, SEI::PICTURE_TIMING);
          if (pictureTimingSEIs.size()>0)
          {
            SEIPictureTiming* pictureTiming = (SEIPictureTiming*) *(pictureTimingSEIs.begin());
            isField    = (pictureTiming->m_picStruct == 1) || (pictureTiming->m_picStruct == 2) || (pictureTiming->m_picStruct == 9) || (pictureTiming->m_picStruct == 10) || (pictureTiming->m_picStruct == 11) || (pictureTiming->m_picStruct == 12);
            isTopField = (pictureTiming->m_picStruct == 1) || (pictureTiming->m_picStruct == 9) || (pictureTiming->m_picStruct == 11);
          }
    
    #else
          // Check if any new Frame Field Info SEI has arrived
          SEIMessages frameFieldSEIs = getSeisByType(m_SEIs, SEI::FRAME_FIELD_INFO);
          if (frameFieldSEIs.size()>0)
          {
            SEIFrameFieldInfo* ff = (SEIFrameFieldInfo*) *(frameFieldSEIs.begin());
            isField    = ff->m_fieldPicFlag;
            isTopField = isField && (!ff->m_bottomFieldFlag);
          }
    #endif
    
        }
    
        //Set Field/Frame coding mode
        m_pcPic->fieldPic = isField;
        m_pcPic->topField = isTopField;
    
        // transfer any SEI messages that have been received to the picture
        m_pcPic->SEIs = m_SEIs;
        m_SEIs.clear();
    
        // Recursive structure
        m_cCuDecoder.init( &m_cTrQuant, &m_cIntraPred, &m_cInterPred );
    
    Taoran Lu's avatar
    Taoran Lu committed
        if (sps->getUseReshaper())
        {
          m_cCuDecoder.initDecCuReshaper(&m_cReshaper, sps->getChromaFormatIdc());
        }
    
    #if MAX_TB_SIZE_SIGNALLING
    
        m_cTrQuant.init( nullptr, sps->getMaxTbSize(), false, false, false, false );
    
        m_cTrQuant.init( nullptr, MAX_TB_SIZEY, false, false, false, false );
    
    
        // RdCost
        m_cRdCost.setCostMode ( COST_STANDARD_LOSSY ); // not used in decoder side RdCost stuff -> set to default
    
        m_cSliceDecoder.create();
    
    
        if( sps->getALFEnabledFlag() )
    
    #if JVET_O1164_PS
          m_cALF.create( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), sps->getMaxCodingDepth(), sps->getBitDepths().recon );
    #else
    
          m_cALF.create( sps->getPicWidthInLumaSamples(), sps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), sps->getMaxCodingDepth(), sps->getBitDepths().recon );
    
        }
      }
      else
      {
        // make the slice-pilot a real slice, and set up the slice-pilot for the next slice
        m_pcPic->allocateNewSlice();
        CHECK(m_pcPic->slices.size() != (size_t)(m_uiSliceSegmentIdx + 1), "Invalid number of slices");
        m_apcSlicePilot = m_pcPic->swapSliceObject(m_apcSlicePilot, m_uiSliceSegmentIdx);
    
        Slice *pSlice = m_pcPic->slices[m_uiSliceSegmentIdx]; // we now have a real slice.
    
        const SPS *sps = pSlice->getSPS();
        const PPS *pps = pSlice->getPPS();