diff --git a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp index c31a7a5a7ba8b0c0f146a1e20f6d0d065d57256a..50f3c01cf708856c4019ed69cdc3e0702b271bca 100644 --- a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp +++ b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp @@ -172,6 +172,30 @@ bool BitstreamExtractorApp::xCheckSliceSubpicture(InputNALUnit &nalu, int target } #endif +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 +bool BitstreamExtractorApp::xCheckSEIFiller(SEIMessages SEIs, int targetSubPicId, bool &rmAllFillerInSubpicExt, bool lastSliceWritten) +{ + for (auto sei : SEIs) + { + if (sei->payloadType() == SEI::SUBPICTURE_LEVEL_INFO) + { + SEISubpicureLevelInfo *seiSLI = (SEISubpicureLevelInfo *)sei; + if (!seiSLI->m_cbrConstraintFlag) + { + rmAllFillerInSubpicExt = true; + } + } + } + for (auto sei : SEIs) + { + if (sei->payloadType() == SEI::FILLER_PAYLOAD) + { + return (rmAllFillerInSubpicExt ? false : lastSliceWritten); + } + } + return true; +} +#else bool BitstreamExtractorApp::xCheckSeiSubpicture(SEIMessages SEIs, int targetSubPicId, bool &rmAllFillerInSubpicExt, bool lastSliceWritten, bool isVclNalUnitRemoved) { bool isWriteSeiNalUnitToStream = true; @@ -242,6 +266,7 @@ bool BitstreamExtractorApp::xCheckSeiSubpicture(SEIMessages SEIs, int targetSubP return isWriteSeiNalUnitToStream; } +#endif void BitstreamExtractorApp::xRewriteSPS (SPS &targetSPS, const SPS &sourceSPS, SubPic &subPic) { @@ -479,7 +504,11 @@ bool BitstreamExtractorApp::xCheckNumSubLayers(InputNALUnit &nalu, VPS *vps) return retval; } +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 +bool BitstreamExtractorApp::xCheckSEIsSubPicture(SEIMessages& SEIs, InputNALUnit& nalu, std::ostream& out, int subpicId, VPS *vps) +#else bool BitstreamExtractorApp::xCheckSEIsSubPicture(SEIMessages& SEIs, InputNALUnit& nalu, std::ostream& out, int subpicId) +#endif { SEIMessages scalableNestingSEIs = getSeisByType(SEIs, SEI::SCALABLE_NESTING); if (scalableNestingSEIs.size()) @@ -496,12 +525,20 @@ bool BitstreamExtractorApp::xCheckSEIsSubPicture(SEIMessages& SEIs, InputNALUnit } if (std::find(sei->m_snSubpicId.begin(), sei->m_snSubpicId.end(), subpicId) != sei->m_snSubpicId.end()) { - // applies to target subpicture -> extract - OutputNALUnit outNalu( nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId ); - m_seiWriter.writeSEImessages(outNalu.m_Bitstream, sei->m_nestedSEIs, m_hrd, false, nalu.m_temporalId); - NALUnitEBSP naluWithHeader(outNalu); - writeAnnexBNalUnit(out, naluWithHeader, true); - return false; +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + // C.7 step 7.c + if (sei->m_snOlsFlag || vps->getNumLayersInOls(m_targetOlsIdx) == 1) + { +#endif + // applies to target subpicture -> extract + OutputNALUnit outNalu( nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId ); + m_seiWriter.writeSEImessages(outNalu.m_Bitstream, sei->m_nestedSEIs, m_hrd, false, nalu.m_temporalId); + NALUnitEBSP naluWithHeader(outNalu); + writeAnnexBNalUnit(out, naluWithHeader, true); + return false; +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + } +#endif } else { @@ -554,6 +591,86 @@ bool BitstreamExtractorApp::xCheckScalableNestingSEI(SEIScalableNesting *seiNest return nestingAppliedInTargetOlsLayerId; } +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 +bool BitstreamExtractorApp::xIsTargetOlsIncludeAllVclLayers() +{ + std::ifstream bitstreamFileIn(m_bitstreamFileNameIn.c_str(), std::ifstream::in | std::ifstream::binary); + if (!bitstreamFileIn) + { + EXIT("failed to open bitstream file " << m_bitstreamFileNameIn.c_str() << " for reading"); + } + + InputByteStream bytestream(bitstreamFileIn); + + bitstreamFileIn.clear(); + bitstreamFileIn.seekg(0, std::ios::beg); + + if (m_targetOlsIdx >= 0) + { + std::vector<int> layerIdInTargetOls; + std::vector<int> layerIdInVclNalu; + while (!!bitstreamFileIn) + { + AnnexBStats stats = AnnexBStats(); + InputNALUnit nalu; + byteStreamNALUnit(bytestream, nalu.getBitstream().getFifo(), stats); + + // call actual decoding function + if (nalu.getBitstream().getFifo().empty()) + { + msg(WARNING, "Warning: Attempt to decode an empty NAL unit"); + } + else + { + read(nalu); + + if (nalu.m_nalUnitType == NAL_UNIT_VPS) + { + VPS* vps = new VPS(); + m_hlSynaxReader.setBitstream(&nalu.getBitstream()); + m_hlSynaxReader.parseVPS(vps); + int vpsId = vps->getVPSId(); + // note: storeVPS may invalidate the vps pointer! + m_parameterSetManager.storeVPS(vps, nalu.getBitstream().getFifo()); + // get VPS back + vps = m_parameterSetManager.getVPS(vpsId); + m_vpsId = vps->getVPSId(); + } + + VPS *vps = nullptr; + if (m_vpsId > 0) + { + vps = m_parameterSetManager.getVPS(m_vpsId); + layerIdInTargetOls = vps->getLayerIdsInOls(m_targetOlsIdx); + if (NALUnit::isVclNalUnitType(nalu.m_nalUnitType)) + { + if (layerIdInVclNalu.size() == 0 || nalu.m_nuhLayerId >= layerIdInVclNalu[layerIdInVclNalu.size() - 1]) + { + layerIdInVclNalu.push_back(nalu.m_nuhLayerId); + } + else + { + break; + } + } + } + } + } + + //When LayerIdInOls[ targetOlsIdx ] does not include all values of nuh_layer_id in all VCL NAL units in the bitstream inBitstream + for (int i = 0; i < layerIdInVclNalu.size(); i++) + { + bool vclLayerIncludedInTargetOls = std::find(layerIdInTargetOls.begin(), layerIdInTargetOls.end(), layerIdInVclNalu[i]) != layerIdInTargetOls.end(); + if (!vclLayerIncludedInTargetOls) + { + return false; + } + } + } + return true; +} +#endif + uint32_t BitstreamExtractorApp::decode() { std::ifstream bitstreamFileIn(m_bitstreamFileNameIn.c_str(), std::ifstream::in | std::ifstream::binary); @@ -585,6 +702,10 @@ uint32_t BitstreamExtractorApp::decode() bool isMultiSubpicLayer[MAX_VPS_LAYERS] = { false }; bool rmAllFillerInSubpicExt[MAX_VPS_LAYERS] = { false }; +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + bool targetOlsIncludeAllVclLayers = xIsTargetOlsIncludeAllVclLayers(); +#endif + while (!!bitstreamFileIn) { AnnexBStats stats = AnnexBStats(); @@ -812,27 +933,55 @@ uint32_t BitstreamExtractorApp::decode() { writeInpuNalUnitToStream &= xCheckScalableNestingSEI(seiNesting, nalu, vps); } +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + // C.6 step 9.c + if (writeInpuNalUnitToStream && !targetOlsIncludeAllVclLayers && !seiNesting->m_snSubpicFlag) + { + if (seiNesting->m_snOlsFlag || vps->getNumLayersInOls(m_targetOlsIdx) == 1) + { + OutputNALUnit outNalu(nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId); + m_seiWriter.writeSEImessages(outNalu.m_Bitstream, seiNesting->m_nestedSEIs, m_hrd, false, nalu.m_temporalId); + NALUnitEBSP naluWithHeader(outNalu); + writeAnnexBNalUnit(bitstreamFileOut, naluWithHeader, true); + writeInpuNalUnitToStream = false; + } + } +#endif } // remove unqualified timing related SEI if (sei->payloadType() == SEI::BUFFERING_PERIOD || (m_removeTimingSEI && sei->payloadType() == SEI::PICTURE_TIMING) || sei->payloadType() == SEI::DECODING_UNIT_INFO || sei->payloadType() == SEI::SUBPICTURE_LEVEL_INFO) { +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + writeInpuNalUnitToStream &= targetOlsIncludeAllVclLayers; +#else bool targetOlsIdxGreaterThanZero = m_targetOlsIdx > 0; writeInpuNalUnitToStream &= !targetOlsIdxGreaterThanZero; +#endif } } +#if !JVET_S0154_ASPECT9_AND_S0158_ASPECT4 if (m_subPicIdx >= 0 && writeInpuNalUnitToStream) { writeInpuNalUnitToStream = xCheckSeiSubpicture(SEIs, subpicIdTarget[nalu.m_nuhLayerId], rmAllFillerInSubpicExt[nalu.m_nuhLayerId], lastSliceWritten, isVclNalUnitRemoved[nalu.m_nuhLayerId]); } +#endif if (m_vpsId == -1) { delete vps; } } +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + writeInpuNalUnitToStream &= xCheckSEIFiller(SEIs, subpicIdTarget[nalu.m_nuhLayerId], rmAllFillerInSubpicExt[nalu.m_nuhLayerId], lastSliceWritten); + if (writeInpuNalUnitToStream && isVclNalUnitRemoved[nalu.m_nuhLayerId] && m_subPicIdx >= 0) + { + writeInpuNalUnitToStream &= xCheckSEIsSubPicture(SEIs, nalu, bitstreamFileOut, subpicIdTarget[nalu.m_nuhLayerId], vps); + } +#else if (m_subPicIdx >= 0) { writeInpuNalUnitToStream &= xCheckSEIsSubPicture(SEIs, nalu, bitstreamFileOut, subpicIdTarget[nalu.m_nuhLayerId]); } +#endif } #if JVET_R0107_BITSTREAM_EXTACTION @@ -842,9 +991,15 @@ uint32_t BitstreamExtractorApp::decode() slice = xParseSliceHeader(nalu); } #endif +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + if (isMultiSubpicLayer[nalu.m_nuhLayerId] && writeInpuNalUnitToStream) + { + if (m_subPicIdx >= 0 && nalu.isSlice()) +#else if (m_subPicIdx >= 0 && isMultiSubpicLayer[nalu.m_nuhLayerId] && writeInpuNalUnitToStream) { if (nalu.isSlice()) +#endif { writeInpuNalUnitToStream = xCheckSliceSubpicture(slice, subpicIdTarget[nalu.m_nuhLayerId]); if (!writeInpuNalUnitToStream) diff --git a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h index 37767d95eeba909c87fc02c7d575dd82cc86a74c..1ff853487d70ec482a50e8b2e664a55856edaf52 100644 --- a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h +++ b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h @@ -65,7 +65,11 @@ protected: void xPrintSubPicInfo (PPS *pps); void xRewriteSPS (SPS &targetSPS, const SPS &sourceSPS, SubPic &subPic); void xRewritePPS (PPS &targetPPS, const PPS &sourcePPS, const SPS &sourceSPS, SubPic &subPic); +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + bool xCheckSEIFiller(SEIMessages SEIs, int targetSubPicId, bool &rmAllFillerInSubpicExt, bool lastSliceWritten); +#else bool xCheckSeiSubpicture(SEIMessages SEIs, int targetSubPicId, bool &rmAllFillerInSubpicExt, bool lastSliceWritten, bool isVclNalUnitRemoved); +#endif #if JVET_R0107_BITSTREAM_EXTACTION Slice xParseSliceHeader(InputNALUnit &nalu); @@ -74,7 +78,12 @@ protected: bool xCheckSliceSubpicture(InputNALUnit &nalu, int subPicId); #endif void xReadPicHeader(InputNALUnit &nalu); +#if JVET_S0154_ASPECT9_AND_S0158_ASPECT4 + bool xIsTargetOlsIncludeAllVclLayers(); + bool xCheckSEIsSubPicture(SEIMessages& SEIs, InputNALUnit& nalu, std::ostream& out, int subpicId, VPS *vps); +#else bool xCheckSEIsSubPicture(SEIMessages& SEIs, InputNALUnit& nalu, std::ostream& out, int subpicId); +#endif bool xCheckScalableNestingSEI(SEIScalableNesting *seiNesting, InputNALUnit& nalu, VPS *vps); void xSetSPSUpdated(int spsId) { return m_updatedSPSList.push_back(spsId); } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 22d0b53144a6fda32c0359546187840977012a82..10042e62624151f19edeefde80ceba2c258653cf 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -69,6 +69,10 @@ #define JVET_W2005_RANGE_EXTENSION_PROFILES 1 // JVET-W2005 (JVET-W0136 profile plus meeting decisions) +#define JVET_S0154_ASPECT9_AND_S0158_ASPECT4 1 // JVET-S0154 #9: In the subpicture sub-bitstream extraction process, insert SEI NAL units to directly contain those SEI messages that were scalable-nested HRD-related SEI messages that apply to the output bitstream, and remove their original container SEI NAL units from the output bitstream. When the target OLS includes only one layer, apply the same for scalable-nested non-HRD-related SEI messages. + // JVET-S0158 #4c: Insert SEI NAL units to directly contain those SEI messages that were scalable-nested HRD-related SEI messages that apply to the output bitstream, and remove their original container SEI NAL units from the output bitstream. When the target OLS includes only one layer, apply the same for scalable-nested non-HRD-related SEI messages. + + //########### place macros to be be kept below this line ############### #define GDR_ENABLED 1