DecLib.cpp 105.77 KiB
/* 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 <set>
#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
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
);
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, 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" );
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 );
}
}
pcEncPic->cs->slice = pcEncPic->slices.back();
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() )
{
pcEncPic->copySAO( *pic, 0 );
}
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() );
for( int i = 0; i < pic->slices.size(); i++ )
{
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());
}
}
pcDecLib->executeLoopFilters();
if ( pic->cs->sps->getSAOEnabledFlag() )
{
pcEncPic->copySAO( *pic, 1 );
}
pcEncPic->cs->copyStructure( *pic->cs, CH_L, true, true );
if( CS::isDualITree( *pcEncPic->cs ) )
{
pcEncPic->cs->copyStructure( *pic->cs, CH_C, true, true );
}
}
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);
if( 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_associatedIRAPType(NAL_UNIT_INVALID)
, m_associatedIRAPDecodingOrderNumber(0)
, m_decodingOrderCounter(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_cTrQuantScalingList()
, m_cCuDecoder()
, m_HLSReader()
, m_seiReader()
, m_cLoopFilter()
, m_cSAO()
, m_cReshaper()
#if JVET_J0090_MEMORY_BANDWITH_MEASURE
, m_cacheModel()
#endif
, m_pcPic(NULL)
, 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_sliceLmcsApsId(-1)
, m_pDecodedSEIOutputStream(NULL)
, m_decodedPictureHashSEIEnabled(false)
, m_numberOfChecksumErrorsDetected(0)
, m_warningMessageSkipPicture(false)
, m_prefixSEINALUs()
, m_debugPOC( -1 )
, m_debugCTU( -1 )
, m_vps( nullptr )
, m_maxDecSubPicIdx(0)
, m_maxDecSliceAddrInSubPic(-1)
, m_dci(NULL)
{
#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
m_cCuDecoder.destoryDecCuReshaprBuf();
m_cReshaper.destroy();
}
Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_t temporalLayer, const int layerId )
{
Picture * pcPic = nullptr;
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();
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 );
pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, true, layerId );
}
else
{
if( !pcPic->Y().Size::operator==( Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ) ) || pps.pcv->maxCUWidth != sps.getMaxCUWidth() || pps.pcv->maxCUHeight != sps.getMaxCUHeight() )
{
pcPic->destroy();
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();
CodingStructure& cs = *m_pcPic->cs;
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());
}
}
}
m_cReshaper.setRecReshaped(false);
m_cSAO.setReshaper(&m_cReshaper);
}
// deblocking filter
m_cLoopFilter.loopFilterPic( cs );
CS::setRefinedMotionField(cs);
if( cs.sps->getSAOEnabledFlag() )
{
m_cSAO.SAOProcess( cs, cs.picture->getSAO() );
}
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++)
{
// keep target subpic samples untouched, for other subpics mask their output sample value to 0
int targetSubPicIdx = m_targetSubPicIdx - 1;
if (i != targetSubPicIdx)
{
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;
}
}
}
}
m_pcPic->cs->slice->stopProcessingTimer();
}
void DecLib::finishPictureLight(int& poc, PicList*& rpcListPic )
{
Slice* pcSlice = m_pcPic->cs->slice;
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';
//-- For time output for each slice
msg( msgl, "POC %4d LId: %2d TId: %1d ( %s, %c-SLICE, QP%3d ) ", pcSlice->getPOC(), pcSlice->getPic()->layerId,
pcSlice->getTLayer(),
nalUnitTypeToString(pcSlice->getNalUnitType()),
c,
pcSlice->getSliceQp() );
msg( msgl, "[DT %6.3f] ", pcSlice->getProcessingTime() );
for (int iRefList = 0; iRefList < 2; iRefList++)
{
msg( msgl, "[L%d", iRefList);
for (int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx(RefPicList(iRefList)); iRefIndex++)
{
const std::pair<int, int>& scaleRatio = pcSlice->getScalingRatio( RefPicList( iRefList ), iRefIndex );
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 ) );
}
else
{
msg( msgl, " %dc", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
}
}
else
{
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 ) );
}
else
{
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
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();
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();
}
}
void DecLib::xCreateLostPicture( int iLostPoc, const int layerId )
{
msg( INFO, "\ninserting lost poc : %d\n",iLostPoc);
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)
{
msg(INFO, "\ninserting unavailable poc : %d\n", iUnavailablePoc);
Picture* cFillPic = xGetNewPicBuffer( *( m_parameterSetManager.getFirstSPS() ), *( m_parameterSetManager.getFirstPPS() ), 0, layerId );
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);
// for(int ctuRsAddr=0; ctuRsAddr<cFillPic->getNumberOfCtusInFrame(); ctuRsAddr++) { cFillPic->getCtu(ctuRsAddr)->initCtu(cFillPic, ctuRsAddr); }
cFillPic->referenced = true;
cFillPic->interLayerRefPicFlag = interLayerRefPicFlag;
cFillPic->longTerm = longTermFlag;
cFillPic->slices[0]->setPOC(iUnavailablePoc);
xUpdatePreviousTid0POC(cFillPic->slices[0]);
cFillPic->reconstructed = true;
cFillPic->neededForOutput = false;
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;
}
}
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))
{
isFdNaluLayerIdSameAsVclNaluLayerId = false;
break;
}
}
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");
}
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]");
}
}
}
#if JVET_Q0488_SEI_REPETITION_CONSTRAINT
#define SEI_REPETITION_CONSTRAINT_LIST_SIZE 21
/**
- Count the number of identical SEI messages in the current picture
*/
void DecLib::checkSeiInPictureUnit()
{
std::vector<std::tuple<int, uint32_t, uint8_t*>> seiList;
// payload types subject to constrained SEI repetition
int picUnitRepConSeiList[SEI_REPETITION_CONSTRAINT_LIST_SIZE] = { 0, 1, 19, 45, 129, 132, 133, 137, 144, 145, 147, 148, 149, 150, 153, 154, 155, 156, 168, 203, 204};
// extract SEI messages from NAL units
for (auto &sei : m_pictureSeiNalus)
{
InputBitstream bs = sei->getBitstream();
do
{
int payloadType = 0;
uint32_t val = 0;
do
{
bs.readByte(val);
payloadType += val;
} while (val==0xFF);
uint32_t payloadSize = 0;
do
{
bs.readByte(val);
payloadSize += val;
} while (val==0xFF);
uint8_t *payload = new uint8_t[payloadSize];
for (uint32_t i = 0; i < payloadSize; i++)
{
bs.readByte(val);
payload[i] = (uint8_t)val;
}
seiList.push_back(std::tuple<int, uint32_t, uint8_t*>(payloadType, payloadSize, payload));
}
while (bs.getNumBitsLeft() > 8);
}
// count repeated messages in list
for (uint32_t i = 0; i < seiList.size(); i++)
{
int k, count = 1;
int payloadType1 = std::get<0>(seiList[i]);
uint32_t payloadSize1 = std::get<1>(seiList[i]);
uint8_t *payload1 = std::get<2>(seiList[i]);
// only consider SEI payload types in the PicUnitRepConSeiList
for(k=0; k<SEI_REPETITION_CONSTRAINT_LIST_SIZE; k++)
{
if(payloadType1 == picUnitRepConSeiList[k])
{
break;
}
}
if(k >= SEI_REPETITION_CONSTRAINT_LIST_SIZE)
{
continue;
}
// compare current SEI message with remaining messages in the list
for (uint32_t j = i+1; j < seiList.size(); j++)
{
int payloadType2 = std::get<0>(seiList[j]);
uint32_t payloadSize2 = std::get<1>(seiList[j]);
uint8_t *payload2 = std::get<2>(seiList[j]);
// check for identical SEI type, size, and payload
if(payloadType1 == payloadType2 && payloadSize1 == payloadSize2)
{
if(memcmp(payload1, payload2, payloadSize1*sizeof(uint8_t)) == 0)
{
count++;
}
}
}
CHECK(count > 4, "There shall be less than or equal to 4 identical sei_payload( ) syntax structures within a picture unit.");
}
// free SEI message list memory
for (uint32_t i = 0; i < seiList.size(); i++)
{
uint8_t *payload = std::get<2>(seiList[i]);
delete payload;
}
seiList.clear();
}
/**
- Reset list of SEI NAL units from the current picture
*/
void DecLib::resetPictureSeiNalus()
{
while (!m_pictureSeiNalus.empty())
{
delete m_pictureSeiNalus.front();
m_pictureSeiNalus.pop_front();
}
}
#endif
/**
- 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;
}
// 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();
m_HLSReader.setBitstream( &nalu.getBitstream() );
m_HLSReader.getSlicePoc( m_apcSlicePilot, &m_picHeader, &m_parameterSetManager, m_prevTid0POC );
// check for different POC
return (m_apcSlicePilot->getPOC() != m_prevPOC);
}
#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
void DecLib::checkAPSInPictureUnit()
{
bool firstVCLFound = false;
bool suffixAPSFound = false;
for (auto &nalu : m_pictureUnitNals)
{
if (NALUnit::isVclNalUnitType(nalu))
{
firstVCLFound = true;
CHECK( suffixAPSFound, "When any suffix APS NAL units are present in a PU, they shall follow the last VCL unit of the PU" );
}
else if (nalu == NAL_UNIT_PREFIX_APS)
{
CHECK( firstVCLFound, "When any prefix APS NAL units are present in a PU, they shall precede the first VCL unit of the PU");
}
else if (nalu == NAL_UNIT_SUFFIX_APS)
{
suffixAPSFound = true;
}
}
}
#endif
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
//luma APSs
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!");
}
CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
//ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
#if JVET_R0232_CCALF_APS_CONSTRAINT
CHECK(((sps->getCCALFEnabledFlag() == false) && (aps->getCcAlfAPSParam().newCcAlfFilter[0] || aps->getCcAlfAPSParam().newCcAlfFilter[1])), "When sps_ccalf_enabled_flag is 0, the values of alf_cc_cb_filter_signal_flag and alf_cc_cr_filter_signal_flag shall be equal to 0");
#endif
}
}
}
if (pSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cb)||pSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) )
{
//chroma APS
int apsId = pSlice->getTileGroupApsIdChroma();
APS* aps = parameterSetManager.getAPS(apsId, ALF_APS);
if (aps)
{
apss[apsId] = aps;
if (false == parameterSetManager.activateAPS(apsId, ALF_APS))
{
THROW("APS activation failed!");
}
CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
//ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
#if JVET_R0232_CCALF_APS_CONSTRAINT
CHECK(((sps->getCCALFEnabledFlag() == false) && (aps->getCcAlfAPSParam().newCcAlfFilter[0] || aps->getCcAlfAPSParam().newCcAlfFilter[1])), "When sps_ccalf_enabled_flag is 0, the values of alf_cc_cb_filter_signal_flag and alf_cc_cr_filter_signal_flag shall be equal to 0");
#endif
}
}
CcAlfFilterParam &filterParam = pSlice->m_ccAlfFilterParam;
// cleanup before copying
for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
{
memset( filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], 0, sizeof(filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx]) );
memset( filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], 0, sizeof(filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx]) );
}
memset( filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1], false, sizeof(filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1]) );
memset( filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1], false, sizeof(filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1]) );
if(pSlice->getTileGroupCcAlfCbEnabledFlag())
{
int apsId = pSlice->getTileGroupCcAlfCbApsId();
APS *aps = parameterSetManager.getAPS(apsId, ALF_APS);
if(aps)
{
apss[apsId] = aps;
if (false == parameterSetManager.activateAPS(apsId, ALF_APS))
{
THROW("APS activation failed!");
}
CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
//ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
filterParam.ccAlfFilterCount[COMPONENT_Cb - 1] = aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cb - 1];
for (int filterIdx=0; filterIdx < filterParam.ccAlfFilterCount[COMPONENT_Cb - 1]; filterIdx++ )
{
filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx] = aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx];
memcpy(filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], sizeof(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx]));
}
}
}
if(pSlice->getTileGroupCcAlfCrEnabledFlag())
{
int apsId = pSlice->getTileGroupCcAlfCrApsId();
APS *aps = parameterSetManager.getAPS(apsId, ALF_APS);
if(aps)
{
apss[apsId] = aps;
if (false == parameterSetManager.activateAPS(apsId, ALF_APS))
{
THROW("APS activation failed!");
}
CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
//ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
filterParam.ccAlfFilterCount[COMPONENT_Cr - 1] = aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cr - 1];
for (int filterIdx=0; filterIdx < filterParam.ccAlfFilterCount[COMPONENT_Cr - 1]; filterIdx++ )
{
filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx] = aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx];
memcpy(filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], sizeof(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx]));
}
}
}
if (picHeader->getLmcsEnabledFlag() && lmcsAPS == nullptr)
{
lmcsAPS = parameterSetManager.getAPS(picHeader->getLmcsAPSId(), LMCS_APS);
CHECK(lmcsAPS == nullptr, "No LMCS APS present");
if (lmcsAPS)
{
parameterSetManager.clearAPSChangedFlag(picHeader->getLmcsAPSId(), LMCS_APS);
if (false == parameterSetManager.activateAPS(picHeader->getLmcsAPSId(), LMCS_APS))
{
THROW("LMCS APS activation failed!");
}
CHECK( lmcsAPS->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
//ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
}
}
picHeader->setLmcsAPS(lmcsAPS);
if( picHeader->getExplicitScalingListEnabledFlag() && scalingListAPS == nullptr)
{
scalingListAPS = parameterSetManager.getAPS( picHeader->getScalingListAPSId(), SCALING_LIST_APS );
CHECK( scalingListAPS == nullptr, "No SCALING LIST APS present" );
if( scalingListAPS )
{
parameterSetManager.clearAPSChangedFlag( picHeader->getScalingListAPSId(), SCALING_LIST_APS );
if( false == parameterSetManager.activateAPS( picHeader->getScalingListAPSId(), SCALING_LIST_APS ) )
{
THROW( "SCALING LIST APS activation failed!" );
}
CHECK( scalingListAPS->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
//ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
}
}
picHeader->setScalingListAPS(scalingListAPS);
}
void DecLib::xActivateParameterSets( const int layerId )
{
if (m_bFirstSliceInPicture)
{
APS** apss = m_parameterSetManager.getAPSs();
memset(apss, 0, sizeof(*apss) * ALF_CTB_MAX_NUM_APS);
const PPS *pps = m_parameterSetManager.getPPS(m_picHeader.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");
const VPS *vps = sps->getVPSId() ? m_parameterSetManager.getVPS( sps->getVPSId() ) : nullptr;
if( nullptr != pps->pcv )
{
delete m_parameterSetManager.getPPS( m_picHeader.getPPSId() )->pcv;
}
m_parameterSetManager.getPPS( m_picHeader.getPPSId() )->pcv = new PreCalcValues( *sps, *pps, false );
m_parameterSetManager.clearSPSChangedFlag(sps->getSPSId());
m_parameterSetManager.clearPPSChangedFlag(pps->getPPSId());
if (false == m_parameterSetManager.activatePPS(m_picHeader.getPPSId(),m_apcSlicePilot->isIRAP()))
{
THROW("Parameter set activation failed!");
}
m_parameterSetManager.getApsMap()->clear();
for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++)
{
APS* aps = m_parameterSetManager.getAPS(i, ALF_APS);
if (aps)
{
m_parameterSetManager.clearAPSChangedFlag(i, ALF_APS);
}
}
APS* lmcsAPS = nullptr;
APS* scalinglistAPS = nullptr;
activateAPS(&m_picHeader, m_apcSlicePilot, m_parameterSetManager, apss, lmcsAPS, scalinglistAPS);
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(), layerId );
m_apcSlicePilot->applyReferencePictureListBasedMarking( m_cListPic, m_apcSlicePilot->getRPL0(), m_apcSlicePilot->getRPL1(), layerId, *pps);
m_pcPic->finalInit( vps, *sps, *pps, &m_picHeader, apss, lmcsAPS, scalinglistAPS );
m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth );
m_pcPic->cs->createCoeffs((bool)m_pcPic->cs->sps->getPLTMode());
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;
m_pcPic->cs->vps = vps;
memcpy(m_pcPic->cs->alfApss, apss, sizeof(m_pcPic->cs->alfApss));
m_pcPic->cs->lmcsAps = lmcsAPS;
m_pcPic->cs->scalinglistAps = scalinglistAPS;
m_pcPic->cs->pcv = pps->pcv;
// Initialise the various objects for the new set of settings
const int maxDepth = floorLog2(sps->getMaxCUWidth()) - pps->pcv->minCUWidthLog2;
const uint32_t log2SaoOffsetScaleLuma = (uint32_t) std::max(0, sps->getBitDepth(CHANNEL_TYPE_LUMA ) - MAX_SAO_TRUNCATED_BITDEPTH);
const uint32_t log2SaoOffsetScaleChroma = (uint32_t) std::max(0, sps->getBitDepth(CHANNEL_TYPE_CHROMA) - MAX_SAO_TRUNCATED_BITDEPTH);
m_cSAO.create( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(),
sps->getChromaFormatIdc(),
sps->getMaxCUWidth(), sps->getMaxCUHeight(),
maxDepth,
log2SaoOffsetScaleLuma, log2SaoOffsetScaleChroma );
m_cLoopFilter.create(maxDepth);
m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth( CHANNEL_TYPE_LUMA ) );
m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc(), sps->getMaxCUHeight() );
if (sps->getUseLmcs())
{
m_cReshaper.createDec(sps->getBitDepth(CHANNEL_TYPE_LUMA));
}
bool isField = false;
bool isTopField = false;
if(!m_SEIs.empty())
{
// 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);
}
}
//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 );
if (sps->getUseLmcs())
{
m_cCuDecoder.initDecCuReshaper(&m_cReshaper, sps->getChromaFormatIdc());
}
m_cTrQuant.init(m_cTrQuantScalingList.getQuant(), sps->getMaxTbSize(), 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() )
{
const int maxDepth = floorLog2(sps->getMaxCUWidth()) - sps->getLog2MinCodingBlockSize();
m_cALF.create( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), maxDepth, sps->getBitDepths().recon);
}
pSlice->m_ccAlfFilterControl[0] = m_cALF.getCcAlfControlIdc(COMPONENT_Cb);
pSlice->m_ccAlfFilterControl[1] = m_cALF.getCcAlfControlIdc(COMPONENT_Cr);
}
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();
APS** apss = pSlice->getAlfAPSs();
APS *lmcsAPS = m_picHeader.getLmcsAPS();
APS *scalinglistAPS = m_picHeader.getScalingListAPS();
// 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;
m_pcPic->cs->scalinglistAps = scalinglistAPS;
m_pcPic->cs->pcv = pps->pcv;
// check that the current active PPS has not changed...
if (m_parameterSetManager.getSPSChangedFlag(sps->getSPSId()) )
{
EXIT("Error - a new SPS has been decoded while processing a picture");
}
if (m_parameterSetManager.getPPSChangedFlag(pps->getPPSId()) )
{
EXIT("Error - a new PPS has been decoded while processing a picture");
}
for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++)
{
APS* aps = m_parameterSetManager.getAPS(i, ALF_APS);
if (aps && m_parameterSetManager.getAPSChangedFlag(i, ALF_APS))
{
EXIT("Error - a new APS has been decoded while processing a picture");
}
}
if (lmcsAPS && m_parameterSetManager.getAPSChangedFlag(lmcsAPS->getAPSId(), LMCS_APS) )
{
EXIT("Error - a new LMCS APS has been decoded while processing a picture");
}
if( scalinglistAPS && m_parameterSetManager.getAPSChangedFlag( scalinglistAPS->getAPSId(), SCALING_LIST_APS ) )
{
EXIT( "Error - a new SCALING LIST APS has been decoded while processing a picture" );
}
activateAPS(&m_picHeader, pSlice, m_parameterSetManager, apss, lmcsAPS, scalinglistAPS);
m_pcPic->cs->lmcsAps = lmcsAPS;
m_pcPic->cs->scalinglistAps = scalinglistAPS;
xParsePrefixSEImessages();
// Check if any new SEI has arrived
if(!m_SEIs.empty())
{
// Currently only decoding Unit SEI message occurring between VCL NALUs copied
SEIMessages& picSEI = m_pcPic->SEIs;
SEIMessages decodingUnitInfos = extractSeisByType( picSEI, SEI::DECODING_UNIT_INFO);
picSEI.insert(picSEI.end(), decodingUnitInfos.begin(), decodingUnitInfos.end());
deleteSEIs(m_SEIs);
}
}
xCheckParameterSetConstraints(layerId);
}
void DecLib::xCheckParameterSetConstraints(const int layerId)
{
// Conformance checks
Slice *slice = m_pcPic->slices[m_uiSliceSegmentIdx];
const SPS *sps = slice->getSPS();
const PPS *pps = slice->getPPS();
const VPS *vps = slice->getVPS();
if (((vps!=nullptr)&&(vps->getVPSGeneralHrdParamsPresentFlag()))||(sps->getGeneralHrdParametersPresentFlag()))
{
if (((vps != nullptr) && (vps->getVPSGeneralHrdParamsPresentFlag())) && (sps->getGeneralHrdParametersPresentFlag()))
{
CHECK(!(*vps->getGeneralHrdParameters() == *sps->getGeneralHrdParameters()), "It is a requirement of bitstream conformance that the content of the general_hrd_parameters( ) syntax structure present in any VPSs or SPSs in the bitstream shall be identical");
}
if (!m_isFirstGeneralHrd)
{
CHECK(!(m_prevGeneralHrdParams == (sps->getGeneralHrdParametersPresentFlag() ? *sps->getGeneralHrdParameters() : *vps->getGeneralHrdParameters())), "It is a requirement of bitstream conformance that the content of the general_hrd_parameters( ) syntax structure present in any VPSs or SPSs in the bitstream shall be identical");
}
m_prevGeneralHrdParams = (sps->getGeneralHrdParametersPresentFlag() ? *sps->getGeneralHrdParameters() : *vps->getGeneralHrdParameters());
}
m_isFirstGeneralHrd = false;
static std::unordered_map<int, int> m_clvssSPSid;
if( slice->isClvssPu() && m_bFirstSliceInPicture )
{
m_clvssSPSid[layerId] = pps->getSPSId();
}
CHECK( m_clvssSPSid[layerId] != pps->getSPSId(), "The value of pps_seq_parameter_set_id shall be the same in all PPSs that are referred to by coded pictures in a CLVS" );
CHECK(sps->getGDREnabledFlag() == false && m_picHeader.getGdrPicFlag(), "When gdr_enabled_flag is equal to 0, the value of gdr_pic_flag shall be equal to 0 ");
if( !sps->getUseWP() )
{
CHECK( pps->getUseWP(), "When sps_weighted_pred_flag is equal to 0, the value of pps_weighted_pred_flag shall be equal to 0." );
}
if( !sps->getUseWPBiPred() )
{
CHECK( pps->getWPBiPred(), "When sps_weighted_bipred_flag is equal to 0, the value of pps_weighted_bipred_flag shall be equal to 0." );
}
const int minCuSize = 1 << sps->getLog2MinCodingBlockSize();
CHECK( ( pps->getPicWidthInLumaSamples() % ( std::max( 8, minCuSize) ) ) != 0, "Coded frame width must be a multiple of Max(8, the minimum unit size)" );
CHECK( ( pps->getPicHeightInLumaSamples() % ( std::max( 8, minCuSize) ) ) != 0, "Coded frame height must be a multiple of Max(8, the minimum unit size)" );
if( !sps->getRprEnabledFlag() )
{
CHECK( pps->getPicWidthInLumaSamples() != sps->getMaxPicWidthInLumaSamples(), "When res_change_in_clvs_allowed_flag equal to 0, the value of pic_width_in_luma_samples shall be equal to pic_width_max_in_luma_samples." );
CHECK( pps->getPicHeightInLumaSamples() != sps->getMaxPicHeightInLumaSamples(), "When res_change_in_clvs_allowed_flag equal to 0, the value of pic_height_in_luma_samples shall be equal to pic_height_max_in_luma_samples." );
}
if( sps->getRprEnabledFlag() )
{
CHECK( sps->getSubPicInfoPresentFlag() != 0, "When res_change_in_clvs_allowed_flag is equal to 1, the value of subpic_info_present_flag shall be equal to 0." );
}
CHECK( sps->getRprEnabledFlag() && sps->getVirtualBoundariesPresentFlag(), "when the value of res_change_in_clvs_allowed_flag is equal to 1, the value of sps_virtual_boundaries_present_flag shall be equal to 0" );
if( sps->getCTUSize() + 2 * ( 1 << sps->getLog2MinCodingBlockSize() ) > pps->getPicWidthInLumaSamples() )
{
#if JVET_Q0764_WRAP_AROUND_WITH_RPR
CHECK( pps->getWrapAroundEnabledFlag(), "Wraparound shall be disabled when the value of ( CtbSizeY / MinCbSizeY + 1) is greater than or equal to ( pic_width_in_luma_samples / MinCbSizeY - 1 )" );
#else
CHECK( sps->getWrapAroundEnabledFlag(), "Wraparound shall be disabled when the value of ( CtbSizeY / MinCbSizeY + 1) is less than or equal to ( pic_width_in_luma_samples / MinCbSizeY - 1 )" );
#endif
}
if( vps != nullptr && vps->m_numOutputLayersInOls[vps->m_targetOlsIdx] > 1 )
{
CHECK( sps->getMaxPicWidthInLumaSamples() > vps->getOlsDpbPicSize( vps->m_targetOlsIdx ).width, "pic_width_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_width[ i ]" );
CHECK( sps->getMaxPicHeightInLumaSamples() > vps->getOlsDpbPicSize( vps->m_targetOlsIdx ).height, "pic_height_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_height[ i ]" );
}
static std::unordered_map<int, int> m_layerChromaFormat;
static std::unordered_map<int, int> m_layerBitDepth;
if (vps != nullptr && vps->getMaxLayers() > 1)
{
int curLayerIdx = vps->getGeneralLayerIdx(layerId);
int curLayerChromaFormat = sps->getChromaFormatIdc();
int curLayerBitDepth = sps->getBitDepth(CHANNEL_TYPE_LUMA);
if( slice->isClvssPu() && m_bFirstSliceInPicture )
{
m_layerChromaFormat[curLayerIdx] = curLayerChromaFormat;
m_layerBitDepth[curLayerIdx] = curLayerBitDepth;
}
else
{
CHECK(m_layerChromaFormat[curLayerIdx] != curLayerChromaFormat, "Different chroma format in the same layer.");
CHECK(m_layerBitDepth[curLayerIdx] != curLayerBitDepth, "Different bit-depth in the same layer.");
}
for (int i = 0; i < curLayerIdx; i++)
{
if (vps->getDirectRefLayerFlag(curLayerIdx, i))
{
int refLayerChromaFormat = m_layerChromaFormat[i];
CHECK(curLayerChromaFormat != refLayerChromaFormat, "The chroma formats of the current layer and the reference layer are different");
int refLayerBitDepth = m_layerBitDepth[i];
CHECK(curLayerBitDepth != refLayerBitDepth, "The bit-depth of the current layer and the reference layer are different");
}
}
}
if (sps->getProfileTierLevel()->getConstraintInfo()->getOneTilePerPicConstraintFlag())
{
CHECK(pps->getNumTiles() != 1, "When one_tile_per_pic_constraint_flag is equal to 1, each picture shall contain only one tile");
}
if (sps->getProfileTierLevel()->getConstraintInfo()->getOneSlicePerPicConstraintFlag())
{
CHECK( pps->getNumSlicesInPic() != 1, "When one_slice_per_pic_constraint_flag is equal to 1, each picture shall contain only one slice");
}
if (sps->getMaxPicWidthInLumaSamples() == pps->getPicWidthInLumaSamples() &&
sps->getMaxPicHeightInLumaSamples() == pps->getPicHeightInLumaSamples())
{
const Window& spsConfWin = sps->getConformanceWindow();
const Window& ppsConfWin = pps->getConformanceWindow();
CHECK(spsConfWin.getWindowLeftOffset() != ppsConfWin.getWindowLeftOffset(), "When picture size is equal to maximum picutre size, conformance window left offset in SPS and PPS shall be equal");
CHECK(spsConfWin.getWindowRightOffset() != ppsConfWin.getWindowRightOffset(), "When picture size is equal to maximum picutre size, conformance window right offset in SPS and PPS shall be equal");
CHECK(spsConfWin.getWindowTopOffset() != ppsConfWin.getWindowTopOffset(), "When picture size is equal to maximum picutre size, conformance window top offset in SPS and PPS shall be equal");
CHECK(spsConfWin.getWindowBottomOffset() != ppsConfWin.getWindowBottomOffset(), "When picture size is equal to maximum picutre size, conformance window bottom offset in SPS and PPS shall be equal");
}
int levelIdcSps = int(sps->getProfileTierLevel()->getLevelIdc());
int maxLevelIdxDci = 0;
if (m_dci)
{
for (int i = 0; i < m_dci->getNumPTLs(); i++)
{
if (maxLevelIdxDci < int(m_dci->getProfileTierLevel(i).getLevelIdc()))
{
maxLevelIdxDci = int(m_dci->getProfileTierLevel(i).getLevelIdc());
}
}
CHECK(levelIdcSps > maxLevelIdxDci, "max level signaled in the DCI shall not be less than the level signaled in the SPS");
}
#if !JVET_R0276_REORDERED_SUBPICS
// When the current picture is not the first picture of the CLVS, if the value of SubpicId[ i ] is not equal to the value of SubpicId[ i ] of previous picture in decoding order in the same layer,
// the nal_unit_type for all coded slice NAL units of the the subpicture with subpicture index i shall be in the range of IDR_W_RADL to CRA_NUT, inclusive.
if( sps->getSubPicInfoPresentFlag() )
{
static std::unordered_map<int, std::vector<int>> previousSubPicIds;
if( m_firstSliceInSequence[layerId] )
{
for( int subPicIdx = 0; subPicIdx < sps->getNumSubPics(); subPicIdx++ )
{
previousSubPicIds[layerId].push_back( pps->getSubPic( subPicIdx ).getSubPicID() );
}
}
else
{
int currentSubPicIdx = NOT_VALID;
for( int subPicIdx = 0; subPicIdx < sps->getNumSubPics(); subPicIdx++ )
{
if( pps->getSubPic( subPicIdx ).getSubPicID() == slice->getSliceSubPicId() )
{
currentSubPicIdx = subPicIdx;
break;
}
}
CHECK( currentSubPicIdx == NOT_VALID, "Sub-picture was not found" );
CHECK( !previousSubPicIds.count( layerId ), "Sub-picture information of the previously decoded picture was not stored" );
if( previousSubPicIds[layerId][currentSubPicIdx] != slice->getSliceSubPicId() )
{
CHECK( !slice->isIRAP(), "For reordered sub-pictures, the slice NAL shall be in the range of IDR_W_RADL to CRA_NUT, inclusive" )
}
// store PPS ID to have sub-picture info for the next pictures when last rectangular slice in the picture is encountered
if( slice->getSliceID() + 1 == pps->getNumSlicesInPic() )
{
previousSubPicIds[layerId].clear();
for( int subPicIdx = 0; subPicIdx < sps->getNumSubPics(); subPicIdx++ )
{
previousSubPicIds[layerId].push_back( pps->getSubPic( subPicIdx ).getSubPicID() );
}
}
}
}
#endif
#if JVET_R0278_CONSTRAINT
if( slice->getPicHeader()->getGdrOrIrapPicFlag() && !slice->getPicHeader()->getGdrPicFlag() && ( !vps || vps->getIndependentLayerFlag( vps->getGeneralLayerIdx( layerId ) ) ) )
{
CHECK( slice->getPicHeader()->getPicInterSliceAllowedFlag(),
"When gdr_or_irap_pic_flag is equal to 1 and gdr_pic_flag is equal to 0 and vps_independent_layer_flag[ GeneralLayerIdx[ nuh_layer_id ] ] is equal to 1, ph_inter_slice_allowed_flag shall be equal to 0" );
}
#endif
#if JVET_R0275_SPS_PTL_DBP_HRD
if( sps->getVPSId() && vps->m_numLayersInOls[vps->m_targetOlsIdx] == 1 )
{
CHECK( !sps->getPtlDpbHrdParamsPresentFlag(), "When sps_video_parameter_set_id is greater than 0 and there is an OLS that contains only one layer with nuh_layer_id equal to the nuh_layer_id of the SPS, the value of sps_ptl_dpb_hrd_params_present_flag shall be equal to 1" );
}
#endif
}
void DecLib::xParsePrefixSEIsForUnknownVCLNal()
{
while (!m_prefixSEINALUs.empty())
{
// do nothing?
msg( NOTICE, "Discarding Prefix SEI associated with unknown VCL NAL unit.\n");
delete m_prefixSEINALUs.front();
}
// TODO: discard following suffix SEIs as well?
}
void DecLib::xParsePrefixSEImessages()
{
while (!m_prefixSEINALUs.empty())
{
InputNALUnit &nalu=*m_prefixSEINALUs.front();
m_accessUnitSeiTids.push_back(nalu.m_temporalId);
const SPS *sps = m_parameterSetManager.getActiveSPS();
const VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId());
m_seiReader.parseSEImessage( &(nalu.getBitstream()), m_SEIs, nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId, vps, sps, m_HRD, m_pDecodedSEIOutputStream );
m_accessUnitSeiPayLoadTypes.push_back(std::tuple<NalUnitType, int, SEI::PayloadType>(nalu.m_nalUnitType, nalu.m_nuhLayerId, m_SEIs.back()->payloadType()));
delete m_prefixSEINALUs.front();
m_prefixSEINALUs.pop_front();
}
}
void DecLib::xDecodePicHeader( InputNALUnit& nalu )
{
m_HLSReader.setBitstream( &nalu.getBitstream() );
m_HLSReader.parsePictureHeader( &m_picHeader, &m_parameterSetManager, true );
m_picHeader.setValid();
}
bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDisplay )
{
m_apcSlicePilot->setPicHeader( &m_picHeader );
m_apcSlicePilot->initSlice(); // the slice pilot is an object to prepare for a new slice
// it is not associated with picture, sps or pps structures.
Picture* scaledRefPic[MAX_NUM_REF] = {};
if (m_bFirstSliceInPicture)
{
m_uiSliceSegmentIdx = 0;
}
else
{
CHECK(nalu.m_nalUnitType != m_pcPic->slices[m_uiSliceSegmentIdx - 1]->getNalUnitType(), "The value of NAL unit type shall be the same for all coded slice NAL units of a picture");
m_apcSlicePilot->copySliceInfo( m_pcPic->slices[m_uiSliceSegmentIdx-1] );
}
m_apcSlicePilot->setNalUnitType(nalu.m_nalUnitType);
m_apcSlicePilot->setNalUnitLayerId(nalu.m_nuhLayerId);
m_apcSlicePilot->setTLayer(nalu.m_temporalId);
for( auto& naluTemporalId : m_accessUnitNals )
{
if (
naluTemporalId.first != NAL_UNIT_DCI
&& naluTemporalId.first != NAL_UNIT_VPS
&& naluTemporalId.first != NAL_UNIT_SPS
&& naluTemporalId.first != NAL_UNIT_EOS
&& naluTemporalId.first != NAL_UNIT_EOB)
{
CHECK( naluTemporalId.second < nalu.m_temporalId, "TemporalId shall be greater than or equal to the TemporalId of the layer access unit containing the NAL unit" );
}
}
if (nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_GDR)
{
CHECK(nalu.m_temporalId != 0, "Current GDR picture has TemporalId not equal to 0");
}
m_HLSReader.setBitstream( &nalu.getBitstream() );
m_apcSlicePilot->m_ccAlfFilterParam = m_cALF.getCcAlfFilterParam();
m_HLSReader.parseSliceHeader( m_apcSlicePilot, &m_picHeader, &m_parameterSetManager, m_prevTid0POC );
PPS *pps = m_parameterSetManager.getPPS(m_picHeader.getPPSId());
CHECK(pps == 0, "No PPS present");
SPS *sps = m_parameterSetManager.getSPS(pps->getSPSId());
CHECK(sps == 0, "No SPS present");
VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId());
if (nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_STSA && vps != nullptr && (vps->getIndependentLayerFlag(vps->getGeneralLayerIdx(nalu.m_nuhLayerId)) == 1))
{
CHECK(nalu.m_temporalId == 0, "TemporalID of STSA picture shall not be zero in independent layers");
}
int currSubPicIdx = pps->getSubPicIdxFromSubPicId( m_apcSlicePilot->getSliceSubPicId() );
int currSliceAddr = m_apcSlicePilot->getSliceID();
for(int sp = 0; sp < currSubPicIdx; sp++)
{
currSliceAddr -= pps->getSubPic(sp).getNumSlicesInSubPic();
}
CHECK( currSubPicIdx < m_maxDecSubPicIdx, "Error in the order of coded slice NAL units of subpictures" );
CHECK( currSubPicIdx == m_maxDecSubPicIdx && currSliceAddr <= m_maxDecSliceAddrInSubPic, "Error in the order of coded slice NAL units within a subpicture" );
if( currSubPicIdx == m_maxDecSubPicIdx )
{
m_maxDecSliceAddrInSubPic = currSliceAddr;
}
if( currSubPicIdx > m_maxDecSubPicIdx )
{
m_maxDecSubPicIdx = currSubPicIdx;
m_maxDecSliceAddrInSubPic = currSliceAddr;
}
if ((sps->getVPSId() == 0) && (m_prevLayerID != MAX_INT))
{
CHECK(m_prevLayerID != nalu.m_nuhLayerId, "All VCL NAL unit in the CVS shall have the same value of nuh_layer_id "
"when sps_video_parameter_set_id is equal to 0");
}
CHECK((sps->getVPSId() > 0) && (vps == 0), "Invalid VPS");
if (vps != nullptr && (vps->getIndependentLayerFlag(nalu.m_nuhLayerId) == 0))
{
bool pocIsSet = false;
for(auto auNALit=m_accessUnitPicInfo.begin(); auNALit != m_accessUnitPicInfo.end();auNALit++)
{
for (int iRefIdx = 0; iRefIdx < m_apcSlicePilot->getNumRefIdx(REF_PIC_LIST_0) && !pocIsSet; iRefIdx++)
{
if (m_apcSlicePilot->getRefPic(REF_PIC_LIST_0, iRefIdx) && m_apcSlicePilot->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() == (*auNALit).m_POC)
{
m_apcSlicePilot->setPOC(m_apcSlicePilot->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC());
pocIsSet = true;
}
}
for (int iRefIdx = 0; iRefIdx < m_apcSlicePilot->getNumRefIdx(REF_PIC_LIST_1) && !pocIsSet; iRefIdx++)
{
if (m_apcSlicePilot->getRefPic(REF_PIC_LIST_1, iRefIdx) && m_apcSlicePilot->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() == (*auNALit).m_POC)
{
m_apcSlicePilot->setPOC(m_apcSlicePilot->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC());
pocIsSet = true;
}
}
}
}
// update independent slice index
uint32_t uiIndependentSliceIdx = 0;
if (!m_bFirstSliceInPicture)
{
uiIndependentSliceIdx = m_pcPic->slices[m_uiSliceSegmentIdx-1]->getIndependentSliceIdx();
uiIndependentSliceIdx++;
}
m_apcSlicePilot->setIndependentSliceIdx(uiIndependentSliceIdx);
#if K0149_BLOCK_STATISTICS
writeBlockStatisticsHeader(sps);
#endif
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "poc", m_apcSlicePilot->getPOC() ) );
if ((m_bFirstSliceInPicture ||
m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ||
m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR) &&
getNoOutputPriorPicsFlag())
{
checkNoOutputPriorPics(&m_cListPic);
setNoOutputPriorPicsFlag (false);
}
xUpdatePreviousTid0POC(m_apcSlicePilot);
m_apcSlicePilot->setAssociatedIRAPPOC(m_pocCRA);
m_apcSlicePilot->setAssociatedIRAPType(m_associatedIRAPType);
if( m_apcSlicePilot->getRapPicFlag() || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR )
{
// Derive NoOutputBeforeRecoveryFlag
if( !pps->getMixedNaluTypesInPicFlag() )
{
if( m_firstSliceInSequence[nalu.m_nuhLayerId] )
{
m_picHeader.setNoOutputBeforeRecoveryFlag( true );
}
else if( m_apcSlicePilot->getIdrPicFlag() )
{
m_picHeader.setNoOutputBeforeRecoveryFlag( true );
}
else if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA )
{
m_picHeader.setNoOutputBeforeRecoveryFlag( m_picHeader.getHandleCraAsCvsStartFlag() );
}
else if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR )
{
m_picHeader.setNoOutputBeforeRecoveryFlag( m_picHeader.getHandleGdrAsCvsStartFlag() );
}
}
//the inference for NoOutputOfPriorPicsFlag
if( !m_firstSliceInBitstream && m_picHeader.getNoOutputBeforeRecoveryFlag() )
{
m_picHeader.setNoOutputOfPriorPicsFlag( true );
}
else
{
m_picHeader.setNoOutputOfPriorPicsFlag(false);
}
if (m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR)
{
m_lastNoOutputBeforeRecoveryFlag = m_picHeader.getNoOutputBeforeRecoveryFlag();
}
if( m_picHeader.getNoOutputOfPriorPicsFlag() )
{
m_lastPOCNoOutputPriorPics = m_apcSlicePilot->getPOC();
m_isNoOutputPriorPics = true;
}
else
{
m_isNoOutputPriorPics = false;
}
}
//For inference of PicOutputFlag
if( !pps->getMixedNaluTypesInPicFlag() && ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL ) )
{
if( m_lastNoOutputBeforeRecoveryFlag )
{
m_picHeader.setPicOutputFlag(false);
}
}
{
PPS *pps = m_parameterSetManager.getPPS(m_picHeader.getPPSId());
CHECK(pps == 0, "No PPS present");
SPS *sps = m_parameterSetManager.getSPS(pps->getSPSId());
CHECK(sps == 0, "No SPS present");
if (sps->getVPSId() > 0)
{
VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId());
CHECK(vps == 0, "No VPS present");
if ((vps->getOlsModeIdc() == 0 && vps->getGeneralLayerIdx(nalu.m_nuhLayerId) < (vps->getMaxLayers() - 1) && vps->getOlsOutputLayerFlag(vps->m_targetOlsIdx, vps->getMaxLayers() - 1) == 1) || (vps->getOlsModeIdc() == 2 && vps->getOlsOutputLayerFlag(vps->m_targetOlsIdx, vps->getGeneralLayerIdx(nalu.m_nuhLayerId)) == 0))
{
m_picHeader.setPicOutputFlag(false);
}
}
}
//Reset POC MSB when CRA or GDR has NoOutputBeforeRecoveryFlag equal to 1
if( !pps->getMixedNaluTypesInPicFlag() && ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR ) && m_lastNoOutputBeforeRecoveryFlag )
{
int iMaxPOClsb = 1 << sps->getBitsForPOC();
m_apcSlicePilot->setPOC( m_apcSlicePilot->getPOC() & (iMaxPOClsb - 1) );
xUpdatePreviousTid0POC(m_apcSlicePilot);
}
AccessUnitPicInfo picInfo;
picInfo.m_nalUnitType = nalu.m_nalUnitType;
picInfo.m_nuhLayerId = nalu.m_nuhLayerId;
picInfo.m_temporalId = nalu.m_temporalId;
picInfo.m_POC = m_apcSlicePilot->getPOC();
m_accessUnitPicInfo.push_back(picInfo);
// Skip pictures due to random access
if (isRandomAccessSkipPicture(iSkipFrame, iPOCLastDisplay))
{
m_prevSliceSkipped = true;
m_skippedPOC = m_apcSlicePilot->getPOC();
return false;
}
// Skip TFD pictures associated with BLA/BLANT pictures
// clear previous slice skipped flag
m_prevSliceSkipped = false;
//we should only get a different poc for a new picture (with CTU address==0)
if (m_apcSlicePilot->getPOC() != m_prevPOC && !m_firstSliceInSequence[nalu.m_nuhLayerId] && (m_apcSlicePilot->getFirstCtuRsAddrInSlice() != 0))
{
msg( WARNING, "Warning, the first slice of a picture might have been lost!\n");
}
m_prevLayerID = nalu.m_nuhLayerId;
// leave when a new picture is found
if(m_apcSlicePilot->getFirstCtuRsAddrInSlice() == 0 && !m_bFirstSliceInPicture)
{
if (m_prevPOC >= m_pocRandomAccess)
{
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 0 ) );
m_prevPOC = m_apcSlicePilot->getPOC();
return true;
}
m_prevPOC = m_apcSlicePilot->getPOC();
}
else
{
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
}
//detect lost reference picture and insert copy of earlier frame.
{
int lostPoc;
int refPicIndex;
while ((lostPoc = m_apcSlicePilot->checkThatAllRefPicsAreAvailable(m_cListPic, m_apcSlicePilot->getRPL0(), 0, true, &refPicIndex, m_apcSlicePilot->getNumRefIdx(REF_PIC_LIST_0))) > 0)
{
if( !pps->getMixedNaluTypesInPicFlag() && ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) && m_picHeader.getNoOutputBeforeRecoveryFlag() )
{
if (m_apcSlicePilot->getRPL0()->isInterLayerRefPic(refPicIndex) == 0)
{
xCreateUnavailablePicture(lostPoc - 1, m_apcSlicePilot->getRPL0()->isRefPicLongterm(refPicIndex), m_apcSlicePilot->getPic()->layerId, m_apcSlicePilot->getRPL0()->isInterLayerRefPic(refPicIndex));
}
}
else
{
xCreateLostPicture( lostPoc - 1, m_apcSlicePilot->getPic()->layerId );
}
}
while ((lostPoc = m_apcSlicePilot->checkThatAllRefPicsAreAvailable(m_cListPic, m_apcSlicePilot->getRPL1(), 0, true, &refPicIndex, m_apcSlicePilot->getNumRefIdx(REF_PIC_LIST_1))) > 0)
{
if( !pps->getMixedNaluTypesInPicFlag() && ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) && m_picHeader.getNoOutputBeforeRecoveryFlag() )
{
if (m_apcSlicePilot->getRPL1()->isInterLayerRefPic(refPicIndex) == 0)
{
xCreateUnavailablePicture(lostPoc - 1, m_apcSlicePilot->getRPL1()->isRefPicLongterm(refPicIndex), m_apcSlicePilot->getPic()->layerId, m_apcSlicePilot->getRPL1()->isInterLayerRefPic(refPicIndex));
}
}
else
{
xCreateLostPicture( lostPoc - 1, m_apcSlicePilot->getPic()->layerId );
}
}
}
m_prevPOC = m_apcSlicePilot->getPOC();
if (m_bFirstSliceInPicture)
{
xUpdateRasInit(m_apcSlicePilot);
}
// actual decoding starts here
xActivateParameterSets( nalu.m_nuhLayerId );
m_firstSliceInSequence[nalu.m_nuhLayerId] = false;
m_firstSliceInBitstream = false;
Slice* pcSlice = m_pcPic->slices[m_uiSliceSegmentIdx];
pcSlice->setPic( m_pcPic );
m_pcPic->poc = pcSlice->getPOC();
m_pcPic->layer = pcSlice->getTLayer();
m_pcPic->referenced = true;
m_pcPic->layer = nalu.m_temporalId;
m_pcPic->layerId = nalu.m_nuhLayerId;
m_pcPic->subLayerNonReferencePictureDueToSTSA = false;
if (m_bFirstSliceInPicture)
{
m_pcPic->setDecodingOrderNumber(m_decodingOrderCounter);
m_decodingOrderCounter++;
m_pcPic->setPictureType(nalu.m_nalUnitType);
}
pcSlice->checkCRA(pcSlice->getRPL0(), pcSlice->getRPL1(), m_pocCRA, m_cListPic);
pcSlice->constructRefPicList(m_cListPic);
pcSlice->checkRPL(pcSlice->getRPL0(), pcSlice->getRPL1(), m_associatedIRAPDecodingOrderNumber, m_cListPic);
pcSlice->checkSTSA(m_cListPic);
pcSlice->scaleRefPicList( scaledRefPic, m_pcPic->cs->picHeader, m_parameterSetManager.getAPSs(), m_picHeader.getLmcsAPS(), m_picHeader.getScalingListAPS(), true );
#if JVET_R0276_REORDERED_SUBPICS
// For each value of i in the range of 0 to sps_num_subpics_minus1, inclusive, when the value of SubpicIdVal[ i ] of a current picture is not equal to the value of SubpicIdVal[ i ] of a reference picture,
// the active entries of the RPLs of the coded slices in the i-th subpicture of the current picture shall not include that reference picture.
if( sps->getSubPicInfoPresentFlag() )
{
// store sub-picture IDs with a picture
if( m_bFirstSliceInPicture )
{
pcSlice->getPic()->subPicIDs.clear();
for( int subPicIdx = 0; subPicIdx < sps->getNumSubPics(); subPicIdx++ )
{
pcSlice->getPic()->subPicIDs.push_back( pps->getSubPic( subPicIdx ).getSubPicID() );
}
}
if( !pcSlice->isIntra() )
{
int currentSubPicIdx = NOT_VALID;
// derive sub-picture index for a slice
for( int subPicIdx = 0; subPicIdx < sps->getNumSubPics(); subPicIdx++ )
{
if( pps->getSubPic( subPicIdx ).getSubPicID() == pcSlice->getSliceSubPicId() )
{
currentSubPicIdx = subPicIdx;
break;
}
}
CHECK( currentSubPicIdx == NOT_VALID, "Sub-picture was not found" );
// check collocated sub-picture ID of each active reference picture
for( int refPicList = 0; refPicList < NUM_REF_PIC_LIST_01; refPicList++ )
{
for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( RefPicList( refPicList ) ); refIdx++ )
{
Picture* refPic = pcSlice->getRefPic( RefPicList( refPicList ), refIdx );
if( refPic->layerId == nalu.m_nuhLayerId )
{
CHECK( currentSubPicIdx >= refPic->subPicIDs.size(), "Number of sub-pictures in a reference picture is less then the current slice sub-picture index" );
CHECK( refPic->subPicIDs[currentSubPicIdx] != pcSlice->getSliceSubPicId(), "A picture with different sub-picture ID of the collocated sub-picture cannot be used as an active reference picture" );
}
}
}
}
}
#endif
if (!pcSlice->isIntra())
{
bool bLowDelay = true;
int iCurrPOC = pcSlice->getPOC();
int iRefIdx = 0;
for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++)
{
if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC )
{
bLowDelay = false;
}
}
if (pcSlice->isInterB())
{
for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++)
{
if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC )
{
bLowDelay = false;
}
}
}
pcSlice->setCheckLDC(bLowDelay);
}
if (pcSlice->getSPS()->getUseSMVD() && pcSlice->getCheckLDC() == false
&& pcSlice->getPicHeader()->getMvdL1ZeroFlag() == false
)
{
int currPOC = pcSlice->getPOC();
int forwardPOC = currPOC;
int backwardPOC = currPOC;
int ref = 0;
int refIdx0 = -1;
int refIdx1 = -1;
// search nearest forward POC in List 0
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
if ( poc < currPOC && (poc > forwardPOC || refIdx0 == -1) && !isRefLongTerm )
{
forwardPOC = poc;
refIdx0 = ref;
}
}
// search nearest backward POC in List 1
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
if ( poc > currPOC && (poc < backwardPOC || refIdx1 == -1) && !isRefLongTerm )
{
backwardPOC = poc;
refIdx1 = ref;
}
}
if ( !(forwardPOC < currPOC && backwardPOC > currPOC) )
{
forwardPOC = currPOC;
backwardPOC = currPOC;
refIdx0 = -1;
refIdx1 = -1;
// search nearest backward POC in List 0
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
if ( poc > currPOC && (poc < backwardPOC || refIdx0 == -1) && !isRefLongTerm )
{
backwardPOC = poc;
refIdx0 = ref;
}
}
// search nearest forward POC in List 1
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
if ( poc < currPOC && (poc > forwardPOC || refIdx1 == -1) && !isRefLongTerm )
{
forwardPOC = poc;
refIdx1 = ref;
}
}
}
if ( forwardPOC < currPOC && backwardPOC > currPOC )
{
pcSlice->setBiDirPred( true, refIdx0, refIdx1 );
}
else
{
pcSlice->setBiDirPred( false, -1, -1 );
}
}
else
{
pcSlice->setBiDirPred( false, -1, -1 );
}
//---------------
pcSlice->setRefPOCList();
NalUnitInfo naluInfo;
naluInfo.m_nalUnitType = nalu.m_nalUnitType;
naluInfo.m_nuhLayerId = nalu.m_nuhLayerId;
naluInfo.m_firstCTUinSlice = pcSlice->getFirstCtuRsAddrInSlice();
naluInfo.m_POC = pcSlice->getPOC();
xCheckMixedNalUnit(pcSlice, sps, nalu);
m_nalUnitInfo[naluInfo.m_nuhLayerId].push_back(naluInfo);
SEIMessages drapSEIs = getSeisByType(m_pcPic->SEIs, SEI::DEPENDENT_RAP_INDICATION );
if (!drapSEIs.empty())
{
msg( NOTICE, "Dependent RAP indication SEI decoded\n");
pcSlice->setDRAP(true);
pcSlice->setLatestDRAPPOC(pcSlice->getPOC());
}
pcSlice->checkConformanceForDRAP(nalu.m_temporalId);
Quant *quant = m_cTrQuant.getQuant();
if (pcSlice->getExplicitScalingListUsed())
{
APS* scalingListAPS = pcSlice->getPicHeader()->getScalingListAPS();
ScalingList scalingList = scalingListAPS->getScalingList();
quant->setScalingListDec(scalingList);
quant->setUseScalingList(true);
}
else
{
quant->setUseScalingList( false );
}
if (pcSlice->getSPS()->getUseLmcs())
{
if (m_bFirstSliceInPicture)
m_sliceLmcsApsId = -1;
if (pcSlice->getLmcsEnabledFlag())
{
APS* lmcsAPS = pcSlice->getPicHeader()->getLmcsAPS();
if (m_sliceLmcsApsId == -1)
{
m_sliceLmcsApsId = lmcsAPS->getAPSId();
}
else
{
CHECK(lmcsAPS->getAPSId() != m_sliceLmcsApsId, "same APS ID shall be used for all slices in one picture");
}
SliceReshapeInfo& sInfo = lmcsAPS->getReshaperAPSInfo();
SliceReshapeInfo& tInfo = m_cReshaper.getSliceReshaperInfo();
tInfo.reshaperModelMaxBinIdx = sInfo.reshaperModelMaxBinIdx;
tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx;
memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS));
tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW;
tInfo.chrResScalingOffset = sInfo.chrResScalingOffset;
tInfo.setUseSliceReshaper(pcSlice->getLmcsEnabledFlag());
tInfo.setSliceReshapeChromaAdj(pcSlice->getPicHeader()->getLmcsChromaResidualScaleFlag());
tInfo.setSliceReshapeModelPresentFlag(true);
}
else
{
SliceReshapeInfo& tInfo = m_cReshaper.getSliceReshaperInfo();
tInfo.setUseSliceReshaper(false);
tInfo.setSliceReshapeChromaAdj(false);
tInfo.setSliceReshapeModelPresentFlag(false);
}
if (pcSlice->getLmcsEnabledFlag())
{
m_cReshaper.constructReshaper();
}
else
{
m_cReshaper.setReshapeFlag(false);
}
if ((pcSlice->getSliceType() == I_SLICE) && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper())
{
m_cReshaper.setCTUFlag(false);
m_cReshaper.setRecReshaped(true);
}
else
{
if (m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper())
{
m_cReshaper.setCTUFlag(true);
m_cReshaper.setRecReshaped(true);
}
else
{
m_cReshaper.setCTUFlag(false);
m_cReshaper.setRecReshaped(false);
}
}
m_cReshaper.setVPDULoc(-1, -1);
}
else
{
m_cReshaper.setCTUFlag(false);
m_cReshaper.setRecReshaped(false);
}
// Decode a picture
m_cSliceDecoder.decompressSlice( pcSlice, &( nalu.getBitstream() ), ( m_pcPic->poc == getDebugPOC() ? getDebugCTU() : -1 ) );
m_bFirstSliceInPicture = false;
m_uiSliceSegmentIdx++;
pcSlice->freeScaledRefPicList( scaledRefPic );
return false;
}
void DecLib::updateAssociatedIRAP()
{
const NalUnitType pictureType = m_pcPic->getPictureType();
if (pictureType == NAL_UNIT_CODED_SLICE_IDR_W_RADL || pictureType == NAL_UNIT_CODED_SLICE_IDR_N_LP || pictureType == NAL_UNIT_CODED_SLICE_CRA)
{
m_associatedIRAPDecodingOrderNumber = m_pcPic->getDecodingOrderNumber();
m_pocCRA = m_pcPic->getPOC();
m_associatedIRAPType = pictureType;
}
}
void DecLib::xDecodeVPS( InputNALUnit& nalu )
{
m_vps = new VPS();
m_HLSReader.setBitstream( &nalu.getBitstream() );
CHECK( nalu.m_temporalId, "The value of TemporalId of VPS NAL units shall be equal to 0" );
m_HLSReader.parseVPS( m_vps );
m_parameterSetManager.storeVPS( m_vps, nalu.getBitstream().getFifo());
}
void DecLib::xDecodeDCI(InputNALUnit& nalu)
{
m_HLSReader.setBitstream(&nalu.getBitstream());
CHECK(nalu.m_temporalId, "The value of TemporalId of DCI NAL units shall be equal to 0");
if (!m_dci)
{
m_dci = new DCI;
m_HLSReader.parseDCI(m_dci);
}
else
{
DCI dupDCI;
m_HLSReader.parseDCI(&dupDCI);
CHECK( !m_dci->IsIndenticalDCI(dupDCI), "Two signaled DCIs are different");
}
}
void DecLib::xDecodeSPS( InputNALUnit& nalu )
{
SPS* sps = new SPS();
m_HLSReader.setBitstream( &nalu.getBitstream() );
CHECK( nalu.m_temporalId, "The value of TemporalId of SPS NAL units shall be equal to 0" );
m_HLSReader.parseSPS( sps );
DTRACE( g_trace_ctx, D_QP_PER_CTU, "CTU Size: %dx%d", sps->getMaxCUWidth(), sps->getMaxCUHeight() );
m_parameterSetManager.storeSPS( sps, nalu.getBitstream().getFifo() );
}
void DecLib::xDecodePPS( InputNALUnit& nalu )
{
PPS* pps = new PPS();
m_HLSReader.setBitstream( &nalu.getBitstream() );
m_HLSReader.parsePPS( pps );
pps->setLayerId( nalu.m_nuhLayerId );
pps->setTemporalId( nalu.m_temporalId );
m_parameterSetManager.storePPS( pps, nalu.getBitstream().getFifo() );
}
void DecLib::xDecodeAPS(InputNALUnit& nalu)
{
APS* aps = new APS();
m_HLSReader.setBitstream(&nalu.getBitstream());
m_HLSReader.parseAPS(aps);
aps->setTemporalId(nalu.m_temporalId);
aps->setLayerId( nalu.m_nuhLayerId );
#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
aps->setHasPrefixNalUnitType( nalu.m_nalUnitType == NAL_UNIT_PREFIX_APS );
#endif
m_parameterSetManager.checkAuApsContent( aps, m_accessUnitApsNals );
// aps will be deleted if it was already stored (and did not changed),
// thus, storing it must be last action.
m_parameterSetManager.storeAPS(aps, nalu.getBitstream().getFifo());
}
bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, int iTargetOlsIdx)
{
bool ret;
// ignore all NAL units of layers > 0
m_accessUnitNals.push_back( std::pair<NalUnitType, int>( nalu.m_nalUnitType, nalu.m_temporalId ) );
#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
m_pictureUnitNals.push_back( nalu.m_nalUnitType );
#endif
switch (nalu.m_nalUnitType)
{
case NAL_UNIT_VPS:
xDecodeVPS( nalu );
m_vps->m_targetOlsIdx = iTargetOlsIdx;
return false;
case NAL_UNIT_DCI:
xDecodeDCI( nalu );
return false;
case NAL_UNIT_SPS:
xDecodeSPS( nalu );
return false;
case NAL_UNIT_PPS:
xDecodePPS( nalu );
return false;
case NAL_UNIT_PH:
xDecodePicHeader(nalu);
return !m_bFirstSliceInPicture;
case NAL_UNIT_PREFIX_APS:
case NAL_UNIT_SUFFIX_APS:
xDecodeAPS(nalu);
return false;
case NAL_UNIT_PREFIX_SEI:
// Buffer up prefix SEI messages until SPS of associated VCL is known.
m_prefixSEINALUs.push_back(new InputNALUnit(nalu));
#if JVET_Q0488_SEI_REPETITION_CONSTRAINT
m_pictureSeiNalus.push_back(new InputNALUnit(nalu));
#endif
return false;
case NAL_UNIT_SUFFIX_SEI:
if (m_pcPic)
{
#if JVET_Q0488_SEI_REPETITION_CONSTRAINT
m_pictureSeiNalus.push_back(new InputNALUnit(nalu));
#endif
m_accessUnitSeiTids.push_back(nalu.m_temporalId);
const SPS *sps = m_parameterSetManager.getActiveSPS();
const VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId());
m_seiReader.parseSEImessage( &(nalu.getBitstream()), m_pcPic->SEIs, nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId, vps, sps, m_HRD, m_pDecodedSEIOutputStream );
m_accessUnitSeiPayLoadTypes.push_back(std::tuple<NalUnitType, int, SEI::PayloadType>(nalu.m_nalUnitType, nalu.m_nuhLayerId, m_pcPic->SEIs.back()->payloadType()));
}
else
{
msg( NOTICE, "Note: received suffix SEI but no picture currently active.\n");
}
return false;
case NAL_UNIT_CODED_SLICE_TRAIL:
case NAL_UNIT_CODED_SLICE_STSA:
case NAL_UNIT_CODED_SLICE_IDR_W_RADL:
case NAL_UNIT_CODED_SLICE_IDR_N_LP:
case NAL_UNIT_CODED_SLICE_CRA:
case NAL_UNIT_CODED_SLICE_GDR:
case NAL_UNIT_CODED_SLICE_RADL:
case NAL_UNIT_CODED_SLICE_RASL:
ret = xDecodeSlice(nalu, iSkipFrame, iPOCLastDisplay);
return ret;
case NAL_UNIT_EOS:
m_associatedIRAPType = NAL_UNIT_INVALID;
m_pocCRA = 0;
m_pocRandomAccess = MAX_INT;
m_prevLayerID = MAX_INT;
m_prevPOC = MAX_INT;
m_prevSliceSkipped = false;
m_skippedPOC = 0;
return false;
case NAL_UNIT_ACCESS_UNIT_DELIMITER:
{
AUDReader audReader;
uint32_t picType;
audReader.parseAccessUnitDelimiter(&(nalu.getBitstream()),picType);
return !m_bFirstSliceInPicture;
}
case NAL_UNIT_EOB:
return false;
case NAL_UNIT_RESERVED_IRAP_VCL_11:
case NAL_UNIT_RESERVED_IRAP_VCL_12:
msg( NOTICE, "Note: found reserved VCL NAL unit.\n");
xParsePrefixSEIsForUnknownVCLNal();
return false;
case NAL_UNIT_RESERVED_VCL_4:
case NAL_UNIT_RESERVED_VCL_5:
case NAL_UNIT_RESERVED_VCL_6:
case NAL_UNIT_RESERVED_NVCL_26:
case NAL_UNIT_RESERVED_NVCL_27:
msg( NOTICE, "Note: found reserved NAL unit.\n");
return false;
case NAL_UNIT_UNSPECIFIED_28:
case NAL_UNIT_UNSPECIFIED_29:
case NAL_UNIT_UNSPECIFIED_30:
case NAL_UNIT_UNSPECIFIED_31:
msg( NOTICE, "Note: found unspecified NAL unit.\n");
return false;
default:
THROW( "Invalid NAL unit type" );
break;
}
return false;
}
/** Function for checking if picture should be skipped because of random access. This function checks the skipping of pictures in the case of -s option random access.
* All pictures prior to the random access point indicated by the counter iSkipFrame are skipped.
* It also checks the type of Nal unit type at the random access point.
* If the random access point is CRA/CRANT/BLA/BLANT, TFD pictures with POC less than the POC of the random access point are skipped.
* If the random access point is IDR all pictures after the random access point are decoded.
* If the random access point is none of the above, a warning is issues, and decoding of pictures with POC
* equal to or greater than the random access point POC is attempted. For non IDR/CRA/BLA random
* access point there is no guarantee that the decoder will not crash.
*/
bool DecLib::isRandomAccessSkipPicture( int& iSkipFrame, int& iPOCLastDisplay )
{
if (iSkipFrame)
{
iSkipFrame--; // decrement the counter
return true;
}
else if ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP )
{
m_pocRandomAccess = -MAX_INT; // no need to skip the reordered pictures in IDR, they are decodable.
}
else if (m_pocRandomAccess == MAX_INT) // start of random access point, m_pocRandomAccess has not been set yet.
{
if (m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA )
{
// set the POC random access since we need to skip the reordered pictures in the case of CRA/CRANT/BLA/BLANT.
m_pocRandomAccess = m_apcSlicePilot->getPOC();
}
else
{
if(!m_warningMessageSkipPicture)
{
msg( WARNING, "\nWarning: this is not a valid random access point and the data is discarded until the first CRA picture");
m_warningMessageSkipPicture = true;
}
return true;
}
}
// skip the reordered pictures, if necessary
else if (m_apcSlicePilot->getPOC() < m_pocRandomAccess && (m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL))
{
iPOCLastDisplay++;
return true;
}
// if we reach here, then the picture is not skipped.
return false;
}
void DecLib::checkNalUnitConstraints( uint32_t naluType )
{
if (m_parameterSetManager.getActiveSPS() != NULL && m_parameterSetManager.getActiveSPS()->getProfileTierLevel() != NULL)
{
const ConstraintInfo *cInfo = m_parameterSetManager.getActiveSPS()->getProfileTierLevel()->getConstraintInfo();
xCheckNalUnitConstraintFlags( cInfo, naluType );
}
}
void DecLib::xCheckNalUnitConstraintFlags( const ConstraintInfo *cInfo, uint32_t naluType )
{
if (cInfo != NULL)
{
CHECK(cInfo->getNoTrailConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_TRAIL,
"Non-conforming bitstream. no_trail_constraint_flag is equal to 1 but bitstream contains NAL unit of type TRAIL_NUT.");
CHECK(cInfo->getNoStsaConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_STSA,
"Non-conforming bitstream. no_stsa_constraint_flag is equal to 1 but bitstream contains NAL unit of type STSA_NUT.");
CHECK(cInfo->getNoRaslConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_RASL,
"Non-conforming bitstream. no_rasl_constraint_flag is equal to 1 but bitstream contains NAL unit of type RASL_NUT.");
CHECK(cInfo->getNoRadlConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_RADL,
"Non-conforming bitstream. no_radl_constraint_flag is equal to 1 but bitstream contains NAL unit of type RADL_NUT.");
CHECK(cInfo->getNoIdrConstraintFlag() && (naluType == NAL_UNIT_CODED_SLICE_IDR_W_RADL),
"Non-conforming bitstream. no_idr_constraint_flag is equal to 1 but bitstream contains NAL unit of type IDR_W_RADL.");
CHECK(cInfo->getNoIdrConstraintFlag() && (naluType == NAL_UNIT_CODED_SLICE_IDR_N_LP),
"Non-conforming bitstream. no_idr_constraint_flag is equal to 1 but bitstream contains NAL unit of type IDR_N_LP.");
CHECK(cInfo->getNoCraConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_CRA,
"Non-conforming bitstream. no_cra_constraint_flag is equal to 1 but bitstream contains NAL unit of type CRA_NUT.");
CHECK(cInfo->getNoGdrConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_GDR,
"Non-conforming bitstream. no_gdr_constraint_flag is equal to 1 but bitstream contains NAL unit of type GDR_NUT.");
CHECK(cInfo->getNoApsConstraintFlag() && naluType == NAL_UNIT_PREFIX_APS,
"Non-conforming bitstream. no_aps_constraint_flag is equal to 1 but bitstream contains NAL unit of type APS_PREFIX_NUT.");
CHECK(cInfo->getNoApsConstraintFlag() && naluType == NAL_UNIT_SUFFIX_APS,
"Non-conforming bitstream. no_aps_constraint_flag is equal to 1 but bitstream contains NAL unit of type APS_SUFFIX_NUT.");
}
}
void DecLib::xCheckMixedNalUnit(Slice* pcSlice, SPS *sps, InputNALUnit &nalu)
{
if (pcSlice->getPPS()->getMixedNaluTypesInPicFlag())
{
CHECK(pcSlice->getPPS()->getNumSlicesInPic() < 2, "mixed nal unit type picture, but with less than 2 slices");
#if JVET_R0203_IRAP_LEADING_CONSTRAINT
CHECK( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR, "picture with mixed NAL unit type cannot have GDR slice");
//Check that if current slice is IRAP type, the other type of NAL can only be TRAIL_NUT
if( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA )
{
for( int i = 0; i < m_uiSliceSegmentIdx; i++ )
{
Slice* PreSlice = m_pcPic->slices[i];
CHECK( (pcSlice->getNalUnitType() != PreSlice->getNalUnitType()) && (PreSlice->getNalUnitType() != NAL_UNIT_CODED_SLICE_TRAIL), "In a mixed NAL unt type picture, an IRAP slice can be mixed with Trail slice(s) only");
}
}
// if this is the last slice of the picture, check whether that there are at least two different NAL unit types in the picture
if (pcSlice->getPPS()->getNumSlicesInPic() == (m_uiSliceSegmentIdx + 1))
{
bool hasDiffTypes = false;
for( int i = 1; !hasDiffTypes && i <= m_uiSliceSegmentIdx; i++ )
{
Slice* slice1 = m_pcPic->slices[i-1];
Slice* slice2 = m_pcPic->slices[i];
if( slice1->getNalUnitType() != slice2->getNalUnitType())
{
hasDiffTypes = true;
}
}
CHECK( !hasDiffTypes, "VCL NAL units of the picture shall have two or more different nal_unit_type values");
}
#endif
const unsigned ctuRsAddr = pcSlice->getCtuAddrInSlice(0);
const unsigned ctuXPosInCtus = ctuRsAddr % pcSlice->getPPS()->getPicWidthInCtu();
const unsigned ctuYPosInCtus = ctuRsAddr / pcSlice->getPPS()->getPicWidthInCtu();
const unsigned maxCUSize = sps->getMaxCUWidth();
Position pos(ctuXPosInCtus*maxCUSize, ctuYPosInCtus*maxCUSize);
const SubPic &curSubPic = pcSlice->getPPS()->getSubPicFromPos(pos);
// check subpicture constraints
if ((pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_IDR_W_RADL) && (pcSlice->getNalUnitType() <= NAL_UNIT_CODED_SLICE_CRA))
{
CHECK(curSubPic.getTreatedAsPicFlag() != true, "a slice of IDR_W_RADL to CRA_NUT shall have its subpic's sub_pic_treated_as_pic_flag equal to 1");
}
else
{
// check reference list constraint
if (!m_nalUnitInfo[nalu.m_nuhLayerId].empty())
{
//find out the closest IRAP nal unit that are in the same layer and in the corresponding subpicture
NalUnitInfo *latestIRAPNalUnit = nullptr;
int size = (int)m_nalUnitInfo[nalu.m_nuhLayerId].size();
int naluIdx;
for (naluIdx = size - 1; naluIdx >= 0; naluIdx--)
{
NalUnitInfo *iterNalu = &m_nalUnitInfo[nalu.m_nuhLayerId][naluIdx];
bool isIRAPSlice = iterNalu->m_nalUnitType >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && iterNalu->m_nalUnitType <= NAL_UNIT_CODED_SLICE_CRA;
if (isIRAPSlice)
{
latestIRAPNalUnit = iterNalu;
break;
}
}
if (latestIRAPNalUnit != nullptr && ((latestIRAPNalUnit->m_nalUnitType >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && latestIRAPNalUnit->m_nalUnitType <= NAL_UNIT_CODED_SLICE_IDR_N_LP)
|| (latestIRAPNalUnit->m_nalUnitType == NAL_UNIT_CODED_SLICE_CRA && pcSlice->getPOC() > latestIRAPNalUnit->m_POC)))
{
// clear the nalu unit before the latest IRAP slice
m_nalUnitInfo[nalu.m_nuhLayerId].erase(m_nalUnitInfo[nalu.m_nuhLayerId].begin(), m_nalUnitInfo[nalu.m_nuhLayerId].begin() + naluIdx);
const unsigned ctuRsAddrIRAP = latestIRAPNalUnit->m_firstCTUinSlice;
const unsigned ctuXPosInCtusIRAP = ctuRsAddrIRAP % pcSlice->getPPS()->getPicWidthInCtu();
const unsigned ctuYPosInCtusIRAP = ctuRsAddrIRAP / pcSlice->getPPS()->getPicWidthInCtu();
Position posIRAP(ctuXPosInCtusIRAP*maxCUSize, ctuYPosInCtusIRAP*maxCUSize);
bool isInCorrespondingSubpic = curSubPic.isContainingPos(posIRAP);
if (isInCorrespondingSubpic)
{
// check RefPicList[0]
for (int refIdx = 0; refIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0); refIdx++)
{
int POC = pcSlice->getRefPOC(REF_PIC_LIST_0, refIdx);
bool notInPOCAfterIRAP = true;
// check all ref pics of the current slice are from poc after the IRAP slice
for (auto iterNalu : m_nalUnitInfo[nalu.m_nuhLayerId])
{
if (POC == iterNalu.m_POC)
notInPOCAfterIRAP = false;
}
CHECK(notInPOCAfterIRAP, "all reference pictures of a slice after the IRAP picture are from pictures after the IRAP");
}
// check RefPicList[1]
for (int refIdx = 0; refIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1); refIdx++)
{
int POC = pcSlice->getRefPOC(REF_PIC_LIST_1, refIdx);
bool notInPOCAfterIRAP = true;
// check all ref pics of the current slice are from poc after the IRAP slice
for (auto iterNalu : m_nalUnitInfo[nalu.m_nuhLayerId])
{
if (POC == iterNalu.m_POC)
notInPOCAfterIRAP = false;
}
CHECK(notInPOCAfterIRAP, "all reference pictures of a slice after the IRAP picture are from pictures after the IRAP");
}
}
}
}
}
#if !JVET_R0203_IRAP_LEADING_CONSTRAINT
// if this is the last slice of the picture, check whether the nalu type of the slices meet the nal unit type constraints
if (pcSlice->getPPS()->getNumSlicesInPic() == (m_uiSliceSegmentIdx + 1))
{
std::set<NalUnitType> firstSet = { NAL_UNIT_CODED_SLICE_STSA, NAL_UNIT_CODED_SLICE_RADL,
NAL_UNIT_CODED_SLICE_RASL, NAL_UNIT_CODED_SLICE_IDR_W_RADL, NAL_UNIT_CODED_SLICE_IDR_N_LP, NAL_UNIT_CODED_SLICE_CRA };
std::set<NalUnitType> secondSet = { NAL_UNIT_CODED_SLICE_TRAIL, NAL_UNIT_CODED_SLICE_RADL, NAL_UNIT_CODED_SLICE_RASL };
bool allNalsOK = true;
bool foundNalInOtherSet = false;
//if the NAL unit of the current slice is in the first set
if (firstSet.find(pcSlice->getNalUnitType()) != firstSet.end())
{
NalUnitType otherNalType = pcSlice->getNalUnitType();
for (int i = 0; i < m_uiSliceSegmentIdx; i++)
{
Slice* PreSlice = m_pcPic->slices[i];
if (PreSlice->getNalUnitType() != pcSlice->getNalUnitType())
{
foundNalInOtherSet = true;
//Set the value of the other NAL unit type the first time a different NAL unit is found
if (otherNalType == pcSlice->getNalUnitType())
{
otherNalType = PreSlice->getNalUnitType();
}
if (otherNalType != PreSlice->getNalUnitType())
{
allNalsOK = false;
}
if (secondSet.find(PreSlice->getNalUnitType()) == secondSet.end())
{
allNalsOK = false;
}
}
}
}
if (foundNalInOtherSet == false || allNalsOK == false)
{
allNalsOK = true;
foundNalInOtherSet = false;
//if the NAL unit of the current slice is in the second set
if (secondSet.find(pcSlice->getNalUnitType()) != secondSet.end())
{
NalUnitType otherNalType = pcSlice->getNalUnitType();
for (int i = 0; i < m_uiSliceSegmentIdx; i++)
{
Slice* PreSlice = m_pcPic->slices[i];
if (PreSlice->getNalUnitType() != pcSlice->getNalUnitType())
{
foundNalInOtherSet = true;
//Set the value of the other NAL unit type the first time a different NAL unit is found
if (otherNalType == pcSlice->getNalUnitType())
{
otherNalType = PreSlice->getNalUnitType();
}
if (otherNalType != PreSlice->getNalUnitType())
{
allNalsOK = false;
}
if (firstSet.find(PreSlice->getNalUnitType()) == firstSet.end())
{
allNalsOK = false;
}
}
}
}
CHECK(!allNalsOK || !foundNalInOtherSet, "disallowed mix of nal unit types");
}
}
#endif
}
else // all slices shall have the same nal unit type
{
bool sameNalUnitType = true;
for (int i = 0; i < m_uiSliceSegmentIdx; i++)
{
Slice *PreSlice = m_pcPic->slices[i];
if (PreSlice->getNalUnitType() != pcSlice->getNalUnitType())
sameNalUnitType = false;
}
CHECK(!sameNalUnitType, "mixed_nalu_types_in_pic_flag is zero, but have different nal unit types");
}
}
//! \}