diff --git a/cfg/sei_vui/annotated_regions/anno_reg_0.txt b/cfg/sei_vui/annotated_regions/anno_reg_0.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e8c985328f067e678c4832c0a8a047f5a456cc6 --- /dev/null +++ b/cfg/sei_vui/annotated_regions/anno_reg_0.txt @@ -0,0 +1,48 @@ +SEIArCancelFlag: 0 +SEIArNotOptForViewingFlag: 0 +SEIArTrueMotionFlag: 0 +SEIArOccludedObjsFlag: 0 +SEIArPartialObjsFlagPresentFlag: 0 +SEIArObjLabelPresentFlag: 1 +SEIArObjConfInfoPresentFlag: 1 +SEIArObjDetConfLength: 7 +SEIArObjLabelLangPresentFlag: 1 +SEIArLabelLanguage: ENGLISH +SEIArNumLabelUpdates: 2 +SEIArLabelIdc[c]: 0 +SEIArLabelCancelFlag[c]: 0 +SEIArLabel[c]: car +SEIArLabelIdc[c]: 1 +SEIArLabelCancelFlag[c]: 0 +SEIArLabel[c]: person +SEIArNumObjUpdates: 3 +SEIArObjIdx[c]: 0 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 1 +SEIArObjectLabelIdc[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 10 +SEIArObjLeft[c]: 10 +SEIArObjWidth[c]: 50 +SEIArObjHeight[c]: 50 +SEIArObjDetConf[c]: 90 +SEIArObjIdx[c]: 1 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 1 +SEIArObjectLabelIdc[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 100 +SEIArObjLeft[c]: 100 +SEIArObjWidth[c]: 50 +SEIArObjHeight[c]: 50 +SEIArObjDetConf[c]: 90 +SEIArObjIdx[c]: 2 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 1 +SEIArObjectLabelIdc[c]: 1 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 200 +SEIArObjLeft[c]: 200 +SEIArObjWidth[c]: 80 +SEIArObjHeight[c]: 100 +SEIArObjDetConf[c]: 85 diff --git a/cfg/sei_vui/annotated_regions/anno_reg_1.txt b/cfg/sei_vui/annotated_regions/anno_reg_1.txt new file mode 100644 index 0000000000000000000000000000000000000000..5508a22a77ae5728f72ed6ef4f62291716081ca7 --- /dev/null +++ b/cfg/sei_vui/annotated_regions/anno_reg_1.txt @@ -0,0 +1,31 @@ +SEIArCancelFlag: 0 +SEIArNotOptForViewingFlag: 0 +SEIArTrueMotionFlag: 0 +SEIArOccludedObjsFlag: 0 +SEIArPartialObjsFlagPresentFlag: 0 +SEIArObjLabelPresentFlag: 1 +SEIArObjConfInfoPresentFlag: 1 +SEIArObjDetConfLength: 7 +SEIArObjLabelLangPresentFlag: 1 +SEIArLabelLanguage: ENGLISH +SEIArNumLabelUpdates: 0 +SEIArNumObjUpdates: 2 +SEIArObjIdx[c]: 0 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 20 +SEIArObjLeft[c]: 20 +SEIArObjWidth[c]: 50 +SEIArObjHeight[c]: 50 +SEIArObjDetConf[c]: 90 +SEIArObjIdx[c]: 3 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 1 +SEIArObjectLabelIdc[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 300 +SEIArObjLeft[c]: 300 +SEIArObjWidth[c]: 80 +SEIArObjHeight[c]: 100 +SEIArObjDetConf[c]: 90 diff --git a/cfg/sei_vui/annotated_regions/anno_reg_2.txt b/cfg/sei_vui/annotated_regions/anno_reg_2.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd334b850b1e93987b6f15ecb7eaaa4dc3527879 --- /dev/null +++ b/cfg/sei_vui/annotated_regions/anno_reg_2.txt @@ -0,0 +1,43 @@ +SEIArCancelFlag: 0 +SEIArNotOptForViewingFlag: 0 +SEIArTrueMotionFlag: 0 +SEIArOccludedObjsFlag: 0 +SEIArPartialObjsFlagPresentFlag: 0 +SEIArObjLabelPresentFlag: 1 +SEIArObjConfInfoPresentFlag: 1 +SEIArObjDetConfLength: 7 +SEIArObjLabelLangPresentFlag: 1 +SEIArLabelLanguage: ENGLISH +SEIArNumLabelUpdates: 1 +SEIArLabelIdc[c]: 2 +SEIArLabelCancelFlag[c]: 0 +SEIArLabel[c]: dog +SEIArNumObjUpdates: 3 +SEIArObjIdx[c]: 1 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 150 +SEIArObjLeft[c]: 150 +SEIArObjWidth[c]: 50 +SEIArObjHeight[c]: 50 +SEIArObjDetConf[c]: 90 +SEIArObjIdx[c]: 2 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 220 +SEIArObjLeft[c]: 220 +SEIArObjWidth[c]: 80 +SEIArObjHeight[c]: 100 +SEIArObjDetConf[c]: 85 +SEIArObjIdx[c]: 4 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 1 +SEIArObjectLabelIdc[c]: 2 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 400 +SEIArObjLeft[c]: 400 +SEIArObjWidth[c]: 30 +SEIArObjHeight[c]: 60 +SEIArObjDetConf[c]: 25 diff --git a/cfg/sei_vui/annotated_regions/anno_reg_3.txt b/cfg/sei_vui/annotated_regions/anno_reg_3.txt new file mode 100644 index 0000000000000000000000000000000000000000..49236846207aeb2c8c8dc9af53cf1fede5e5fffc --- /dev/null +++ b/cfg/sei_vui/annotated_regions/anno_reg_3.txt @@ -0,0 +1,25 @@ +SEIArCancelFlag: 0 +SEIArNotOptForViewingFlag: 0 +SEIArTrueMotionFlag: 0 +SEIArOccludedObjsFlag: 0 +SEIArPartialObjsFlagPresentFlag: 0 +SEIArObjLabelPresentFlag: 1 +SEIArObjConfInfoPresentFlag: 1 +SEIArObjDetConfLength: 7 +SEIArObjLabelLangPresentFlag: 1 +SEIArLabelLanguage: ENGLISH +SEIArNumLabelUpdates: 1 +SEIArLabelIdc[c]: 2 +SEIArLabelCancelFlag[c]: 1 +SEIArNumObjUpdates: 2 +SEIArObjIdx[c]: 0 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 30 +SEIArObjLeft[c]: 30 +SEIArObjWidth[c]: 50 +SEIArObjHeight[c]: 50 +SEIArObjDetConf[c]: 90 +SEIArObjIdx[c]: 4 +SEIArObjCancelFlag[c]: 1 diff --git a/cfg/sei_vui/annotated_regions/anno_reg_4.txt b/cfg/sei_vui/annotated_regions/anno_reg_4.txt new file mode 100644 index 0000000000000000000000000000000000000000..86406d191f1e592cd2a1ff5d00fd0983a1944fad --- /dev/null +++ b/cfg/sei_vui/annotated_regions/anno_reg_4.txt @@ -0,0 +1,23 @@ +SEIArCancelFlag: 0 +SEIArNotOptForViewingFlag: 0 +SEIArTrueMotionFlag: 0 +SEIArOccludedObjsFlag: 0 +SEIArPartialObjsFlagPresentFlag: 0 +SEIArObjLabelPresentFlag: 1 +SEIArObjConfInfoPresentFlag: 1 +SEIArObjDetConfLength: 7 +SEIArObjLabelLangPresentFlag: 1 +SEIArLabelLanguage: ENGLISH +SEIArNumLabelUpdates: 0 +SEIArNumObjUpdates: 2 +SEIArObjIdx[c]: 1 +SEIArObjCancelFlag[c]: 0 +SEIArObjLabelUpdateFlag[c]: 0 +SEIArBoundBoxUpdateFlag[c]: 1 +SEIArObjTop[c]: 180 +SEIArObjLeft[c]: 180 +SEIArObjWidth[c]: 50 +SEIArObjHeight[c]: 50 +SEIArObjDetConf[c]: 90 +SEIArObjIdx[c]: 3 +SEIArObjCancelFlag[c]: 1 diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index e2fa972b0dd4baf0415b43d515d7e872c6a34ae2..30f23d9d158e4f45aa688a094c9e622f1245c2f2 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -123,6 +123,19 @@ uint32_t DecApp::decode() } } +#if JVET_T0053_ANNOTATED_REGIONS_SEI + // clear contents of annotated-Regions-SEI output file + if (!m_annotatedRegionsSEIFileName.empty()) + { + std::ofstream ofile(m_annotatedRegionsSEIFileName.c_str()); + if (!ofile.good() || !ofile.is_open()) + { + fprintf(stderr, "\nUnable to open file '%s' for writing annotated-Regions-SEI\n", m_annotatedRegionsSEIFileName.c_str()); + exit(EXIT_FAILURE); + } + } +#endif + // main decoder loop bool loopFiltered[MAX_VPS_LAYERS] = { false }; @@ -325,6 +338,12 @@ uint32_t DecApp::decode() m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].open( reconFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon ); // write mode } } +#if JVET_T0053_ANNOTATED_REGIONS_SEI + if (!m_annotatedRegionsSEIFileName.empty()) + { + xOutputAnnotatedRegions(pcListPic); + } +#endif // write reconstruction to file if( bNewPicture ) { @@ -333,6 +352,12 @@ uint32_t DecApp::decode() } if (nalu.m_nalUnitType == NAL_UNIT_EOS) { +#if JVET_T0053_ANNOTATED_REGIONS_SEI + if (!m_annotatedRegionsSEIFileName.empty() && bNewPicture) + { + xOutputAnnotatedRegions(pcListPic); + } +#endif setOutputPicturePresentInStream(); xWriteOutput( pcListPic, nalu.m_temporalId ); m_cDecLib.setFirstSliceInPicture (false); @@ -430,6 +455,12 @@ uint32_t DecApp::decode() #endif } } +#if JVET_T0053_ANNOTATED_REGIONS_SEI + if (!m_annotatedRegionsSEIFileName.empty()) + { + xOutputAnnotatedRegions(pcListPic); + } +#endif // May need to check again one more time as in case one the bitstream has only one picture, the first check may miss it setOutputPicturePresentInStream(); CHECK(!outputPicturePresentInBitstream, "It is required that there shall be at least one picture with PictureOutputFlag equal to 1 in the bitstream") @@ -862,6 +893,155 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId ) m_iPOCLastDisplay = -MAX_INT; } +#if JVET_T0053_ANNOTATED_REGIONS_SEI +/** \param pcListPic list of pictures to be written to file + */ +void DecApp::xOutputAnnotatedRegions(PicList* pcListPic) +{ + if(!pcListPic || pcListPic->empty()) + { + return; + } + PicList::iterator iterPic = pcListPic->begin(); + + while (iterPic != pcListPic->end()) + { + Picture* pcPic = *(iterPic); + if (pcPic->neededForOutput) + { + // Check if any annotated region SEI has arrived + SEIMessages annotatedRegionSEIs = getSeisByType(pcPic->SEIs, SEI::ANNOTATED_REGIONS); + for(auto it=annotatedRegionSEIs.begin(); it!=annotatedRegionSEIs.end(); it++) + { + const SEIAnnotatedRegions &seiAnnotatedRegions = *(SEIAnnotatedRegions*)(*it); + + if (seiAnnotatedRegions.m_hdr.m_cancelFlag) + { + m_arObjects.clear(); + m_arLabels.clear(); + } + else + { + if (m_arHeader.m_receivedSettingsOnce) + { + // validate those settings that must stay constant are constant. + assert(m_arHeader.m_occludedObjectFlag == seiAnnotatedRegions.m_hdr.m_occludedObjectFlag); + assert(m_arHeader.m_partialObjectFlagPresentFlag == seiAnnotatedRegions.m_hdr.m_partialObjectFlagPresentFlag); + assert(m_arHeader.m_objectConfidenceInfoPresentFlag == seiAnnotatedRegions.m_hdr.m_objectConfidenceInfoPresentFlag); + assert((!m_arHeader.m_objectConfidenceInfoPresentFlag) || m_arHeader.m_objectConfidenceLength == seiAnnotatedRegions.m_hdr.m_objectConfidenceLength); + } + else + { + m_arHeader.m_receivedSettingsOnce=true; + m_arHeader=seiAnnotatedRegions.m_hdr; // copy the settings. + } + // Process label updates + if (seiAnnotatedRegions.m_hdr.m_objectLabelPresentFlag) + { + for(auto srcIt=seiAnnotatedRegions.m_annotatedLabels.begin(); srcIt!=seiAnnotatedRegions.m_annotatedLabels.end(); srcIt++) + { + const uint32_t labIdx = srcIt->first; + if (srcIt->second.labelValid) + { + m_arLabels[labIdx] = srcIt->second.label; + } + else + { + m_arLabels.erase(labIdx); + } + } + } + + // Process object updates + for(auto srcIt=seiAnnotatedRegions.m_annotatedRegions.begin(); srcIt!=seiAnnotatedRegions.m_annotatedRegions.end(); srcIt++) + { + uint32_t objIdx = srcIt->first; + const SEIAnnotatedRegions::AnnotatedRegionObject &src =srcIt->second; + + if (src.objectCancelFlag) + { + m_arObjects.erase(objIdx); + } + else + { + auto destIt = m_arObjects.find(objIdx); + + if (destIt == m_arObjects.end()) + { + //New object arrived, needs to be appended to the map of tracked objects + m_arObjects[objIdx] = src; + } + else //Existing object, modifications to be done + { + SEIAnnotatedRegions::AnnotatedRegionObject &dst=destIt->second; + + if (seiAnnotatedRegions.m_hdr.m_objectLabelPresentFlag && src.objectLabelValid) + { + dst.objectLabelValid=true; + dst.objLabelIdx = src.objLabelIdx; + } + if (src.boundingBoxValid) + { + dst.boundingBoxTop = src.boundingBoxTop ; + dst.boundingBoxLeft = src.boundingBoxLeft ; + dst.boundingBoxWidth = src.boundingBoxWidth ; + dst.boundingBoxHeight = src.boundingBoxHeight; + if (seiAnnotatedRegions.m_hdr.m_partialObjectFlagPresentFlag) + { + dst.partialObjectFlag = src.partialObjectFlag; + } + if (seiAnnotatedRegions.m_hdr.m_objectConfidenceInfoPresentFlag) + { + dst.objectConfidence = src.objectConfidence; + } + } + } + } + } + } + } + + if (!m_arObjects.empty()) + { + FILE *fp_persist = fopen(m_annotatedRegionsSEIFileName.c_str(), "ab"); + if (fp_persist == NULL) + { + std::cout << "Not able to open file for writing persist SEI messages" << std::endl; + } + else + { + fprintf(fp_persist, "\n"); + fprintf(fp_persist, "Number of objects = %d\n", (int)m_arObjects.size()); + for (auto it = m_arObjects.begin(); it != m_arObjects.end(); ++it) + { + fprintf(fp_persist, "Object Idx = %d\n", it->first); + fprintf(fp_persist, "Object Top = %d\n", it->second.boundingBoxTop); + fprintf(fp_persist, "Object Left = %d\n", it->second.boundingBoxLeft); + fprintf(fp_persist, "Object Width = %d\n", it->second.boundingBoxWidth); + fprintf(fp_persist, "Object Height = %d\n", it->second.boundingBoxHeight); + if (it->second.objectLabelValid) + { + auto labelIt=m_arLabels.find(it->second.objLabelIdx); + fprintf(fp_persist, "Object Label = %s\n", labelIt!=m_arLabels.end() ? (labelIt->second.c_str()) : "<UNKNOWN>"); + } + if (m_arHeader.m_partialObjectFlagPresentFlag) + { + fprintf(fp_persist, "Object Partial = %d\n", it->second.partialObjectFlag?1:0); + } + if (m_arHeader.m_objectConfidenceInfoPresentFlag) + { + fprintf(fp_persist, "Object Conf = %d\n", it->second.objectConfidence); + } + } + fclose(fp_persist); + } + } + } + iterPic++; + } +} +#endif + /** \param nalu Input nalu to check whether its LayerId is within targetDecLayerIdSet */ bool DecApp::xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index 11f88ed5ee82192c166f8b60967612d8d2b46705..a0f110939371f2e8cba4b01a486e202cb0129814 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -70,6 +70,11 @@ private: bool m_newCLVS[MAX_NUM_LAYER_IDS]; ///< used to record a new CLVSS +#if JVET_T0053_ANNOTATED_REGIONS_SEI + SEIAnnotatedRegions::AnnotatedRegionHeader m_arHeader; ///< AR header + std::map<uint32_t, SEIAnnotatedRegions::AnnotatedRegionObject> m_arObjects; ///< AR object pool + std::map<uint32_t, std::string> m_arLabels; ///< AR label pool +#endif private: bool xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const; ///< check whether given Nalu is within targetDecLayerIdSet @@ -94,6 +99,9 @@ private: 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 void writeLineToOutputLog(Picture * pcPic); +#if JVET_T0053_ANNOTATED_REGIONS_SEI + void xOutputAnnotatedRegions(PicList* pcListPic); +#endif }; diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index d96c20493f7fe9759ff8016909921467fff3796b..6bbdacde781197eff1302e2d4748a25c866ed562 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -101,6 +101,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("SEINoDisplay", m_decodedNoDisplaySEIEnabled, true, "Control handling of decoded no display SEI messages") ("TarDecLayerIdSetFile,l", cfg_TargetDecLayerIdSetFile, string(""), "targetDecLayerIdSet file name. The file should include white space separated LayerId values to be decoded. Omitting the option or a value of -1 in the file decodes all layers.") ("SEIColourRemappingInfoFilename", m_colourRemapSEIFileName, string(""), "Colour Remapping YUV output file name. If empty, no remapping is applied (ignore SEI message)\n") +#if JVET_T0053_ANNOTATED_REGIONS_SEI + ("SEIAnnotatedRegionsInfoFilename", m_annotatedRegionsSEIFileName, string(""), "Annotated regions output file name. If empty, no object information will be saved (ignore SEI message)\n") +#endif ("OutputDecodedSEIMessagesFilename", m_outputDecodedSEIMessagesFilename, string(""), "When non empty, output decoded SEI messages to the indicated file. If file is '-', then output to stdout\n") #if JVET_S0257_DUMP_360SEI_MESSAGE ("360DumpFile", m_outputDecoded360SEIMessagesFilename, string(""), "When non empty, output decoded 360 SEI messages to the indicated file.\n") @@ -263,6 +266,9 @@ DecAppCfg::DecAppCfg() , m_decodedPictureHashSEIEnabled(0) , m_decodedNoDisplaySEIEnabled(false) , m_colourRemapSEIFileName() +#if JVET_T0053_ANNOTATED_REGIONS_SEI +, m_annotatedRegionsSEIFileName() +#endif , m_targetDecLayerIdSet() , m_outputDecodedSEIMessagesFilename() #if JVET_S0257_DUMP_360SEI_MESSAGE diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index ba7c0338ef6372fc153146f77902783e3953a852..4abe105c1d0de00badf134da76074c0c757e0150 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -74,6 +74,9 @@ protected: int m_decodedPictureHashSEIEnabled; ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message bool m_decodedNoDisplaySEIEnabled; ///< Enable(true)/disable(false) writing only pictures that get displayed based on the no display SEI message std::string m_colourRemapSEIFileName; ///< output Colour Remapping file name +#if JVET_T0053_ANNOTATED_REGIONS_SEI + std::string m_annotatedRegionsSEIFileName; ///< annotated regions file name +#endif std::vector<int> m_targetDecLayerIdSet; ///< set of LayerIds to be included in the sub-bitstream extraction process. std::string m_outputDecodedSEIMessagesFilename; ///< filename to output decoded SEI messages to. If '-', then use stdout. If empty, do not output details. #if JVET_S0257_DUMP_360SEI_MESSAGE diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 2bac42232efde91e89bc6d15e964308cc5cd0187..e5b7cbc41f7dc5b4b5996d71416130c45882eeb8 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -879,6 +879,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setOmniViewportSEITiltCentre ( m_omniViewportSEITiltCentre ); m_cEncLib.setOmniViewportSEIHorRange ( m_omniViewportSEIHorRange ); m_cEncLib.setOmniViewportSEIVerRange ( m_omniViewportSEIVerRange ); +#if JVET_T0053_ANNOTATED_REGIONS_SEI + m_cEncLib.setAnnotatedRegionSEIFileRoot (m_arSEIFileRoot); +#endif m_cEncLib.setRwpSEIEnabled (m_rwpSEIEnabled); m_cEncLib.setRwpSEIRwpCancelFlag (m_rwpSEIRwpCancelFlag); m_cEncLib.setRwpSEIRwpPersistenceFlag (m_rwpSEIRwpPersistenceFlag); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 3703064f07572fd48226a82db344dd505ca34b6a..4f752cdd838425f612de2176b4dd4fd51b1f6dc1 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1300,6 +1300,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SEISubpicLevelInfoRefLevels", cfg_sliRefLevels, cfg_sliRefLevels, "List of reference levels for Subpicture Level Information SEI messages") ("SEISubpicLevelInfoExplicitFraction", m_cfgSubpictureLevelInfoSEI.m_explicitFraction, false, "Enable sending of explicit fractions in Subpicture Level Information SEI messages") ("SEISubpicLevelInfoNumSubpics", m_cfgSubpictureLevelInfoSEI.m_numSubpictures, 1, "Number of subpictures for Subpicture Level Information SEI messages") +#if JVET_T0053_ANNOTATED_REGIONS_SEI + ("SEIAnnotatedRegionsFileRoot,-ar", m_arSEIFileRoot, string(""), "Annotated region SEI parameters root file name (wo num ext); only the file name base is to be added. Underscore and POC would be automatically addded to . E.g. \"-ar ar\" will search for files ar_0.txt, ar_1.txt, ...") +#endif ("SEISubpicLevelInfoMaxSublayers", m_cfgSubpictureLevelInfoSEI.m_sliMaxSublayers, 1, "Number of sublayers for Subpicture Level Information SEI messages") ("SEISubpicLevelInfoSublayerInfoPresentFlag", m_cfgSubpictureLevelInfoSEI.m_sliSublayerInfoPresentFlag, false, "Enable sending of level information for all sublayers in Subpicture Level Information SEI messages") ("SEISubpicLevelInfoRefLevelFractions", cfg_sliFractions, cfg_sliFractions, "List of subpicture level fractions for Subpicture Level Information SEI messages") diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 7d61374c993326f80c80e7061486bab4536c8f64..bca02f63f178441d112900ba58cd60574a4287d0 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -558,6 +558,9 @@ protected: std::vector<int> m_omniViewportSEITiltCentre; std::vector<uint32_t> m_omniViewportSEIHorRange; std::vector<uint32_t> m_omniViewportSEIVerRange; +#if JVET_T0053_ANNOTATED_REGIONS_SEI + std::string m_arSEIFileRoot; // Annotated region SEI - initialized from external file +#endif bool m_rwpSEIEnabled; bool m_rwpSEIRwpCancelFlag; bool m_rwpSEIRwpPersistenceFlag; diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp index cb27029c4210aa708fae276ac813898c094c2557..bcd52eec269fc1de4cf4a6a37a3d5dbac563b46e 100644 --- a/source/Lib/CommonLib/SEI.cpp +++ b/source/Lib/CommonLib/SEI.cpp @@ -180,6 +180,9 @@ const char *SEI::getSEIMessageString(SEI::PayloadType payloadType) case SEI::GENERALIZED_CUBEMAP_PROJECTION: return "Generalized cubemap projection"; case SEI::SAMPLE_ASPECT_RATIO_INFO: return "Sample aspect ratio information"; case SEI::SUBPICTURE_LEVEL_INFO: return "Subpicture level information"; +#if JVET_T0053_ANNOTATED_REGIONS_SEI + case SEI::ANNOTATED_REGIONS: return "Annotated Region"; +#endif default: return "Unknown"; } } diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h index a77a94e2b9e5d9b8208483eeeb8a0a588be347fe..2788ef2b4845124be8c428bb0c6e55c60e969cfd 100644 --- a/source/Lib/CommonLib/SEI.h +++ b/source/Lib/CommonLib/SEI.h @@ -79,6 +79,9 @@ public: ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147, AMBIENT_VIEWING_ENVIRONMENT = 148, CONTENT_COLOUR_VOLUME = 149, +#if JVET_T0053_ANNOTATED_REGIONS_SEI + ANNOTATED_REGIONS = 202, +#endif }; SEI() {} @@ -664,9 +667,71 @@ public: std::vector<std::vector<std::vector<int>>> m_refLevelFraction; }; +#if JVET_T0053_ANNOTATED_REGIONS_SEI +class SEIAnnotatedRegions : public SEI +{ +public: + PayloadType payloadType() const { return ANNOTATED_REGIONS; } + SEIAnnotatedRegions() {} + virtual ~SEIAnnotatedRegions() {} + void copyFrom(const SEIAnnotatedRegions &seiAnnotatedRegions) + { + (*this) = seiAnnotatedRegions; + } + + struct AnnotatedRegionObject + { + AnnotatedRegionObject() : + objectCancelFlag(false), + objectLabelValid(false), + boundingBoxValid(false) + { } + bool objectCancelFlag; + + bool objectLabelValid; + uint32_t objLabelIdx; // only valid if bObjectLabelValid + + bool boundingBoxValid; + uint32_t boundingBoxTop; // only valid if bBoundingBoxValid + uint32_t boundingBoxLeft; + uint32_t boundingBoxWidth; + uint32_t boundingBoxHeight; + + bool partialObjectFlag; // only valid if bPartialObjectFlagValid + uint32_t objectConfidence; + }; + struct AnnotatedRegionLabel + { + AnnotatedRegionLabel() : labelValid(false) { } + bool labelValid; + std::string label; // only valid if bLabelValid + }; + struct AnnotatedRegionHeader + { + AnnotatedRegionHeader() : m_cancelFlag(true), m_receivedSettingsOnce(false) { } + bool m_cancelFlag; + bool m_receivedSettingsOnce; // used for decoder conformance checking. Other confidence flags must be unchanged once this flag is set. + + bool m_notOptimizedForViewingFlag; + bool m_trueMotionFlag; + bool m_occludedObjectFlag; + bool m_partialObjectFlagPresentFlag; + bool m_objectLabelPresentFlag; + bool m_objectConfidenceInfoPresentFlag; + uint32_t m_objectConfidenceLength; // Only valid if m_objectConfidenceInfoPresentFlag + bool m_objectLabelLanguagePresentFlag; // Only valid if m_objectLabelPresentFlag + std::string m_annotatedRegionsObjectLabelLang; + }; + typedef uint32_t AnnotatedRegionObjectIndex; + typedef uint32_t AnnotatedRegionLabelIndex; + AnnotatedRegionHeader m_hdr; + std::vector<std::pair<AnnotatedRegionObjectIndex, AnnotatedRegionObject> > m_annotatedRegions; + std::vector<std::pair<AnnotatedRegionLabelIndex, AnnotatedRegionLabel> > m_annotatedLabels; +}; +#endif //! \} diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index d4269b0dd6cb2b97c81cdf3967af1bd2ac42d90c..d70e0b18a2b1836a887c7fc49da1d040846ccc2d 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -92,6 +92,10 @@ typedef std::pair<int, int> TrCost; #define EXTENSION_360_VIDEO 0 ///< extension for 360/spherical video coding support; this macro should be controlled by makefile, as it would be used to control whether the library is built and linked #endif +#ifndef JVET_T0053_ANNOTATED_REGIONS_SEI +#define JVET_T0053_ANNOTATED_REGIONS_SEI 1 //Enable/disable the annotated regions SEI +#endif + #ifndef EXTENSION_HDRTOOLS #define EXTENSION_HDRTOOLS 0 //< extension for HDRTools/Metrics support; this macro should be controlled by makefile, as it would be used to control whether the library is built and linked #endif diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp index d0b54d41cf8d46b5dcaad5814a14c584bc7a39bb..facb29b8e6c134a7f1db790bcb79ef2e66e9a2ad 100644 --- a/source/Lib/DecoderLib/SEIread.cpp +++ b/source/Lib/DecoderLib/SEIread.cpp @@ -236,6 +236,12 @@ void SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType sei = new SEIFramePacking; xParseSEIFramePacking((SEIFramePacking&) *sei, payloadSize, pDecodedMessageOutputStream); break; +#if JVET_T0053_ANNOTATED_REGIONS_SEI + case SEI::ANNOTATED_REGIONS: + sei = new SEIAnnotatedRegions; + xParseSEIAnnotatedRegions((SEIAnnotatedRegions&)*sei, payloadSize, pDecodedMessageOutputStream); + break; +#endif case SEI::PARAMETER_SETS_INCLUSION_INDICATION: sei = new SEIParameterSetsInclusionIndication; xParseSEIParameterSetsInclusionIndication((SEIParameterSetsInclusionIndication&)*sei, payloadSize, pDecodedMessageOutputStream); @@ -977,6 +983,128 @@ void SEIReader::xParseSEIPictureTiming(SEIPictureTiming& sei, uint32_t payloadSi sei.m_ptDisplayElementalPeriodsMinus1 = symbol; } +#if JVET_T0053_ANNOTATED_REGIONS_SEI +void SEIReader::xParseSEIAnnotatedRegions(SEIAnnotatedRegions& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) +{ + output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize); + uint32_t val; + + sei_read_flag(pDecodedMessageOutputStream, val, "ar_cancel_flag"); sei.m_hdr.m_cancelFlag = val; + if (!sei.m_hdr.m_cancelFlag) + { + sei_read_flag(pDecodedMessageOutputStream, val, "ar_not_optimized_for_viewing_flag"); sei.m_hdr.m_notOptimizedForViewingFlag = val; + sei_read_flag(pDecodedMessageOutputStream, val, "ar_true_motion_flag"); sei.m_hdr.m_trueMotionFlag = val; + sei_read_flag(pDecodedMessageOutputStream, val, "ar_occluded_object_flag"); sei.m_hdr.m_occludedObjectFlag = val; // must be constant + sei_read_flag(pDecodedMessageOutputStream, val, "ar_partial_object_flag_present_flag"); sei.m_hdr.m_partialObjectFlagPresentFlag = val; // must be constant + sei_read_flag(pDecodedMessageOutputStream, val, "ar_object_label_present_flag"); sei.m_hdr.m_objectLabelPresentFlag = val; + sei_read_flag(pDecodedMessageOutputStream, val, "ar_object_confidence_info_present_flag"); sei.m_hdr.m_objectConfidenceInfoPresentFlag = val; // must be constant + if (sei.m_hdr.m_objectConfidenceInfoPresentFlag) + { + sei_read_code(pDecodedMessageOutputStream, 4, val, "ar_object_confidence_length_minus_1"); sei.m_hdr.m_objectConfidenceLength = (val + 1); // must be constant + } + if (sei.m_hdr.m_objectLabelPresentFlag) + { + sei_read_flag(pDecodedMessageOutputStream, val, "ar_object_label_language_present_flag"); sei.m_hdr.m_objectLabelLanguagePresentFlag = val; + if (sei.m_hdr.m_objectLabelLanguagePresentFlag) + { + // byte alignment + while (m_pcBitstream->getNumBitsRead() % 8 != 0) + { + uint32_t code; + sei_read_flag(pDecodedMessageOutputStream, code, "ar_bit_equal_to_zero"); + } + sei.m_hdr.m_annotatedRegionsObjectLabelLang.clear(); + do + { + sei_read_code(pDecodedMessageOutputStream, 8, val, "ar_label_language"); + if (val) + { + assert(sei.m_hdr.m_annotatedRegionsObjectLabelLang.size()<256); + sei.m_hdr.m_annotatedRegionsObjectLabelLang.push_back((char)val); + } + } while (val != '\0'); + } + } + + uint32_t numLabelUpdates; + sei_read_uvlc(pDecodedMessageOutputStream, numLabelUpdates, "ar_num_label_updates"); + assert(numLabelUpdates<256); + + sei.m_annotatedLabels.clear(); + sei.m_annotatedLabels.resize(numLabelUpdates); + for (auto it=sei.m_annotatedLabels.begin(); it!=sei.m_annotatedLabels.end(); it++) + { + SEIAnnotatedRegions::AnnotatedRegionLabel &ar = it->second; + sei_read_uvlc(pDecodedMessageOutputStream, val, "ar_label_idx[]"); it->first = val; + assert(val<256); + sei_read_flag(pDecodedMessageOutputStream, val, "ar_label_cancel_flag"); ar.labelValid = !val; + if (ar.labelValid) + { + ar.label.clear(); + // byte alignment + while (m_pcBitstream->getNumBitsRead() % 8 != 0) + { + uint32_t code; + sei_read_flag(pDecodedMessageOutputStream, code, "ar_bit_equal_to_zero"); + } + do + { + sei_read_code(pDecodedMessageOutputStream, 8, val, "ar_label[]"); + if (val) + { + assert(ar.label.size()<256); + ar.label.push_back((char)val); + } + } while (val != '\0'); + } + } + + uint32_t numObjUpdates; + sei_read_uvlc(pDecodedMessageOutputStream, numObjUpdates, "ar_num_object_updates"); + assert(numObjUpdates<256); + sei.m_annotatedRegions.clear(); + sei.m_annotatedRegions.resize(numObjUpdates); + for (auto it=sei.m_annotatedRegions.begin(); it!=sei.m_annotatedRegions.end(); it++) + { + sei_read_uvlc(pDecodedMessageOutputStream, val, "ar_object_idx"); it->first=val; + assert(val<256); + SEIAnnotatedRegions::AnnotatedRegionObject &ar = it->second; + sei_read_flag(pDecodedMessageOutputStream, val, "ar_object_cancel_flag"); ar.objectCancelFlag = val; + ar.objectLabelValid=false; + ar.boundingBoxValid=false; + + if (!ar.objectCancelFlag) + { + if (sei.m_hdr.m_objectLabelPresentFlag) + { + sei_read_flag(pDecodedMessageOutputStream, val, "ar_object_label_update_flag"); ar.objectLabelValid = val; + if (ar.objectLabelValid) + { + sei_read_uvlc(pDecodedMessageOutputStream, val, "ar_object_label_idx"); ar.objLabelIdx = val; + assert(val<256); + } + } + sei_read_flag(pDecodedMessageOutputStream, val, "ar_bounding_box_update_flag"); ar.boundingBoxValid = val; + if (ar.boundingBoxValid) + { + sei_read_code(pDecodedMessageOutputStream, 16, val, "ar_bounding_box_top"); ar.boundingBoxTop = val; + sei_read_code(pDecodedMessageOutputStream, 16, val, "ar_bounding_box_left"); ar.boundingBoxLeft = val; + sei_read_code(pDecodedMessageOutputStream, 16, val, "ar_bounding_box_width"); ar.boundingBoxWidth = val; + sei_read_code(pDecodedMessageOutputStream, 16, val, "ar_bounding_box_height"); ar.boundingBoxHeight = val; + if (sei.m_hdr.m_partialObjectFlagPresentFlag) + { + sei_read_flag(pDecodedMessageOutputStream, val, "ar_partial_object_flag"); ar.partialObjectFlag = val; + } + if (sei.m_hdr.m_objectConfidenceInfoPresentFlag) + { + sei_read_code(pDecodedMessageOutputStream, sei.m_hdr.m_objectConfidenceLength, val, "ar_object_confidence"); ar.objectConfidence = val; + } + } + } + } + } +} +#endif void SEIReader::xParseSEIFrameFieldinfo(SEIFrameFieldInfo& sei, const SEIPictureTiming& pt, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) { output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize); diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h index 8627a85debf8a22968c17dfed12f3672d8f9ff64..c34268f91e7def3ff2e050b0ccf2fff8806a5d08 100644 --- a/source/Lib/DecoderLib/SEIread.h +++ b/source/Lib/DecoderLib/SEIread.h @@ -71,6 +71,9 @@ protected: void xParseSEIFramePacking (SEIFramePacking& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); void xParseSEIParameterSetsInclusionIndication(SEIParameterSetsInclusionIndication& sei, uint32_t payloadSize, std::ostream* pDecodedMessageOutputStream); void xParseSEIMasteringDisplayColourVolume (SEIMasteringDisplayColourVolume& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); +#if JVET_T0053_ANNOTATED_REGIONS_SEI + void xParseSEIAnnotatedRegions (SEIAnnotatedRegions& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); +#endif #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI void xParseSEIAlternativeTransferCharacteristics(SEIAlternativeTransferCharacteristics& sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream); #endif diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 900909411fcd66bf13f48ae8ea36cea8b94f7daf..f79b154b21f2f76e852c9ffed9de01389baa106d 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -637,6 +637,9 @@ protected: double m_ccvSEIMinLuminanceValue; double m_ccvSEIMaxLuminanceValue; double m_ccvSEIAvgLuminanceValue; +#if JVET_T0053_ANNOTATED_REGIONS_SEI + std::string m_arSEIFileRoot; // Annotated region SEI - initialized from external file +#endif //====== Weighted Prediction ======== bool m_useWeightedPred; //< Use of Weighting Prediction (P_SLICE) bool m_useWeightedBiPred; //< Use of Bi-directional Weighting Prediction (B_SLICE) @@ -770,7 +773,9 @@ public: virtual ~EncCfg() {} - +#if JVET_T0053_ANNOTATED_REGIONS_SEI + std::map<uint32_t, SEIAnnotatedRegions::AnnotatedRegionObject> m_arObjects; +#endif void setProfile(Profile::Name profile) { m_profile = profile; } void setLevel(Level::Tier tier, Level::Name level) { m_levelTier = tier; m_level = level; } bool getFrameOnlyConstraintFlag() const { return m_frameOnlyConstraintFlag; } @@ -1552,6 +1557,10 @@ public: uint32_t getOmniViewportSEIHorRange(int idx) { return m_omniViewportSEIHorRange[idx]; } void setOmniViewportSEIVerRange(const std::vector<uint32_t>& vi) { m_omniViewportSEIVerRange = vi; } uint32_t getOmniViewportSEIVerRange(int idx) { return m_omniViewportSEIVerRange[idx]; } +#if JVET_T0053_ANNOTATED_REGIONS_SEI + void setAnnotatedRegionSEIFileRoot(const std::string &s) { m_arSEIFileRoot = s; m_arObjects.clear();} + const std::string &getAnnotatedRegionSEIFileRoot() const { return m_arSEIFileRoot; } +#endif void setRwpSEIEnabled(bool b) { m_rwpSEIEnabled = b; } bool getRwpSEIEnabled() { return m_rwpSEIEnabled; } void setRwpSEIRwpCancelFlag(bool b) { m_rwpSEIRwpCancelFlag = b; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 7947135f3d01c765954493927a6c92ddbc960757..f688001b934c3511d01e4b89375166130f457114 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -801,6 +801,23 @@ void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessage seiMessages.push_back(dependentRAPIndicationSEI); } +#if JVET_T0053_ANNOTATED_REGIONS_SEI + // insert one Annotated Region SEI for the picture (if the file exists) + if (!m_pcCfg->getAnnotatedRegionSEIFileRoot().empty()) + { + SEIAnnotatedRegions *seiAnnotatedRegions = new SEIAnnotatedRegions(); + const bool success = m_seiEncoder.initSEIAnnotatedRegions(seiAnnotatedRegions, slice->getPOC()); + + if (success) + { + seiMessages.push_back(seiAnnotatedRegions); + } + else + { + delete seiAnnotatedRegions; + } + } +#endif } void EncGOP::xCreateScalableNestingSEI(SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, const std::vector<int> &targetOLSs, const std::vector<int> &targetLayers, const std::vector<uint16_t>& subpicIDs) diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index a9ecad7caa99259ec7a2f10e8db0eba6f6fef31c..6b7c5476aa3ac095f3f5b9c4630435a6455f0293 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -559,6 +559,154 @@ static void readTokenValueAndValidate(T &returnedValue, /// value ret } } +#if JVET_T0053_ANNOTATED_REGIONS_SEI +// Bool version does not have maximum and minimum values. +static void readTokenValueAndValidate(bool &returnedValue, /// value returned + bool &failed, /// used and updated + std::istream &is, /// stream to read token from + const char *pToken) /// token string +{ + readTokenValue(returnedValue, failed, is, pToken); +} + +void SEIEncoder::readAnnotatedRegionSEI(std::istream &fic, SEIAnnotatedRegions *seiAnnoRegion, bool &failed) +{ + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_cancelFlag, failed, fic, "SEIArCancelFlag"); + if (!seiAnnoRegion->m_hdr.m_cancelFlag) + { + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_notOptimizedForViewingFlag, failed, fic, "SEIArNotOptForViewingFlag"); + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_trueMotionFlag, failed, fic, "SEIArTrueMotionFlag"); + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_occludedObjectFlag, failed, fic, "SEIArOccludedObjsFlag"); + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_partialObjectFlagPresentFlag, failed, fic, "SEIArPartialObjsFlagPresentFlag"); + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_objectLabelPresentFlag, failed, fic, "SEIArObjLabelPresentFlag"); + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_objectConfidenceInfoPresentFlag, failed, fic, "SEIArObjConfInfoPresentFlag"); + if (seiAnnoRegion->m_hdr.m_objectConfidenceInfoPresentFlag) + { + readTokenValueAndValidate<uint32_t>(seiAnnoRegion->m_hdr.m_objectConfidenceLength, failed, fic, "SEIArObjDetConfLength", uint32_t(0), uint32_t(255)); + } + if (seiAnnoRegion->m_hdr.m_objectLabelPresentFlag) + { + readTokenValueAndValidate(seiAnnoRegion->m_hdr.m_objectLabelLanguagePresentFlag, failed, fic, "SEIArObjLabelLangPresentFlag"); + if (seiAnnoRegion->m_hdr.m_objectLabelLanguagePresentFlag) + { + readTokenValue(seiAnnoRegion->m_hdr.m_annotatedRegionsObjectLabelLang, failed, fic, "SEIArLabelLanguage"); + } + uint32_t numLabelUpdates=0; + readTokenValueAndValidate<uint32_t>(numLabelUpdates, failed, fic, "SEIArNumLabelUpdates", uint32_t(0), uint32_t(255)); + seiAnnoRegion->m_annotatedLabels.resize(numLabelUpdates); + for (auto it=seiAnnoRegion->m_annotatedLabels.begin(); it!=seiAnnoRegion->m_annotatedLabels.end(); it++) + { + SEIAnnotatedRegions::AnnotatedRegionLabel &ar=it->second; + readTokenValueAndValidate(it->first, failed, fic, "SEIArLabelIdc[c]", uint32_t(0), uint32_t(255)); + bool cancelFlag; + readTokenValueAndValidate(cancelFlag, failed, fic, "SEIArLabelCancelFlag[c]"); + ar.labelValid=!cancelFlag; + if (ar.labelValid) + { + readTokenValue(ar.label, failed, fic, "SEIArLabel[c]"); + } + } + } + + uint32_t numObjectUpdates=0; + readTokenValueAndValidate<uint32_t>(numObjectUpdates, failed, fic, "SEIArNumObjUpdates", uint32_t(0), uint32_t(255)); + seiAnnoRegion->m_annotatedRegions.resize(numObjectUpdates); + for (auto it=seiAnnoRegion->m_annotatedRegions.begin(); it!=seiAnnoRegion->m_annotatedRegions.end(); it++) + { + SEIAnnotatedRegions::AnnotatedRegionObject &ar = it->second; + readTokenValueAndValidate(it->first, failed, fic, "SEIArObjIdx[c]", uint32_t(0), uint32_t(255)); + readTokenValueAndValidate(ar.objectCancelFlag, failed, fic, "SEIArObjCancelFlag[c]"); + ar.objectLabelValid=false; + ar.boundingBoxValid=false; + if (!ar.objectCancelFlag) + { + if (seiAnnoRegion->m_hdr.m_objectLabelPresentFlag) + { + readTokenValueAndValidate(ar.objectLabelValid, failed, fic, "SEIArObjLabelUpdateFlag[c]"); + if (ar.objectLabelValid) + { + readTokenValueAndValidate<uint32_t>(ar.objLabelIdx, failed, fic, "SEIArObjectLabelIdc[c]", uint32_t(0), uint32_t(255)); + } + readTokenValueAndValidate(ar.boundingBoxValid, failed, fic, "SEIArBoundBoxUpdateFlag[c]"); + if (ar.boundingBoxValid) + { + readTokenValueAndValidate<uint32_t>(ar.boundingBoxTop, failed, fic, "SEIArObjTop[c]", uint32_t(0), uint32_t(0x7fffffff)); + readTokenValueAndValidate<uint32_t>(ar.boundingBoxLeft, failed, fic, "SEIArObjLeft[c]", uint32_t(0), uint32_t(0x7fffffff)); + readTokenValueAndValidate<uint32_t>(ar.boundingBoxWidth, failed, fic, "SEIArObjWidth[c]", uint32_t(0), uint32_t(0x7fffffff)); + readTokenValueAndValidate<uint32_t>(ar.boundingBoxHeight, failed, fic, "SEIArObjHeight[c]", uint32_t(0), uint32_t(0x7fffffff)); + if (seiAnnoRegion->m_hdr.m_partialObjectFlagPresentFlag) + { + readTokenValueAndValidate(ar.partialObjectFlag, failed, fic, "SEIArObjPartUpdateFlag[c]"); + } + if (seiAnnoRegion->m_hdr.m_objectConfidenceInfoPresentFlag) + { + readTokenValueAndValidate<uint32_t>(ar.objectConfidence, failed, fic, "SEIArObjDetConf[c]", uint32_t(0), uint32_t(1<<seiAnnoRegion->m_hdr.m_objectConfidenceLength)-1); + } + } + //Compare with existing attributes to decide whether it's a static object + //First check whether it's an existing object (or) new object + auto destIt = m_pcCfg->m_arObjects.find(it->first); + //New object + if (destIt == m_pcCfg->m_arObjects.end()) + { + //New object arrived, needs to be appended to the map of tracked objects + m_pcCfg->m_arObjects[it->first] = ar; + } + //Existing object + else + { + // Size remains the same + if(m_pcCfg->m_arObjects[it->first].boundingBoxWidth == ar.boundingBoxWidth && + m_pcCfg->m_arObjects[it->first].boundingBoxHeight == ar.boundingBoxHeight) + { + if(m_pcCfg->m_arObjects[it->first].boundingBoxTop == ar.boundingBoxTop && + m_pcCfg->m_arObjects[it->first].boundingBoxLeft == ar.boundingBoxLeft) + { + ar.boundingBoxValid = 0; + } + } + } + } + } + } + } +} + +bool SEIEncoder::initSEIAnnotatedRegions(SEIAnnotatedRegions* SEIAnnoReg, int currPOC) +{ + assert(m_isInitialized); + assert(SEIAnnoReg != NULL); + + // reading external Annotated Regions Information SEI message parameters from file + if (!m_pcCfg->getAnnotatedRegionSEIFileRoot().empty()) + { + bool failed = false; + // building the annotated regions file name with poc num in prefix "_poc.txt" + std::string AnnoRegionSEIFileWithPoc(m_pcCfg->getAnnotatedRegionSEIFileRoot()); + { + std::stringstream suffix; + suffix << "_" << currPOC << ".txt"; + AnnoRegionSEIFileWithPoc += suffix.str(); + } + std::ifstream fic(AnnoRegionSEIFileWithPoc.c_str()); + if (!fic.good() || !fic.is_open()) + { + std::cerr << "No Annotated Regions SEI parameters file " << AnnoRegionSEIFileWithPoc << " for POC " << currPOC << std::endl; + return false; + } + //Read annotated region SEI parameters from the cfg file + readAnnotatedRegionSEI(fic, SEIAnnoReg, failed); + if (failed) + { + std::cerr << "Error while reading Annotated Regions SEI parameters file '" << AnnoRegionSEIFileWithPoc << "'" << std::endl; + exit(EXIT_FAILURE); + } + } + return true; +} +#endif + + #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI void SEIEncoder::initSEIAlternativeTransferCharacteristics(SEIAlternativeTransferCharacteristics *seiAltTransCharacteristics) { diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h index 0fc26901da38b2de45d0a9cc25a7dd667c791223..14c221fbdb24e2c364e914af1d0b3ef4f16ef12d 100644 --- a/source/Lib/EncoderLib/SEIEncoder.h +++ b/source/Lib/EncoderLib/SEIEncoder.h @@ -86,6 +86,10 @@ public: void initSEIContentLightLevel(SEIContentLightLevelInfo *sei); void initSEIAmbientViewingEnvironment(SEIAmbientViewingEnvironment *sei); void initSEIContentColourVolume(SEIContentColourVolume *sei); +#if JVET_T0053_ANNOTATED_REGIONS_SEI + bool initSEIAnnotatedRegions(SEIAnnotatedRegions *sei, int currPOC); + void readAnnotatedRegionSEI(std::istream &fic, SEIAnnotatedRegions *seiAnnoRegion, bool &failed); +#endif private: EncCfg* m_pcCfg; EncLib* m_pcEncLib; diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp index 042d25a4ab3ed20c08ce12daba2624addf6ffb7e..43131e21c920c5a795c09a8424dabbbfc7408cd9 100644 --- a/source/Lib/EncoderLib/SEIwrite.cpp +++ b/source/Lib/EncoderLib/SEIwrite.cpp @@ -127,6 +127,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &h case SEI::SAMPLE_ASPECT_RATIO_INFO: xWriteSEISampleAspectRatioInfo(*static_cast<const SEISampleAspectRatioInfo*>(&sei)); break; +#if JVET_T0053_ANNOTATED_REGIONS_SEI + case SEI::ANNOTATED_REGIONS: + xWriteSEIAnnotatedRegions(*static_cast<const SEIAnnotatedRegions*>(&sei)); + break; +#endif default: THROW("Trying to write unhandled SEI message"); break; @@ -596,6 +601,98 @@ void SEIWriter::xWriteSEIMasteringDisplayColourVolume(const SEIMasteringDisplayC WRITE_CODE( sei.values.minLuminance, 32, "mdcv_min_display_mastering_luminance" ); } +#if JVET_T0053_ANNOTATED_REGIONS_SEI +void SEIWriter::xWriteSEIAnnotatedRegions(const SEIAnnotatedRegions &sei) +{ + WRITE_FLAG(sei.m_hdr.m_cancelFlag, "ar_cancel_flag"); + if (!sei.m_hdr.m_cancelFlag) + { + WRITE_FLAG(sei.m_hdr.m_notOptimizedForViewingFlag, "ar_not_optimized_for_viewing_flag"); + WRITE_FLAG(sei.m_hdr.m_trueMotionFlag, "ar_true_motion_flag"); + WRITE_FLAG(sei.m_hdr.m_occludedObjectFlag, "ar_occluded_object_flag"); + WRITE_FLAG(sei.m_hdr.m_partialObjectFlagPresentFlag, "ar_partial_object_flag_present_flag"); + WRITE_FLAG(sei.m_hdr.m_objectLabelPresentFlag, "ar_object_label_present_flag"); + WRITE_FLAG(sei.m_hdr.m_objectConfidenceInfoPresentFlag, "ar_object_confidence_info_present_flag"); + if (sei.m_hdr.m_objectConfidenceInfoPresentFlag) + { + assert(sei.m_hdr.m_objectConfidenceLength <= 16 && sei.m_hdr.m_objectConfidenceLength>0); + WRITE_CODE((sei.m_hdr.m_objectConfidenceLength - 1), 4, "ar_object_confidence_length_minus_1"); + } + if (sei.m_hdr.m_objectLabelPresentFlag) + { + WRITE_FLAG(sei.m_hdr.m_objectLabelLanguagePresentFlag, "ar_object_label_language_present_flag"); + if (sei.m_hdr.m_objectLabelLanguagePresentFlag) + { + xWriteByteAlign(); + assert(sei.m_hdr.m_annotatedRegionsObjectLabelLang.size()<256); + for (uint32_t j = 0; j < sei.m_hdr.m_annotatedRegionsObjectLabelLang.size(); j++) + { + char ch = sei.m_hdr.m_annotatedRegionsObjectLabelLang[j]; + WRITE_CODE(ch, 8, "ar_object_label_language"); + } + WRITE_CODE('\0', 8, "ar_label_language"); + } + } + WRITE_UVLC((uint32_t)sei.m_annotatedLabels.size(), "ar_num_label_updates"); + assert(sei.m_annotatedLabels.size()<256); + for(auto it=sei.m_annotatedLabels.begin(); it!=sei.m_annotatedLabels.end(); it++) + { + assert(it->first < 256); + WRITE_UVLC(it->first, "ar_label_idx[]"); + const SEIAnnotatedRegions::AnnotatedRegionLabel &ar=it->second; + WRITE_FLAG(!ar.labelValid, "ar_label_cancel_flag"); + if (ar.labelValid) + { + xWriteByteAlign(); + assert(ar.label.size()<256); + for (uint32_t j = 0; j < ar.label.size(); j++) + { + char ch = ar.label[j]; + WRITE_CODE(ch, 8, "ar_label[]"); + } + WRITE_CODE('\0', 8, "ar_label[]"); + } + } + WRITE_UVLC((uint32_t)sei.m_annotatedRegions.size(), "ar_num_object_updates"); + assert(sei.m_annotatedRegions.size()<256); + for (auto it=sei.m_annotatedRegions.begin(); it!=sei.m_annotatedRegions.end(); it++) + { + const SEIAnnotatedRegions::AnnotatedRegionObject &ar = it->second; + WRITE_UVLC(it->first, "ar_object_idx"); + WRITE_FLAG(ar.objectCancelFlag, "ar_object_cancel_flag"); + if (!ar.objectCancelFlag) + { + if (sei.m_hdr.m_objectLabelPresentFlag) + { + WRITE_FLAG(ar.objectLabelValid, "ar_object_label_update_flag"); + if (ar.objectLabelValid) + { + assert(ar.objLabelIdx<256); + WRITE_UVLC(ar.objLabelIdx, "ar_object_label_idx"); + } + } + WRITE_FLAG(ar.boundingBoxValid, "ar_object_bounding_box_update_flag"); + if (ar.boundingBoxValid) + { + WRITE_CODE(ar.boundingBoxTop, 16, "ar_bounding_box_top"); + WRITE_CODE(ar.boundingBoxLeft, 16, "ar_bounding_box_left"); + WRITE_CODE(ar.boundingBoxWidth, 16, "ar_bounding_box_width"); + WRITE_CODE(ar.boundingBoxHeight,16, "ar_bounding_box_height"); + if (sei.m_hdr.m_partialObjectFlagPresentFlag) + { + WRITE_UVLC(ar.partialObjectFlag, "ar_partial_object_flag"); + } + if (sei.m_hdr.m_objectConfidenceInfoPresentFlag) + { + assert(ar.objectConfidence < (1<<sei.m_hdr.m_objectConfidenceLength)); + WRITE_CODE(ar.objectConfidence, sei.m_hdr.m_objectConfidenceLength, "ar_object_confidence"); + } + } + } + } + } +} +#endif void SEIWriter::xWriteByteAlign() { if( m_pcBitIf->getNumberOfWrittenBits() % 8 != 0) diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h index 912e0ee872704cef589b1ac6b1b93ddd7f65001b..1f67a89dd7f8711c0c1fed0d9d9311bc5b356943 100644 --- a/source/Lib/EncoderLib/SEIwrite.h +++ b/source/Lib/EncoderLib/SEIwrite.h @@ -79,6 +79,9 @@ protected: void xWriteSEIContentLightLevelInfo(const SEIContentLightLevelInfo& sei); void xWriteSEIAmbientViewingEnvironment(const SEIAmbientViewingEnvironment& sei); void xWriteSEIContentColourVolume(const SEIContentColourVolume &sei); +#if JVET_T0053_ANNOTATED_REGIONS_SEI + void xWriteSEIAnnotatedRegions (const SEIAnnotatedRegions& sei); +#endif void xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &hrd, const uint32_t temporalId); void xWriteByteAlign(); protected: