From 4c3066591c49f506bc394caaac82cf2f5ca798db Mon Sep 17 00:00:00 2001 From: Brian Heng <brian.heng@broadcom.com> Date: Sun, 1 Dec 2019 09:02:22 -0800 Subject: [PATCH] JVET-P1006: Picture Header - Add Access Unit detection to support multi-layer streams containing multiple pictures per AU. --- source/App/DecoderApp/DecApp.cpp | 96 ++++++++++++++++++++++++++++- source/App/DecoderApp/DecApp.h | 1 + source/Lib/DecoderLib/DecLib.cpp | 57 +++++++++++++++++ source/Lib/DecoderLib/DecLib.h | 4 ++ source/Lib/DecoderLib/VLCReader.cpp | 47 ++++++++++++++ source/Lib/DecoderLib/VLCReader.h | 1 + 6 files changed, 205 insertions(+), 1 deletion(-) diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 9d529dfab..e4117cad8 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -124,6 +124,7 @@ uint32_t DecApp::decode() // determine if next NAL unit will be the first one from a new picture bool bNewPicture = isNewPicture(&bitstreamFile, &bytestream); + bool bNewAccessUnit = bNewPicture && isNewAccessUnit( bNewPicture, &bitstreamFile, &bytestream ); if(!bNewPicture) { AnnexBStats stats = AnnexBStats(); @@ -336,7 +337,7 @@ uint32_t DecApp::decode() } } #if JVET_P1006_PICTURE_HEADER - if(bNewPicture) + if(bNewAccessUnit) { m_cDecLib.resetAccessUnitNals(); m_cDecLib.resetAccessUnitApsNals(); @@ -478,6 +479,99 @@ bool DecApp::isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytest // return TRUE if next NAL unit is the start of a new picture return ret; } + +/** + - lookahead through next NAL units to determine if current NAL unit is the first NAL unit in a new access unit + */ +bool DecApp::isNewAccessUnit( bool newPicture, ifstream *bitstreamFile, class InputByteStream *bytestream ) +{ + bool ret = false; + bool finished = false; + + // can only be the start of an AU if this is the start of a new picture + if( newPicture == false ) + { + return false; + } + + // save stream position for backup +#if RExt__DECODER_DEBUG_STATISTICS + CodingStatistics::CodingStatisticsData* backupStats = new CodingStatistics::CodingStatisticsData(CodingStatistics::GetStatistics()); + streampos location = bitstreamFile->tellg() - streampos(bytestream->GetNumBufferedBytes()); +#else + streampos location = bitstreamFile->tellg(); +#endif + + // look ahead until access unit start location is determined + while (!finished && !!(*bitstreamFile)) + { + AnnexBStats stats = AnnexBStats(); + InputNALUnit nalu; + byteStreamNALUnit(*bytestream, nalu.getBitstream().getFifo(), stats); + if (nalu.getBitstream().getFifo().empty()) + { + msg( ERROR, "Warning: Attempt to decode an empty NAL unit\n"); + } + else + { + // get next NAL unit type + read(nalu); + switch( nalu.m_nalUnitType ) { + + // AUD always indicates the start of a new access unit + case NAL_UNIT_ACCESS_UNIT_DELIMITER: + ret = true; + finished = true; + break; + + // slice types - check layer ID and POC + case NAL_UNIT_CODED_SLICE_TRAIL: + case NAL_UNIT_CODED_SLICE_STSA: + case NAL_UNIT_CODED_SLICE_RASL: + case NAL_UNIT_CODED_SLICE_RADL: + 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: + ret = m_cDecLib.isSliceNaluFirstInAU( newPicture, nalu ); + finished = true; + break; + + // NUT that are not the start of a new access unit + case NAL_UNIT_EOS: + case NAL_UNIT_EOB: +#if JVET_P0588_SUFFIX_APS + case NAL_UNIT_SUFFIX_APS: +#endif + case NAL_UNIT_SUFFIX_SEI: + case NAL_UNIT_FD: + ret = false; + finished = true; + break; + + // all other NUT - keep looking to find first VCL + default: + break; + } + } + } + + // restore previous stream location +#if RExt__DECODER_DEBUG_BIT_STATISTICS + bitstreamFile->clear(); + bitstreamFile->seekg(location); + bytestream->reset(); + CodingStatistics::SetStatistics(*backupStats); + delete backupStats; +#else + bitstreamFile->clear(); + bitstreamFile->seekg(location); + bytestream->reset(); +#endif + + // return TRUE if next NAL unit is the start of a new picture + return ret; +} #endif // ==================================================================================================================== diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index f3108e7c7..9abfb2919 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -93,6 +93,7 @@ private: bool isNaluTheTargetLayer(InputNALUnit* nalu); ///< check whether given Nalu is within targetDecLayerIdSet #if JVET_P1006_PICTURE_HEADER bool isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytestream); ///< check if next NAL unit will be the first NAL unit from a new picture + bool isNewAccessUnit(bool newPicture, ifstream *bitstreamFile, class InputByteStream *bytestream); ///< check if next NAL unit will be the first NAL unit from a new access unit #endif }; diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index a61f646c0..d85de4df5 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -395,6 +395,9 @@ DecLib::DecLib() , m_cacheModel() #endif , m_pcPic(NULL) +#if JVET_P1006_PICTURE_HEADER + , m_prevLayerID(MAX_INT) +#endif , m_prevPOC(MAX_INT) , m_prevTid0POC(0) , m_bFirstSliceInPicture(true) @@ -847,6 +850,54 @@ void DecLib::xCreateUnavailablePicture(int iUnavailablePoc, bool longTermFlag) } +#if JVET_P1006_PICTURE_HEADER +/** + - 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 valid picture header + if(m_picHeader.isValid() == false) + { + 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.parseSliceHeaderToPoc( m_apcSlicePilot, &m_picHeader, &m_parameterSetManager, m_prevTid0POC ); + + // check for different POC + return (m_apcSlicePilot->getPOC() != m_prevPOC); +} +#endif + #if JVET_P1006_PICTURE_HEADER void activateAPS(PicHeader* picHeader, Slice* pSlice, ParameterSetManager& parameterSetManager, APS** apss, APS* lmcsAPS, APS* scalingListAPS) #else @@ -1449,6 +1500,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl { msg( WARNING, "Warning, the first slice of a picture might have been lost!\n"); } +#if JVET_P1006_PICTURE_HEADER + m_prevLayerID = nalu.m_nuhLayerId; +#endif // leave when a new picture is found if(m_apcSlicePilot->getSliceCurStartCtuTsAddr() == 0 && !m_bFirstSliceInPicture) @@ -1995,6 +2049,9 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay) m_associatedIRAPType = NAL_UNIT_INVALID; m_pocCRA = 0; m_pocRandomAccess = MAX_INT; +#if JVET_P1006_PICTURE_HEADER + m_prevLayerID = MAX_INT; +#endif m_prevPOC = MAX_INT; m_prevSliceSkipped = false; m_skippedPOC = 0; diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index e1d28c591..d2ae600d0 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -109,6 +109,9 @@ private: bool isRandomAccessSkipPicture(int& iSkipFrame, int& iPOCLastDisplay); Picture* m_pcPic; uint32_t m_uiSliceSegmentIdx; +#if JVET_P1006_PICTURE_HEADER + uint32_t m_prevLayerID; +#endif int m_prevPOC; int m_prevTid0POC; bool m_bFirstSliceInPicture; @@ -182,6 +185,7 @@ public: #if JVET_P1006_PICTURE_HEADER void resetAccessUnitNals() { m_accessUnitNals.clear(); } void resetAccessUnitApsNals() { m_accessUnitApsNals.clear(); } + bool isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu ); #endif #if JVET_N0278_FIXES diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 95b4d2616..cb902ad56 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -3596,6 +3596,53 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para return; } +#if JVET_P1006_PICTURE_HEADER +void HLSyntaxReader::parseSliceHeaderToPoc (Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC) +{ + uint32_t uiCode; + PPS* pps = NULL; + SPS* sps = NULL; + + CHECK(picHeader==0, "Invalid Picture Header"); + CHECK(picHeader->isValid()==false, "Invalid Picture Header"); + pps = parameterSetManager->getPPS( picHeader->getPPSId() ); + //!KS: need to add error handling code here, if PPS is not available + CHECK(pps==0, "Invalid PPS"); + sps = parameterSetManager->getSPS(pps->getSPSId()); + //!KS: need to add error handling code here, if SPS is not available + CHECK(sps==0, "Invalid SPS"); + + // picture order count + READ_CODE(sps->getBitsForPOC(), uiCode, "slice_pic_order_cnt_lsb"); + if (pcSlice->getIdrPicFlag()) + { + pcSlice->setPOC(uiCode); + } + else + { + int iPOClsb = uiCode; + int iPrevPOC = prevTid0POC; + int iMaxPOClsb = 1 << sps->getBitsForPOC(); + int iPrevPOClsb = iPrevPOC & (iMaxPOClsb - 1); + int iPrevPOCmsb = iPrevPOC - iPrevPOClsb; + int iPOCmsb; + if ((iPOClsb < iPrevPOClsb) && ((iPrevPOClsb - iPOClsb) >= (iMaxPOClsb / 2))) + { + iPOCmsb = iPrevPOCmsb + iMaxPOClsb; + } + else if ((iPOClsb > iPrevPOClsb) && ((iPOClsb - iPrevPOClsb) > (iMaxPOClsb / 2))) + { + iPOCmsb = iPrevPOCmsb - iMaxPOClsb; + } + else + { + iPOCmsb = iPrevPOCmsb; + } + pcSlice->setPOC(iPOCmsb + iPOClsb); + } +} + +#endif void HLSyntaxReader::parseConstraintInfo(ConstraintInfo *cinfo) { uint32_t symbol; diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h index 74bea8b8e..7598a66fd 100644 --- a/source/Lib/DecoderLib/VLCReader.h +++ b/source/Lib/DecoderLib/VLCReader.h @@ -161,6 +161,7 @@ public: #if JVET_P1006_PICTURE_HEADER void parsePictureHeader ( PicHeader* picHeader, ParameterSetManager *parameterSetManager ); void parseSliceHeader ( Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC ); + void parseSliceHeaderToPoc ( Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC ); #else void parseSliceHeader ( Slice* pcSlice, ParameterSetManager *parameterSetManager, const int prevTid0POC ); #endif -- GitLab