From d4801363157a446794d661a4a9abfc81fadce317 Mon Sep 17 00:00:00 2001 From: Jeeva Raj A <jeeva.raj@ittiam.com> Date: Fri, 13 May 2022 19:55:06 +0000 Subject: [PATCH] JVET-Z0120: SII SEI support and illustration of use case "Backwards-compatible HFR video" --- cfg/sei_vui/shutter_interval_info.cfg | 7 + ...hutter_interval_info_mul_120fps_SA_180.cfg | 6 + ...hutter_interval_info_mul_120fps_SA_360.cfg | 6 + ...shutter_interval_info_mul_120fps_SA_90.cfg | 6 + ...shutter_interval_info_mul_60fps_SA_180.cfg | 6 + ...shutter_interval_info_mul_60fps_SA_360.cfg | 6 + .../shutter_interval_info_mul_60fps_SA_90.cfg | 6 + ...hutter_interval_info_mul_120fps_SA_180.cfg | 6 + ...hutter_interval_info_mul_120fps_SA_360.cfg | 6 + ...shutter_interval_info_mul_120fps_SA_90.cfg | 6 + ...shutter_interval_info_mul_60fps_SA_180.cfg | 6 + ...shutter_interval_info_mul_60fps_SA_360.cfg | 6 + .../shutter_interval_info_mul_60fps_SA_90.cfg | 6 + cfg/sei_vui/shutter_interval_info_fix.cfg | 5 + .../shutter_interval_info_mul_gop16.cfg | 6 + .../shutter_interval_info_mul_gop32.cfg | 6 + doc/software-manual.tex | 15 + source/App/DecoderApp/DecApp.cpp | 240 +++++++++++++++- source/App/DecoderApp/DecApp.h | 22 ++ source/App/DecoderApp/DecAppCfg.cpp | 3 + source/App/DecoderApp/DecAppCfg.h | 3 + source/App/EncoderApp/EncApp.cpp | 30 ++ source/App/EncoderApp/EncApp.h | 3 + source/App/EncoderApp/EncAppCfg.cpp | 106 ++++++++ source/App/EncoderApp/EncAppCfg.h | 15 + source/Lib/CommonLib/CodingStructure.h | 3 + source/Lib/CommonLib/CommonDef.h | 7 + source/Lib/CommonLib/Picture.cpp | 257 ++++++++++++++++++ source/Lib/CommonLib/Picture.h | 17 ++ source/Lib/CommonLib/SEI.cpp | 3 + source/Lib/CommonLib/SEI.h | 19 ++ source/Lib/CommonLib/Slice.cpp | 4 + source/Lib/CommonLib/TypeDef.h | 7 + source/Lib/DecoderLib/DecLib.cpp | 21 +- source/Lib/DecoderLib/DecLib.h | 8 + source/Lib/DecoderLib/SEIread.cpp | 31 +++ source/Lib/DecoderLib/SEIread.h | 3 + source/Lib/EncoderLib/EncCfg.h | 32 +++ source/Lib/EncoderLib/EncGOP.cpp | 8 + source/Lib/EncoderLib/EncLib.cpp | 37 ++- source/Lib/EncoderLib/SEIEncoder.cpp | 22 ++ source/Lib/EncoderLib/SEIEncoder.h | 3 + source/Lib/EncoderLib/SEIwrite.cpp | 25 ++ source/Lib/EncoderLib/SEIwrite.h | 3 + 44 files changed, 1036 insertions(+), 7 deletions(-) create mode 100644 cfg/sei_vui/shutter_interval_info.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_180.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_360.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_90.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_180.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_360.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_90.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_180.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_360.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_90.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_180.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_360.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_90.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_fix.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_mul_gop16.cfg create mode 100644 cfg/sei_vui/shutter_interval_info_mul_gop32.cfg diff --git a/cfg/sei_vui/shutter_interval_info.cfg b/cfg/sei_vui/shutter_interval_info.cfg new file mode 100644 index 000000000..c12f050b6 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info.cfg @@ -0,0 +1,7 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 27000000 +SEISiiInputNumUnitsInShutterInterval : 1080000 # should have at least one entry. if only one entry, the value is assigned to sii_num_units_in_shutter_interval, + # if multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ] + + \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_180.cfg b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_180.cfg new file mode 100644 index 000000000..93ea8ec9b --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_180.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 200000 200000 200000 200000 100000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 120, SFR_fps = 60 and shutterAngle = 180 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_360.cfg b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_360.cfg new file mode 100644 index 000000000..ececa5613 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_360.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 400000 400000 400000 400000 200000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 120, SFR_fps = 60 and shutterAngle = 360 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_90.cfg b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_90.cfg new file mode 100644 index 000000000..1e52eaeed --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_120fps_SA_90.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 100000 100000 100000 100000 50000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 120, SFR_fps = 60 and shutterAngle = 90 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_180.cfg b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_180.cfg new file mode 100644 index 000000000..07d7f0f1c --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_180.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 400000 400000 400000 400000 200000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=60fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 60, SFR_fps = 30 and shutterAngle = 180 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_360.cfg b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_360.cfg new file mode 100644 index 000000000..931f2551c --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_360.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 800000 800000 800000 800000 400000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=60fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 60, SFR_fps = 30 and shutterAngle = 360 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_90.cfg b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_90.cfg new file mode 100644 index 000000000..7e3d93462 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP16/shutter_interval_info_mul_60fps_SA_90.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 200000 200000 200000 200000 100000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=60fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 60, SFR_fps = 30 and shutterAngle = 90 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_180.cfg b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_180.cfg new file mode 100644 index 000000000..598da8d1b --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_180.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 200000 200000 200000 200000 200000 100000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 120, SFR_fps = 60 and shutterAngle = 180 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_360.cfg b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_360.cfg new file mode 100644 index 000000000..ce1386ab4 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_360.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 400000 400000 400000 400000 400000 200000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 120, SFR_fps = 60 and shutterAngle = 360 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_90.cfg b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_90.cfg new file mode 100644 index 000000000..b7c0ea51c --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_120fps_SA_90.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 100000 100000 100000 100000 100000 50000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 120, SFR_fps = 60 and shutterAngle = 90 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_180.cfg b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_180.cfg new file mode 100644 index 000000000..5a5fe7025 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_180.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 400000 400000 400000 400000 400000 200000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=60fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 60, SFR_fps = 30 and shutterAngle = 180 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_360.cfg b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_360.cfg new file mode 100644 index 000000000..7e090f079 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_360.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 800000 800000 800000 800000 800000 400000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=60fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 60, SFR_fps = 30 and shutterAngle = 360 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_90.cfg b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_90.cfg new file mode 100644 index 000000000..ce4b38ca1 --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_GOP32/shutter_interval_info_mul_60fps_SA_90.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 200000 200000 200000 200000 200000 100000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=60fps, encoder derives the actually values based on picture frame rate. + # HFR_fps = 60, SFR_fps = 30 and shutterAngle = 90 \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_fix.cfg b/cfg/sei_vui/shutter_interval_info_fix.cfg new file mode 100644 index 000000000..03178caec --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_fix.cfg @@ -0,0 +1,5 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 200000 # fixed shutter interval: only one entry, the value is assigned to sii_num_units_in_shutter_interval. + # here is one example with frame rate=120fps, encoder derives the actually value based on frame rate. diff --git a/cfg/sei_vui/shutter_interval_info_mul_gop16.cfg b/cfg/sei_vui/shutter_interval_info_mul_gop16.cfg new file mode 100644 index 000000000..b5c4e008b --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_mul_gop16.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 400000 400000 400000 400000 200000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + \ No newline at end of file diff --git a/cfg/sei_vui/shutter_interval_info_mul_gop32.cfg b/cfg/sei_vui/shutter_interval_info_mul_gop32.cfg new file mode 100644 index 000000000..e1fc71a8b --- /dev/null +++ b/cfg/sei_vui/shutter_interval_info_mul_gop32.cfg @@ -0,0 +1,6 @@ +#======== Shutter Interval Info SEI message ===================== +SEIShutterIntervalEnabled : 1 +SEISiiTimeScale : 24000000 +SEISiiInputNumUnitsInShutterInterval : 400000 400000 400000 400000 400000 200000 # multiple shutter intervals: multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ]. + # here is one example with frame rate=120fps, encoder derives the actually values based on picture frame rate. + \ No newline at end of file diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 2ab8c09e2..1b9d77d28 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -3730,6 +3730,7 @@ The table below lists the SEI messages defined for Version 1 and Range-Extension 204 & Sample Aspect Ratio Information & Table \ref{tab:sei-sari} \\ 205 & Scalability Dimension Information & Table \ref{tab:sei-sdi} \\ 207 & Constrained RASL encoding & Table \ref{tab:sei-constrained-rasl-encoding} \\ + 209 & Shutter Interval Information & Table \ref{tab:sei-sii} \\ \end{SEIListTable} %% %% SEI messages @@ -5307,6 +5308,20 @@ When true (non-zero), the SEI enables several restrictions for encoding RASL fra \\ \end{OptionTableNoShorthand} +\begin{OptionTableNoShorthand}{Shutter Interval Information SEI message encoder parameters}{tab:sei-sii} +\Option{SEIShutterIntervalEnabled} & +\Default{false} & +Enables (true) or disables (false) the insertion of Shutter Interval Information SEI message. +\\ +\Option{SEISiiTimeScale} & +\Default{27000000} & +Specifies sii_time_scale. +\\ +\Option{SEISiiInputNumUnitsInShutterInterval} & +\Default{false} & +Specifies sii_num_units_in_shutter_interval for single entry.If multiple entries, the values are set to sub_layer_num_units_in_shutter_interval[ ] corresponding to each temporal sub layer starting from temporal layer id 0. +\\ +\end{OptionTableNoShorthand} %\Option{SEITimeCode} & diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index b77983633..49b31e84f 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -138,6 +138,12 @@ uint32_t DecApp::decode() bool bPicSkipped = false; +#if JVET_Z0120_SII_SEI_PROCESSING + bool openedPostFile = false; + setShutterFilterFlag(!m_shutterIntervalPostFileName.empty()); // not apply shutter interval SEI processing if filename is not specified. + m_cDecLib.setShutterFilterFlag(getShutterFilterFlag()); +#endif + bool isEosPresentInPu = false; bool isEosPresentInLastPu = false; @@ -515,6 +521,177 @@ uint32_t DecApp::decode() { xOutputAnnotatedRegions(pcListPic); } + +#if JVET_Z0120_SII_SEI_PROCESSING + PicList::iterator iterPic = pcListPic->begin(); + Picture* pcPic = *(iterPic); + SEIMessages shutterIntervalInfo = getSeisByType(pcPic->SEIs, SEI::SHUTTER_INTERVAL_INFO); + + if (!m_shutterIntervalPostFileName.empty()) + { + int32_t hasValidSII = 1; + SEIShutterIntervalInfo *curSIIInfo = NULL; + if ((pcPic->getPictureType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || + pcPic->getPictureType() == NAL_UNIT_CODED_SLICE_IDR_N_LP) && m_newCLVS[nalu.m_nuhLayerId]) + { + IdrSiiInfo_s curSII; + curSII.m_picPoc = pcPic->getPOC(); + + curSII.m_isValidSii = 0; + curSII.m_siiInfo.m_siiEnabled = 0; + curSII.m_siiInfo.m_siiNumUnitsInShutterInterval = 0; + curSII.m_siiInfo.m_siiTimeScale = 0; + curSII.m_siiInfo.m_siiMaxSubLayersMinus1 = 0; + curSII.m_siiInfo.m_siiFixedSIwithinCLVS = 0; + + if (shutterIntervalInfo.size() > 0) + { + SEIShutterIntervalInfo *seiShutterIntervalInfo = (SEIShutterIntervalInfo*) *(shutterIntervalInfo.begin()); + curSII.m_isValidSii = 1; + + curSII.m_siiInfo.m_siiEnabled = seiShutterIntervalInfo->m_siiEnabled; + curSII.m_siiInfo.m_siiNumUnitsInShutterInterval = seiShutterIntervalInfo->m_siiNumUnitsInShutterInterval; + curSII.m_siiInfo.m_siiTimeScale = seiShutterIntervalInfo->m_siiTimeScale; + curSII.m_siiInfo.m_siiMaxSubLayersMinus1 = seiShutterIntervalInfo->m_siiMaxSubLayersMinus1; + curSII.m_siiInfo.m_siiFixedSIwithinCLVS = seiShutterIntervalInfo->m_siiFixedSIwithinCLVS; + curSII.m_siiInfo.m_siiSubLayerNumUnitsInSI.clear(); + for (int i = 0; i < seiShutterIntervalInfo->m_siiSubLayerNumUnitsInSI.size(); i++) + curSII.m_siiInfo.m_siiSubLayerNumUnitsInSI.push_back(seiShutterIntervalInfo->m_siiSubLayerNumUnitsInSI[i]); + + uint32_t tmpInfo = (uint32_t)(m_activeSiiInfo.size() + 1); + m_activeSiiInfo.insert(pair<uint32_t, IdrSiiInfo_s>(tmpInfo, curSII)); + curSIIInfo = seiShutterIntervalInfo; + } + else + { + curSII.m_isValidSii = 0; + hasValidSII = 0; + uint32_t tmpInfo = (uint32_t)(m_activeSiiInfo.size() + 1); + m_activeSiiInfo.insert(pair<uint32_t, IdrSiiInfo_s>(tmpInfo, curSII)); + } + } + else + { + if (m_activeSiiInfo.size() == 1) + { + curSIIInfo = &(m_activeSiiInfo.begin()->second.m_siiInfo); + } + else + { + uint8_t isLast = 1; + for (int i = 1; i < m_activeSiiInfo.size() + 1; i++) + { + if (pcPic->getPOC() <= m_activeSiiInfo.at(i).m_picPoc) + { + if (m_activeSiiInfo[i - 1].m_isValidSii) + { + curSIIInfo = &(m_activeSiiInfo.at(i - 1).m_siiInfo); + } + else + { + hasValidSII = 0; + } + isLast = 0; + break; + } + } + if (isLast) + { + uint32_t tmpInfo = (uint32_t)(m_activeSiiInfo.size()); + curSIIInfo = &(m_activeSiiInfo.at(tmpInfo).m_siiInfo); + } + } + } + + if (hasValidSII) + { + if (!curSIIInfo->m_siiFixedSIwithinCLVS) + { + uint32_t siiMaxSubLayersMinus1 = curSIIInfo->m_siiMaxSubLayersMinus1; + uint32_t numUnitsLFR = curSIIInfo->m_siiSubLayerNumUnitsInSI[0]; + uint32_t numUnitsHFR = curSIIInfo->m_siiSubLayerNumUnitsInSI[siiMaxSubLayersMinus1]; + + int blending_ratio = (numUnitsLFR / numUnitsHFR); + bool checkEqualValuesOfSFR = 1; + bool checkSubLayerSI = 0; + int i; + + //supports only the case of SFR = HFR / 2 + if (curSIIInfo->m_siiSubLayerNumUnitsInSI[siiMaxSubLayersMinus1] < + curSIIInfo->m_siiSubLayerNumUnitsInSI[siiMaxSubLayersMinus1 - 1]) + { + checkSubLayerSI = 1; + } + else + { + fprintf(stderr, "Warning: Shutter Interval SEI message processing is disabled due to SFR != (HFR / 2) \n"); + } + //check shutter interval for all sublayer remains same for SFR pictures + for (i = 1; i < siiMaxSubLayersMinus1; i++) + { + if (curSIIInfo->m_siiSubLayerNumUnitsInSI[0] != curSIIInfo->m_siiSubLayerNumUnitsInSI[i]) + { + checkEqualValuesOfSFR = 0; + } + } + if (!checkEqualValuesOfSFR) + { + fprintf(stderr, "Warning: Shutter Interval SEI message processing is disabled when shutter interval is not same for SFR sublayers \n"); + } + if (checkSubLayerSI && checkEqualValuesOfSFR) + { + setShutterFilterFlag(numUnitsLFR == blending_ratio * numUnitsHFR); + setBlendingRatio(blending_ratio); + } + else + { + setShutterFilterFlag(false); + } + + const SPS* activeSPS = pcListPic->front()->cs->sps; + + if (numUnitsLFR == blending_ratio * numUnitsHFR && activeSPS->getMaxTLayers() == 1 && activeSPS->getMaxDecPicBuffering(0) == 1) + { + fprintf(stderr, "Warning: Shutter Interval SEI message processing is disabled for single TempLayer and single frame in DPB\n"); + setShutterFilterFlag(false); + } + } + else + { + fprintf(stderr, "Warning: Shutter Interval SEI message processing is disabled for fixed shutter interval case\n"); + setShutterFilterFlag(false); + } + } + else + { + fprintf(stderr, "Warning: Shutter Interval information should be specified in SII-SEI message\n"); + setShutterFilterFlag(false); + } + } + + + if ((!m_shutterIntervalPostFileName.empty()) && (!openedPostFile) && getShutterFilterFlag()) + { + const BitDepths &bitDepths = pcListPic->front()->cs->sps->getBitDepths(); + for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { + if (m_outputBitDepth[channelType] == 0) + { + m_outputBitDepth[channelType] = bitDepths.recon[channelType]; + } + } + + std::ofstream ofile(m_shutterIntervalPostFileName.c_str()); + if (!ofile.good() || !ofile.is_open()) + { + fprintf(stderr, "\nUnable to open file '%s' for writing shutter-interval-SEI video\n", m_shutterIntervalPostFileName.c_str()); + exit(EXIT_FAILURE); + } + m_cTVideoIOYuvSIIPostFile.open(m_shutterIntervalPostFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon); // write mode + openedPostFile = true; + } +#endif + // write reconstruction to file if( bNewPicture ) { @@ -586,6 +763,13 @@ uint32_t DecApp::decode() xFlushOutput( pcListPic ); +#if JVET_Z0120_SII_SEI_PROCESSING + if (!m_shutterIntervalPostFileName.empty() && getShutterFilterFlag()) + { + m_cTVideoIOYuvSIIPostFile.close(); + } +#endif + // get the number of checksum errors uint32_t nRet = m_cDecLib.getNumberOfChecksumErrorsDetected(); @@ -869,6 +1053,32 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId ) NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); } } + + +#if JVET_Z0120_SII_SEI_PROCESSING + if (!m_shutterIntervalPostFileName.empty() && getShutterFilterFlag()) + { + int blendingRatio = getBlendingRatio(); + pcPic->xOutputPostFilteredPic(pcPic, pcListPic, blendingRatio); + + const Window &conf = pcPic->getConformanceWindow(); + const SPS* sps = pcPic->cs->sps; + ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); + + m_cTVideoIOYuvSIIPostFile.write( + pcPic->getPostRecBuf().get(COMPONENT_Y).width, + pcPic->getPostRecBuf().get(COMPONENT_Y).height, + pcPic->getPostRecBuf(), + m_outputColourSpaceConvert, + m_packedYUVMode, + conf.getWindowLeftOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowRightOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowTopOffset() * SPS::getWinUnitY(chromaFormatIDC), + conf.getWindowBottomOffset() * SPS::getWinUnitY(chromaFormatIDC), + NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } +#endif + // Perform CTI on decoded frame and write to output CTI file if (!m_SEICTIFileName.empty()) { @@ -1043,6 +1253,30 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId ) NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); } } + +#if JVET_Z0120_SII_SEI_PROCESSING + if (!m_shutterIntervalPostFileName.empty() && getShutterFilterFlag()) + { + int blendingRatio = getBlendingRatio(); + pcPic->xOutputPostFilteredPic(pcPic, pcListPic, blendingRatio); + + const Window &conf = pcPic->getConformanceWindow(); + const SPS* sps = pcPic->cs->sps; + ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); + + m_cTVideoIOYuvSIIPostFile.write( + pcPic->getPostRecBuf().get(COMPONENT_Y).width, + pcPic->getPostRecBuf().get(COMPONENT_Y).height, + pcPic->getPostRecBuf(), + m_outputColourSpaceConvert, m_packedYUVMode, + conf.getWindowLeftOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowRightOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowTopOffset() * SPS::getWinUnitY(chromaFormatIDC), + conf.getWindowBottomOffset() * SPS::getWinUnitY(chromaFormatIDC), + NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } +#endif + // Perform CTI on decoded frame and write to output CTI file if (!m_SEICTIFileName.empty()) { @@ -1075,7 +1309,11 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId ) } pcPic->neededForOutput = false; } - if (pcPic != nullptr) +#if JVET_Z0120_SII_SEI_PROCESSING + if (pcPic != nullptr && (m_shutterIntervalPostFileName.empty() || !getShutterFilterFlag())) +#else + if(pcPic != nullptr) +#endif { pcPic->destroy(); delete pcPic; diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index d774ae761..6d83fcb47 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -64,6 +64,22 @@ private: std::unordered_map<int, VideoIOYuv> m_videoIOYuvSEIFGSFile; ///< reconstruction YUV with FGS class std::unordered_map<int, VideoIOYuv> m_cVideoIOYuvSEICTIFile; ///< reconstruction YUV with CTI class +#if JVET_Z0120_SII_SEI_PROCESSING + bool m_ShutterFilterEnable; ///< enable Post-processing with Shutter Interval SEI + VideoIOYuv m_cTVideoIOYuvSIIPostFile; ///< post-filtered YUV class + int m_SII_BlendingRatio; + + typedef struct + { + SEIShutterIntervalInfo m_siiInfo; + uint32_t m_picPoc; + uint8_t m_isValidSii; + }IdrSiiInfo_s; + + std::map<uint32_t, IdrSiiInfo_s> m_activeSiiInfo; + +#endif + // for output control int m_iPOCLastDisplay; ///< last POC in display order std::ofstream m_seiMessageFileStream; ///< Used for outputing SEI messages. @@ -85,6 +101,12 @@ public: virtual ~DecApp () {} uint32_t decode (); ///< main decoding function +#if JVET_Z0120_SII_SEI_PROCESSING + bool getShutterFilterFlag() const { return m_ShutterFilterEnable; } + void setShutterFilterFlag(bool value) { m_ShutterFilterEnable = value; } + int getBlendingRatio() const { return m_SII_BlendingRatio; } + void setBlendingRatio(int value) { m_SII_BlendingRatio = value; } +#endif private: void xCreateDecLib (); ///< create internal classes diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index 908d585b8..8988da1f3 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -90,6 +90,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("OutputColourSpaceConvert", outputColourSpaceConvert, string(""), "Colour space conversion to apply to input 444 video. Permitted values are (empty string=UNCHANGED) " + getListOfColourSpaceConverts(false)) ("MaxTemporalLayer,t", m_iMaxTemporalLayer, 500, "Maximum Temporal Layer to be decoded. -1 to decode all layers") ("TargetOutputLayerSet,p", m_targetOlsIdx, 500, "Target output layer set index") +#if JVET_Z0120_SII_SEI_PROCESSING + ("SEIShutterIntervalPostFilename,-sii", m_shutterIntervalPostFileName, string(""), "Post Filtering with Shutter Interval SEI. If empty, no filtering is applied (ignore SEI message)\n") +#endif ("SEIDecodedPictureHash,-dph",m_decodedPictureHashSEIEnabled, 1, "Control handling of decoded picture hash SEI messages\n" "\t1: check hash in SEI messages if available in the bitstream\n" "\t0: ignore SEI message") diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index 810561223..f9af97fb6 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -81,6 +81,9 @@ protected: std::string m_outputDecoded360SEIMessagesFilename; ///< filename to output decoded 360 SEI messages to. #endif +#if JVET_Z0120_SII_SEI_PROCESSING + std::string m_shutterIntervalPostFileName; ///< output Post Filtering file name +#endif bool m_bClipOutputVideoToRec709Range; ///< If true, clip the output video to the Rec 709 range on saving. bool m_packedYUVMode; ///< If true, output 10-bit and 12-bit YUV data as 5-byte and 3-byte (respectively) packed YUV data diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index d74bf535c..74ea378a6 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -1112,6 +1112,10 @@ void EncApp::xInitLibCfg() m_cEncLib.setDriSEIDisparityRefViewId (m_driSEIDisparityRefViewId); m_cEncLib.setDriSEINonlinearNumMinus1 (m_driSEINonlinearNumMinus1); m_cEncLib.setDriSEINonlinearModel (m_driSEINonlinearModel); +#if JVET_Z0120_SII_SEI_PROCESSING + m_cEncLib.setShutterFilterFlag(m_ShutterFilterEnable); + m_cEncLib.setBlendingRatioSII(m_SII_BlendingRatio); +#endif m_cEncLib.setEntropyCodingSyncEnabledFlag ( m_entropyCodingSyncEnabledFlag ); m_cEncLib.setEntryPointPresentFlag ( m_entryPointPresentFlag ); m_cEncLib.setTMVPModeId ( m_TMVPModeId ); @@ -1153,6 +1157,12 @@ void EncApp::xInitLibCfg() m_cEncLib.setTSRCdisableLL ( m_TSRCdisableLL ); m_cEncLib.setUseRecalculateQPAccordingToLambda ( m_recalculateQPAccordingToLambda ); m_cEncLib.setDCIEnabled ( m_DCIEnabled ); +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + m_cEncLib.setSiiSEIEnabled(m_siiSEIEnabled); + m_cEncLib.setSiiSEINumUnitsInShutterInterval(m_siiSEINumUnitsInShutterInterval); + m_cEncLib.setSiiSEITimeScale(m_siiSEITimeScale); + m_cEncLib.setSiiSEISubLayerNumUnitsInSI(m_siiSEISubLayerNumUnitsInSI); +#endif m_cEncLib.setVuiParametersPresentFlag ( m_vuiParametersPresentFlag ); m_cEncLib.setSamePicTimingInAllOLS (m_samePicTimingInAllOLS); m_cEncLib.setAspectRatioInfoPresentFlag ( m_aspectRatioInfoPresentFlag); @@ -1286,6 +1296,12 @@ void EncApp::xCreateLib( std::list<PelUnitBuf*>& recBufList, const int layerId ) m_cVideoIOYuvReconFile.open( reconFileName, true, m_outputBitDepth, m_outputBitDepth, m_internalBitDepth ); // write mode } +#if JVET_Z0120_SII_SEI_PROCESSING + if (m_ShutterFilterEnable && !m_shutterIntervalPreFileName.empty()) + { + m_cTVideoIOYuvSIIPreFile.open(m_shutterIntervalPreFileName, true, m_outputBitDepth, m_outputBitDepth, m_internalBitDepth); // write mode + } +#endif // create the encoder m_cEncLib.create( layerId ); @@ -1301,6 +1317,12 @@ void EncApp::xDestroyLib() // Video I/O m_cVideoIOYuvInputFile.close(); m_cVideoIOYuvReconFile.close(); +#if JVET_Z0120_SII_SEI_PROCESSING + if (m_ShutterFilterEnable && !m_shutterIntervalPreFileName.empty()) + { + m_cTVideoIOYuvSIIPreFile.close(); + } +#endif // Neo Decoder m_cEncLib.destroy(); @@ -1505,6 +1527,14 @@ bool EncApp::encodePrep( bool& eos ) keepDoing = m_cEncLib.encodePrep( eos, m_flush ? 0 : m_orgPic, m_flush ? 0 : m_trueOrgPic, m_flush ? 0 : m_filteredOrgPic, m_flush ? 0 : m_filteredOrgPicForFG, snrCSC, m_recBufList, m_numEncoded ); } +#if JVET_Z0120_SII_SEI_PROCESSING + if (m_ShutterFilterEnable && !m_shutterIntervalPreFileName.empty()) + { + m_cTVideoIOYuvSIIPreFile.write(m_orgPic->get(COMPONENT_Y).width, m_orgPic->get(COMPONENT_Y).height, *m_orgPic, m_inputColourSpaceConvert, m_packedYUVMode, + m_confWinLeft, m_confWinRight, m_confWinTop, m_confWinBottom, NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } +#endif + return keepDoing; } diff --git a/source/App/EncoderApp/EncApp.h b/source/App/EncoderApp/EncApp.h index d809bfb51..9775f8de0 100644 --- a/source/App/EncoderApp/EncApp.h +++ b/source/App/EncoderApp/EncApp.h @@ -71,6 +71,9 @@ private: EncLib m_cEncLib; ///< encoder class VideoIOYuv m_cVideoIOYuvInputFile; ///< input YUV file VideoIOYuv m_cVideoIOYuvReconFile; ///< output reconstruction file +#if JVET_Z0120_SII_SEI_PROCESSING + VideoIOYuv m_cTVideoIOYuvSIIPreFile; ///< output pre-filtered file +#endif int m_iFrameRcvd; ///< number of received frames uint32_t m_essentialBytes; uint32_t m_totalBytes; diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index b70573c47..6a1ddc3fb 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -738,6 +738,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput<uint32_t> cfg_FgcSEICompModelValueComp0 (0, 65535, 0, 256 * 6); SMultiValueInput<uint32_t> cfg_FgcSEICompModelValueComp1 (0, 65535, 0, 256 * 6); SMultiValueInput<uint32_t> cfg_FgcSEICompModelValueComp2 (0, 65535, 0, 256 * 6); +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + SMultiValueInput<unsigned> cfg_siiSEIInputNumUnitsInSI(0, std::numeric_limits<uint32_t>::max(), 0, 7); +#endif #if ENABLE_TRACING string sTracingRule; @@ -765,6 +768,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("InputPathPrefix,-ipp", inputPathPrefix, string(""), "pathname to prepend to input filename") ("BitstreamFile,b", m_bitstreamFileName, string(""), "Bitstream output file name") ("ReconFile,o", m_reconFileName, string(""), "Reconstructed YUV output file name") +#if JVET_Z0120_SII_SEI_PROCESSING + ("SEIShutterIntervalPreFilename,-sii", m_shutterIntervalPreFileName, string(""), "File name of Pre-Filtering video. If empty, not output video\n") +#endif ("SourceWidth,-wdt", m_sourceWidth, 0, "Source picture width") ("SourceHeight,-hgt", m_sourceHeight, 0, "Source picture height") ("InputBitDepth", m_inputBitDepth[CHANNEL_TYPE_LUMA], 8, "Bit-depth of input file") @@ -1418,6 +1424,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SEISARISarWidth", m_sariSarWidth, 0, "Specifies the Sample Aspect Ratio Width of Sample Aspect Ratio Information SEI messages, if extended SAR is chosen.") ("SEISARISarHeight", m_sariSarHeight, 0, "Specifies the Sample Aspect Ratio Height of Sample Aspect Ratio Information SEI messages, if extended SAR is chosen.") ("MCTSEncConstraint", m_MCTSEncConstraint, false, "For MCTS, constrain motion vectors at tile boundaries") +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + ("SEIShutterIntervalEnabled", m_siiSEIEnabled, false, "Controls if shutter interval information SEI message is enabled") + ("SEISiiTimeScale", m_siiSEITimeScale, 27000000u, "Specifies sii_time_scale") + ("SEISiiInputNumUnitsInShutterInterval", cfg_siiSEIInputNumUnitsInSI, cfg_siiSEIInputNumUnitsInSI, "Specifies sub_layer_num_units_in_shutter_interval") +#endif + #if ENABLE_TRACING ("TraceChannelsList", bTracingChannelsList, false, "List all available tracing channels") ("TraceRule", sTracingRule, string( "" ), "Tracing rule (ex: \"D_CABAC:poc==8\" or \"D_REC_CB_LUMA:poc==8\")") @@ -2988,6 +3000,86 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif // ENABLE_QPA +#if JVET_Z0120_SII_SEI_PROCESSING + m_ShutterFilterEnable = false; +#endif +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + if (m_siiSEIEnabled) + { + assert(m_siiSEITimeScale >= 0 && m_siiSEITimeScale <= MAX_UINT); + uint32_t sii_max_sub_layers = (uint32_t)cfg_siiSEIInputNumUnitsInSI.values.size(); + assert(sii_max_sub_layers > 0); + if (sii_max_sub_layers > 1) + { + m_siiSEISubLayerNumUnitsInSI.resize(sii_max_sub_layers); + for (int32_t i = 0; i < sii_max_sub_layers; i++) + { + m_siiSEISubLayerNumUnitsInSI[i] = cfg_siiSEIInputNumUnitsInSI.values[i]; + assert(m_siiSEISubLayerNumUnitsInSI[i] >= 0 && m_siiSEISubLayerNumUnitsInSI[i] <= MAX_UINT); + } + } + else + { + m_siiSEINumUnitsInShutterInterval = cfg_siiSEIInputNumUnitsInSI.values[0]; + assert(m_siiSEINumUnitsInShutterInterval >= 0 && m_siiSEINumUnitsInShutterInterval <= MAX_UINT); + } +#if JVET_Z0120_SII_SEI_PROCESSING + uint32_t siiMaxSubLayersMinus1 = sii_max_sub_layers - 1; + int blending_ratio = (m_siiSEISubLayerNumUnitsInSI[0] / m_siiSEISubLayerNumUnitsInSI[siiMaxSubLayersMinus1]); + + if (sii_max_sub_layers > 1 && m_siiSEISubLayerNumUnitsInSI[0] == + (blending_ratio * m_siiSEISubLayerNumUnitsInSI[siiMaxSubLayersMinus1])) + { + m_ShutterFilterEnable = true; + double fpsHFR = (double)m_iFrameRate; + int32_t i; + bool checkEqualValuesOfSFR = 1; + bool checkSubLayerSI = 0; + + double shutterAngleFactor = (fpsHFR * ((double)(m_siiSEISubLayerNumUnitsInSI[siiMaxSubLayersMinus1])))/((double)m_siiSEITimeScale); + + // If shutterAngleFactor = 1 indicates that shutterAngle = 360 + // If shutterAngleFactor = 0.5 indicates that shutterAngle = 180 + // If shutterAngleFactor = 0.25 indicates that shutterAngle = 90 + + if (shutterAngleFactor < 0.5) + { + for (int i = 0; i < siiMaxSubLayersMinus1; i++) + { + m_siiSEISubLayerNumUnitsInSI[i] = m_siiSEISubLayerNumUnitsInSI[siiMaxSubLayersMinus1]; + } + m_ShutterFilterEnable = false; + printf("Warning: For the shutterAngle = %d, the blending can't be applied\n", (int)(shutterAngleFactor * 360)); + } + // supports only the case of SFR = HFR / 2 + if (m_siiSEISubLayerNumUnitsInSI[siiMaxSubLayersMinus1] < m_siiSEISubLayerNumUnitsInSI[siiMaxSubLayersMinus1 - 1]) + { + checkSubLayerSI = 1; + } + // check shutter interval for all sublayer remains same for LFR pictures + for (i = 1; i < siiMaxSubLayersMinus1; i++) + { + if (m_siiSEISubLayerNumUnitsInSI[0] != m_siiSEISubLayerNumUnitsInSI[i]) + { + checkEqualValuesOfSFR = 0; + } + } + if (checkSubLayerSI && checkEqualValuesOfSFR) + { + setBlendingRatioSII(blending_ratio); + } + else + { + m_ShutterFilterEnable = false; + } + } + else + { + printf("Warning: SII-processing is applied for multiple shutter intervals and number of LFR units should be 2 times of number of HFR units\n"); + } +#endif + } +#endif if( m_costMode == COST_LOSSLESS_CODING ) @@ -4368,6 +4460,14 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_gcmpSEIGuardBandSamplesMinus1 < 0 || m_gcmpSEIGuardBandSamplesMinus1 > 15, "SEIGcmpGuardBandSamplesMinus1 must be in the range of 0 to 15"); } } + +#if JVET_Z0120_SII_SEI_PROCESSING + if (m_siiSEIEnabled && m_ShutterFilterEnable) + { + xConfirmPara(m_maxTempLayer == 1 || m_maxDecPicBuffering[0] == 1,"Shutter Interval SEI message processing is disabled for single TempLayer and single frame in DPB\n"); + } +#endif + xConfirmPara(m_log2ParallelMergeLevel < 2, "Log2ParallelMergeLevel should be larger than or equal to 2"); xConfirmPara(m_log2ParallelMergeLevel > m_uiCTUSize, "Log2ParallelMergeLevel should be less than or equal to CTU size"); #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI @@ -4437,6 +4537,12 @@ void EncAppCfg::xPrintParameter() msg( DETAILS, "Input File : %s\n", m_inputFileName.c_str() ); msg( DETAILS, "Bitstream File : %s\n", m_bitstreamFileName.c_str() ); msg( DETAILS, "Reconstruction File : %s\n", m_reconFileName.c_str() ); +#if JVET_Z0120_SII_SEI_PROCESSING + if (m_ShutterFilterEnable && !m_shutterIntervalPreFileName.empty()) + { + msg(DETAILS,"SII Pre-processed File : %s\n", m_shutterIntervalPreFileName.c_str()); + } +#endif msg( DETAILS, "Real Format : %dx%d %gHz\n", m_sourceWidth - m_confWinLeft - m_confWinRight, m_sourceHeight - m_confWinTop - m_confWinBottom, (double)m_iFrameRate / m_temporalSubsampleRatio ); msg( DETAILS, "Internal Format : %dx%d %gHz\n", m_sourceWidth, m_sourceHeight, (double)m_iFrameRate / m_temporalSubsampleRatio ); msg( DETAILS, "Sequence PSNR output : %s\n", ( m_printMSEBasedSequencePSNR ? "Linear average, MSE-based" : "Linear average only" ) ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index cb3b59c70..eaeafc49c 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -40,6 +40,8 @@ #include "CommonLib/CommonDef.h" #include "EncoderLib/EncCfgParam.h" +#include "CommonLib/Picture.h" +#include "EncCfg.h" #include <map> template <class T1, class T2> @@ -805,6 +807,19 @@ protected: int m_ImvMode; ///< imv mode int m_Imv4PelFast; ///< imv 4-Pel fast mode +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + bool m_siiSEIEnabled; + uint32_t m_siiSEINumUnitsInShutterInterval; + uint32_t m_siiSEITimeScale; + std::vector<uint32_t> m_siiSEISubLayerNumUnitsInSI; +#endif +#if JVET_Z0120_SII_SEI_PROCESSING + bool m_ShutterFilterEnable; ///< enable Pre-Filtering with Shutter Interval SEI + std::string m_shutterIntervalPreFileName; ///< output Pre-Filtering video + int m_SII_BlendingRatio; + void setBlendingRatioSII(int value) { m_SII_BlendingRatio = value; } +#endif + std::string m_summaryOutFilename; ///< filename to use for producing summary output file. std::string m_summaryPicFilenameBase; ///< Base filename to use for producing summary picture output files. The actual filenames used will have I.txt, P.txt and B.txt appended. uint32_t m_summaryVerboseness; ///< Specifies the level of the verboseness of the text output. diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 9bb80f24c..988f2e21f 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -63,6 +63,9 @@ enum PictureType PIC_ORIGINAL_INPUT, PIC_TRUE_ORIGINAL_INPUT, PIC_FILTERED_ORIGINAL_INPUT, +#if JVET_Z0120_SII_SEI_PROCESSING + PIC_YUV_POST_REC, +#endif NUM_PIC_TYPES }; extern XUCache g_globalUnitCache; diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index dd3224164..4401be276 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -492,6 +492,13 @@ static const int BLK_16 = 16; static const int BLK_32 = 32; static const int BIT_DEPTH_8 = 8; // ==================================================================================================================== +// SEI and related constants +// ==================================================================================================================== +#if JVET_Z0120_SII_SEI_PROCESSING +static const double SII_PF_W2 = 0.6; // weight for current picture +static const double SII_PF_W1 = 0.4; // weight for previous picture , it must be equal to 1.0 - SII_PF_W2 +#endif +// ==================================================================================================================== // Macro functions // ==================================================================================================================== diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index e33b36fa2..bb9bdad93 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -80,7 +80,11 @@ Picture::Picture() m_grainBuf = nullptr; } +#if JVET_Z0120_SII_SEI_PROCESSING +void Picture::create( const ChromaFormat &_chromaFormat, const Size &size, const unsigned _maxCUSize, const unsigned _margin, const bool _decoder, const int _layerId, const bool enablePostFilteringForHFR, const bool gopBasedTemporalFilterEnabled, const bool fgcSEIAnalysisEnabled) +#else void Picture::create( const ChromaFormat &_chromaFormat, const Size &size, const unsigned _maxCUSize, const unsigned _margin, const bool _decoder, const int _layerId, const bool gopBasedTemporalFilterEnabled, const bool fgcSEIAnalysisEnabled ) +#endif { layerId = _layerId; UnitArea::operator=( UnitArea( _chromaFormat, Area( Position{ 0, 0 }, size ) ) ); @@ -89,6 +93,13 @@ void Picture::create( const ChromaFormat &_chromaFormat, const Size &size, const M_BUFS( 0, PIC_RECONSTRUCTION ).create( _chromaFormat, a, _maxCUSize, margin, MEMORY_ALIGN_DEF_SIZE ); M_BUFS( 0, PIC_RECON_WRAP ).create( _chromaFormat, a, _maxCUSize, margin, MEMORY_ALIGN_DEF_SIZE ); +#if JVET_Z0120_SII_SEI_PROCESSING + if (enablePostFilteringForHFR) + { + M_BUFS(0, PIC_YUV_POST_REC).create(_chromaFormat, a, _maxCUSize, margin, MEMORY_ALIGN_DEF_SIZE); + } +#endif + if( !_decoder ) { M_BUFS( 0, PIC_ORIGINAL ). create( _chromaFormat, a ); @@ -223,6 +234,11 @@ const CPelUnitBuf Picture::getRecoBuf(const UnitArea &unit, bool wrap) const PelUnitBuf Picture::getRecoBuf(bool wrap) { return M_BUFS(scheduler.getSplitPicId(), wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION); } const CPelUnitBuf Picture::getRecoBuf(bool wrap) const { return M_BUFS(scheduler.getSplitPicId(), wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION); } +#if JVET_Z0120_SII_SEI_PROCESSING + PelUnitBuf Picture::getPostRecBuf() { return M_BUFS(scheduler.getSplitPicId(), PIC_YUV_POST_REC); } +const CPelUnitBuf Picture::getPostRecBuf() const { return M_BUFS(scheduler.getSplitPicId(), PIC_YUV_POST_REC); } +#endif + void Picture::finalInit( const VPS* vps, const SPS& sps, const PPS& pps, PicHeader *picHeader, APS** alfApss, APS* lmcsAps, APS* scalingListAps ) { for( auto &sei : SEIs ) @@ -1332,3 +1348,244 @@ PelUnitBuf Picture::getDisplayBuf() return *m_invColourTransfBuf; } + + +#if JVET_Z0120_SII_SEI_PROCESSING +void Picture::copyToPic(const SPS *sps, PelStorage *pcPicYuvSrc, PelStorage *pcPicYuvDst) +{ + const ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); + int numValidComponents = getNumberValidComponents(chromaFormatIDC); + + Pel *srcPxl, *dstPxl; + int iSrcStride, iSrcHeight, iSrcWidth; + int iDstStride; + + for (int comp = 0; comp < numValidComponents; comp++) + { + + if (comp == COMPONENT_Y) { + srcPxl = pcPicYuvSrc->Y().buf; + dstPxl = pcPicYuvDst->Y().buf; + iSrcStride = pcPicYuvSrc->Y().stride; + iSrcHeight = pcPicYuvSrc->Y().height; + iSrcWidth = pcPicYuvSrc->Y().width; + iDstStride = pcPicYuvSrc->Y().stride; + } + else if (comp == COMPONENT_Cb) { + srcPxl = pcPicYuvSrc->Cb().buf; + dstPxl = pcPicYuvDst->Cb().buf; + iSrcStride = pcPicYuvSrc->Cb().stride; + iSrcHeight = pcPicYuvSrc->Cb().height; + iSrcWidth = pcPicYuvSrc->Cb().width; + iDstStride = pcPicYuvSrc->Cb().stride; + } + else { + srcPxl = pcPicYuvSrc->Cr().buf; + dstPxl = pcPicYuvDst->Cr().buf; + iSrcStride = pcPicYuvSrc->Cr().stride; + iSrcHeight = pcPicYuvSrc->Cr().height; + iSrcWidth = pcPicYuvSrc->Cr().width; + iDstStride = pcPicYuvSrc->Cr().stride; + } + + if (iSrcStride == iDstStride) + { + ::memcpy(dstPxl, srcPxl, sizeof(Pel) * iSrcStride * iSrcHeight /*getTotalHeight(compId)*/); + } + else + { + for (int y = 0; y < iSrcHeight; y++, srcPxl += iSrcStride, dstPxl += iDstStride) + { + ::memcpy(dstPxl, srcPxl, iSrcWidth * sizeof(Pel)); + } + } + } +} + +Picture* Picture::findNextPicPOC(Picture* pcPic, PicList* pcListPic) +{ + Picture* nextPic = NULL; + Picture* listPic = NULL; + PicList::iterator iterListPic = pcListPic->begin(); + for (int i = 0; i < (int)(pcListPic->size()); i++) + { + listPic = *(iterListPic); + if (listPic->getPOC() == pcPic->getPOC() + 1) + { + nextPic = *(iterListPic); + } + iterListPic++; + } + return nextPic; +} + + +Picture* Picture::findPrevPicPOC(Picture* pcPic, PicList* pcListPic) +{ + Picture* prevPic = NULL; + Picture* listPic = NULL; + PicList::iterator iterListPic = pcListPic->begin(); + for (int i = 0; i < (int)(pcListPic->size()); i++) + { + listPic = *(iterListPic); + if (listPic->getPOC() == pcPic->getPOC() - 1) + { + prevPic = *(iterListPic); + } + iterListPic++; + } + return prevPic; +} + +void Picture::xOutputPostFilteredPic(Picture* pcPic, PicList* pcListPic, int blendingRatio) +{ + const SPS *sps = pcPic->cs->sps; + const ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); + + if ((pcPic->getPOC()) % blendingRatio != 0 || pcPic->getPOC() == 0) + pcPic->getPostRecBuf().copyFrom(pcPic->getRecoBuf()); + + if ((pcPic->getPOC() + 1) % blendingRatio == 0) + { + Picture* nextPic = findNextPicPOC(pcPic, pcListPic); + if (nextPic) + { +#if DISABLE_PRE_POST_FILTER_FOR_IDR_CRA + if((nextPic->m_pictureType == NAL_UNIT_CODED_SLICE_IDR_W_RADL) || + (nextPic->m_pictureType == NAL_UNIT_CODED_SLICE_IDR_N_LP) || + (nextPic->m_pictureType == NAL_UNIT_CODED_SLICE_CRA)) + { + nextPic->getPostRecBuf().copyFrom(nextPic->getRecoBuf()); + return; + } +#endif + PelUnitBuf currTmp = pcPic->getRecoBuf(); + PelUnitBuf nextTmp = nextPic->getRecoBuf(); + PelUnitBuf postTmp = nextPic->getPostRecBuf(); + + PelUnitBuf* currYuv = &currTmp; + PelUnitBuf* nextYuv = &nextTmp; + PelUnitBuf* postYuv = &postTmp; + + int numValidComponents = getNumberValidComponents(chromaFormatIDC); + for (int chan = 0; chan < numValidComponents; chan++) + { + const ComponentID ch = ComponentID(chan); + const ChannelType cType = (ch == COMPONENT_Y) ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA; + const int bitDepth = pcPic->cs->sps->getBitDepth(cType); + const int maxOutputValue = (1 << bitDepth) - 1; + + Pel *currPxl, *nextPxl, *postPxl; + int iStride, iHeight, iWidth; + if (ch == COMPONENT_Y) { + currPxl = currYuv->Y().buf; + nextPxl = nextYuv->Y().buf; + postPxl = postYuv->Y().buf; + iStride = currYuv->Y().stride; + iHeight = currYuv->Y().height; + iWidth = currYuv->Y().width; + } + else if (ch == COMPONENT_Cb) { + nextPxl = nextYuv->Cb().buf; + currPxl = currYuv->Cb().buf; + postPxl = postYuv->Cb().buf; + iStride = currYuv->Cb().stride; + iHeight = currYuv->Cb().height; + iWidth = currYuv->Cb().width; + } + else { + nextPxl = nextYuv->Cr().buf; + currPxl = currYuv->Cr().buf; + postPxl = postYuv->Cr().buf; + iStride = currYuv->Cr().stride; + iHeight = currYuv->Cr().height; + iWidth = currYuv->Cr().width; + } + for (int y = 0; y < iHeight; y++) + { + for (int x = 0; x < iWidth; x++) + { +#if ENABLE_USER_DEFINED_WEIGHTS + postPxl[x] = std::min(maxOutputValue, std::max(0, (int)(((nextPxl[x]) / SII_PF_W2) - ((currPxl[x] * SII_PF_W1) / SII_PF_W2)))); +#else + postPxl[x] = std::min(maxOutputValue, std::max(0, (((nextPxl[x] * (blendingRatio + 1)) / blendingRatio) - (currPxl[x] / blendingRatio)))); +#endif + } + currPxl += iStride; + nextPxl += iStride; + postPxl += iStride; + } + } + } + } +} + +void Picture::xOutputPreFilteredPic(Picture* pcPic, PicList* pcListPic, int blendingRatio, int intraPeriod) +{ + const SPS *sps = pcPic->cs->sps; + const ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); +#if DISABLE_PRE_POST_FILTER_FOR_IDR_CRA + if (pcPic->getPOC() == 0 || + (pcPic->getPOC() % intraPeriod == 0)) + { + return; + } +#endif + if (pcPic->getPOC() % blendingRatio == 0) + { + Picture* prevPic = findPrevPicPOC(pcPic, pcListPic); + if (prevPic) + { + PelStorage* currYuv = &pcPic->m_bufs[PIC_ORIGINAL]; + PelStorage* prevYuv = &prevPic->m_bufs[PIC_ORIGINAL]; + int numValidComponents = getNumberValidComponents(chromaFormatIDC); + for (int chan = 0; chan < numValidComponents; chan++) + { + const ComponentID ch = ComponentID(chan); + const ChannelType cType = (ch == COMPONENT_Y) ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA; + const int bitDepth = pcPic->cs->sps->getBitDepth(cType); + const int maxOutputValue = (1 << bitDepth) - 1; + + Pel *currPxl, *prevPxl; + int iStride, iHeight, iWidth; + if (ch == COMPONENT_Y) { + currPxl = currYuv->Y().buf; + prevPxl = prevYuv->Y().buf; + iStride = currYuv->Y().stride; + iHeight = currYuv->Y().height; + iWidth = currYuv->Y().width; + } + else if (ch == COMPONENT_Cb) { + prevPxl = prevYuv->Cb().buf; + currPxl = currYuv->Cb().buf; + iStride = currYuv->Cb().stride; + iHeight = currYuv->Cb().height; + iWidth = currYuv->Cb().width; + } + else { + prevPxl = prevYuv->Cr().buf; + currPxl = currYuv->Cr().buf; + iStride = currYuv->Cr().stride; + iHeight = currYuv->Cr().height; + iWidth = currYuv->Cr().width; + } + + for (int y = 0; y < iHeight; y++) + { + for (int x = 0; x < iWidth; x++) + { +#if ENABLE_USER_DEFINED_WEIGHTS + currPxl[x] = std::min(maxOutputValue, std::max(0, (int)((currPxl[x] * SII_PF_W2) + (prevPxl[x] * SII_PF_W1)); +#else + currPxl[x] = std::min(maxOutputValue, std::max(0, (((currPxl[x] * blendingRatio) / (blendingRatio + 1)) + (prevPxl[x] / (blendingRatio + 1))))); +#endif + } + currPxl += iStride; + prevPxl += iStride; + } + } + } + } +} +#endif + diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 84b89e693..0792db054 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -64,7 +64,11 @@ struct Picture : public UnitArea uint32_t margin; Picture(); +#if JVET_Z0120_SII_SEI_PROCESSING + void create(const ChromaFormat &_chromaFormat, const Size &size, const unsigned _maxCUSize, const unsigned margin, const bool bDecoder, const int layerId, const bool enablePostFilteringForHFR, const bool gopBasedTemporalFilterEnabled = false, const bool fgcSEIAnalysisEnabled = false); +#else void create(const ChromaFormat &_chromaFormat, const Size &size, const unsigned _maxCUSize, const unsigned margin, const bool bDecoder, const int layerId, const bool gopBasedTemporalFilterEnabled = false, const bool fgcSEIAnalysisEnabled = false); +#endif void destroy(); void createTempBuffers( const unsigned _maxCUSize ); @@ -82,6 +86,14 @@ struct Picture : public UnitArea void createColourTransfProcessor(bool firstPictureInSequence, SEIColourTransformApply* ctiCharacteristics, PelStorage* ctiBuf, int width, int height, ChromaFormat fmt, int bitDepth); PelUnitBuf getDisplayBuf(); +#if JVET_Z0120_SII_SEI_PROCESSING + void copyToPic(const SPS *sps, PelStorage *pcPicYuvSrc, PelStorage *pcPicYuvDst); + Picture* findPrevPicPOC(Picture* pcPic, PicList* pcListPic); + Picture* findNextPicPOC(Picture* pcPic, PicList* pcListPic); + void xOutputPostFilteredPic(Picture* pcPic, PicList* pcListPic, int blendingRatio); + void xOutputPreFilteredPic(Picture* pcPic, PicList* pcListPic, int blendingRatio, int intraPeriod); +#endif + PelBuf getOrigBuf(const CompArea &blk); const CPelBuf getOrigBuf(const CompArea &blk) const; PelUnitBuf getOrigBuf(const UnitArea &unit); @@ -128,6 +140,11 @@ struct Picture : public UnitArea PelUnitBuf getBuf(const UnitArea &unit, const PictureType &type); const CPelUnitBuf getBuf(const UnitArea &unit, const PictureType &type) const; +#if JVET_Z0120_SII_SEI_PROCESSING + PelUnitBuf getPostRecBuf(); + const CPelUnitBuf getPostRecBuf() const; +#endif + void extendPicBorder( const PPS *pps ); void extendWrapBorder( const PPS *pps ); void finalInit( const VPS* vps, const SPS& sps, const PPS& pps, PicHeader *picHeader, APS** alfApss, APS* lmcsAps, APS* scalingListAps ); diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp index dc5c10d26..778050f99 100644 --- a/source/Lib/CommonLib/SEI.cpp +++ b/source/Lib/CommonLib/SEI.cpp @@ -477,6 +477,9 @@ const char *SEI::getSEIMessageString(SEI::PayloadType payloadType) case SEI::EXTENDED_DRAP_INDICATION: return "Extended DRAP indication"; case SEI::CONSTRAINED_RASL_ENCODING: return "Constrained RASL encoding"; case SEI::VDI_SEI_ENVELOPE: return "Video decoding interface SEI envelope"; +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + case SEI::SHUTTER_INTERVAL_INFO: return "Shutter interval information"; +#endif default: return "Unknown"; } } diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h index 51f16fb9e..0cb2f50e7 100644 --- a/source/Lib/CommonLib/SEI.h +++ b/source/Lib/CommonLib/SEI.h @@ -91,6 +91,9 @@ public: EXTENDED_DRAP_INDICATION = 206, CONSTRAINED_RASL_ENCODING = 207, VDI_SEI_ENVELOPE = 208, +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + SHUTTER_INTERVAL_INFO = 209, +#endif }; SEI() {} @@ -101,6 +104,22 @@ public: virtual PayloadType payloadType() const = 0; }; +#if JVET_Z0120_SHUTTER_INTERVAL_SEI +class SEIShutterIntervalInfo : public SEI +{ +public: + PayloadType payloadType() const { return SHUTTER_INTERVAL_INFO; } + SEIShutterIntervalInfo() {} + virtual ~SEIShutterIntervalInfo() {} + + bool m_siiEnabled; + unsigned m_siiNumUnitsInShutterInterval; + unsigned m_siiTimeScale; + unsigned m_siiMaxSubLayersMinus1; + bool m_siiFixedSIwithinCLVS; + std::vector<unsigned> m_siiSubLayerNumUnitsInSI; +}; +#endif class SEIEquirectangularProjection : public SEI { diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 491a54036..282cc93d0 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -4470,7 +4470,11 @@ void Slice::scaleRefPicList( Picture *scaledRefPic[ ], PicHeader *picHeader, APS scaledRefPic[j]->poc = NOT_VALID; +#if JVET_Z0120_SII_SEI_PROCESSING + scaledRefPic[j]->create( sps->getChromaFormatIdc(), Size( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples() ), sps->getMaxCUWidth(), sps->getMaxCUWidth() + 16, isDecoder, layerId, false); +#else scaledRefPic[j]->create( sps->getChromaFormatIdc(), Size( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples() ), sps->getMaxCUWidth(), sps->getMaxCUWidth() + 16, isDecoder, layerId ); +#endif } scaledRefPic[j]->poc = poc; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index f6d058c43..e76c212af 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -56,6 +56,7 @@ //########### place macros to be removed in next cycle below this line ############### #define JVET_Z0111_ADAPT_BYPASS_AFFINE_ME 1 // JVET-Z0111 #define JVET_Z0046_Green_Metadata 1 // JVET-Z0046 +#define JVET_Z0120_SHUTTER_INTERVAL_SEI 1 // JVET-Z0120 //########### place macros to be be kept below this line ############### #define JVET_X0143_ALF_APS_ID_OFFSET 0 // A value between 0 to 7 inclusive. This macro should be kept, or to be defined as a configuration parameter if possible. @@ -104,6 +105,12 @@ typedef std::pair<int, int> TrCost; #define JVET_O0756_CALCULATE_HDRMETRICS 1 #endif +#define JVET_Z0120_SII_SEI_PROCESSING 1 // This is an example illustration of using SII SEI messages for backwards-compatible HFR video +#if JVET_Z0120_SII_SEI_PROCESSING +#define DISABLE_PRE_POST_FILTER_FOR_IDR_CRA 1 +#define ENABLE_USER_DEFINED_WEIGHTS 0 // User can specify weights for both current and previous picture, such that their sum = 1 +#endif + // clang-format on // ==================================================================================================================== diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 0cc95de27..6bef786dc 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -587,8 +587,12 @@ Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_ { pcPic = new Picture(); +#if JVET_Z0120_SII_SEI_PROCESSING pcPic->create(sps.getChromaFormatIdc(), Size(pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples()), - sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId); + sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId, getShutterFilterFlag() ); +#else + pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId ); +#endif m_cListPic.push_back( pcPic ); @@ -624,16 +628,23 @@ Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_ m_cListPic.push_back( pcPic ); - pcPic->create(sps.getChromaFormatIdc(), Size(pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples()), - sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId); +#if JVET_Z0120_SII_SEI_PROCESSING + pcPic->create(sps.getChromaFormatIdc(), Size(pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples()), sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId, getShutterFilterFlag()); +#else + pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId ); +#endif } else { if( !pcPic->Y().Size::operator==( Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ) ) || pps.pcv->maxCUWidth != sps.getMaxCUWidth() || pps.pcv->maxCUHeight != sps.getMaxCUHeight() || pcPic->layerId != layerId ) { pcPic->destroy(); - pcPic->create(sps.getChromaFormatIdc(), Size(pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples()), - sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId); + +#if JVET_Z0120_SII_SEI_PROCESSING + pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId, getShutterFilterFlag()); +#else + pcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, true, layerId ); +#endif } #if GDR_ENABLED // picHeader should be deleted in case pcPic slot gets reused if (pcPic && pcPic->cs && pcPic->cs->picHeader) diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 9edc78da0..61fd0c001 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -158,6 +158,9 @@ private: bool m_warningMessageSkipPicture; std::list<InputNALUnit*> m_prefixSEINALUs; /// Buffered up prefix SEI NAL Units. +#if JVET_Z0120_SII_SEI_PROCESSING + bool m_ShutterFilterEnable; ///< enable Post-processing with Shutter Interval SEI +#endif int m_debugPOC; int m_debugCTU; @@ -318,6 +321,11 @@ public: bool getMixedNaluTypesInPicFlag(); +#if JVET_Z0120_SII_SEI_PROCESSING + bool getShutterFilterFlag() const { return m_ShutterFilterEnable; } + void setShutterFilterFlag(bool value) { m_ShutterFilterEnable = value; } +#endif + protected: void xUpdateRasInit(Slice* slice); diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp index 9fceb6f98..c473b3a71 100644 --- a/source/Lib/DecoderLib/SEIread.cpp +++ b/source/Lib/DecoderLib/SEIread.cpp @@ -403,6 +403,12 @@ void SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType sei = new SEIConstrainedRaslIndication; xParseSEIConstrainedRaslIndication((SEIConstrainedRaslIndication&) *sei, payloadSize, pDecodedMessageOutputStream); break; +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + case SEI::SHUTTER_INTERVAL_INFO: + sei = new SEIShutterIntervalInfo; + xParseSEIShutterInterval((SEIShutterIntervalInfo&)*sei, payloadSize, pDecodedMessageOutputStream); + break; +#endif default: for (uint32_t i = 0; i < payloadSize; i++) { @@ -533,6 +539,31 @@ void SEIReader::xParseSEIuserDataUnregistered(SEIuserDataUnregistered &sei, uint } } +#if JVET_Z0120_SHUTTER_INTERVAL_SEI +void SEIReader::xParseSEIShutterInterval(SEIShutterIntervalInfo& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) +{ + int32_t i; + uint32_t val; + output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize); + sei_read_code(pDecodedMessageOutputStream, 32, val, "sii_time_scale"); sei.m_siiTimeScale = val; + sei_read_flag(pDecodedMessageOutputStream, val, "fixed_shutter_interval_within_clvs_flag"); sei.m_siiFixedSIwithinCLVS = val; + if (sei.m_siiFixedSIwithinCLVS) + { + sei_read_code(pDecodedMessageOutputStream, 32, val, "sii_num_units_in_shutter_interval"); sei.m_siiNumUnitsInShutterInterval = val; + } + else + { + sei_read_code(pDecodedMessageOutputStream, 3, val, "sii_max_sub_layers_minus1 "); sei.m_siiMaxSubLayersMinus1 = val; + sei.m_siiSubLayerNumUnitsInSI.resize(sei.m_siiMaxSubLayersMinus1 + 1); + for (i = 0; i <= sei.m_siiMaxSubLayersMinus1; i++) + { + sei_read_code(pDecodedMessageOutputStream, 32, val, "sub_layer_num_units_in_shutter_interval[ i ]"); + sei.m_siiSubLayerNumUnitsInSI[i] = val; + } + } +} +#endif + /** * parse bitstream bs and unpack a decoded picture hash SEI message * of payloadSize bytes into sei. diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h index 51495d9ca..80bce5755 100644 --- a/source/Lib/DecoderLib/SEIread.h +++ b/source/Lib/DecoderLib/SEIread.h @@ -103,6 +103,9 @@ protected: void xParseSEIExtendedDrapIndication (SEIExtendedDrapIndication& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); void xParseSEIColourTransformInfo (SEIColourTransformInfo& sei, uint32_t payloadSize, std::ostream* pDecodedMessageOutputStream); void xParseSEIConstrainedRaslIndication (SEIConstrainedRaslIndication& sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream); +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + void xParseSEIShutterInterval(SEIShutterIntervalInfo& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); +#endif void sei_read_scode(std::ostream *pOS, uint32_t length, int& code, const char *pSymbolName); void sei_read_code(std::ostream *pOS, uint32_t length, uint32_t &ruiCode, const char *pSymbolName); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index a80e3466c..bdaf7940e 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -180,6 +180,10 @@ protected: bool m_printMSSSIM; bool m_printWPSNR; bool m_cabacZeroWordPaddingEnabled; +#if JVET_Z0120_SII_SEI_PROCESSING + bool m_ShutterFilterEnable; ///< enable Pre-Filtering with Shutter Interval SEI + int m_SII_BlendingRatio; +#endif bool m_gciPresentFlag; bool m_onePictureOnlyConstraintFlag; @@ -654,6 +658,14 @@ protected: bool m_alternativeTransferCharacteristicsSEIEnabled; uint8_t m_preferredTransferCharacteristics; #endif + +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + bool m_siiSEIEnabled; + uint32_t m_siiSEINumUnitsInShutterInterval; + uint32_t m_siiSEITimeScale; + std::vector<uint32_t> m_siiSEISubLayerNumUnitsInSI; +#endif + // film grain characterstics sei bool m_fgcSEIEnabled; bool m_fgcSEICancelFlag; @@ -1087,6 +1099,14 @@ public: bool getCabacZeroWordPaddingEnabled() const { return m_cabacZeroWordPaddingEnabled; } void setCabacZeroWordPaddingEnabled(bool value) { m_cabacZeroWordPaddingEnabled = value; } +#if JVET_Z0120_SII_SEI_PROCESSING + bool getShutterFilterFlag() const { return m_ShutterFilterEnable; } + void setShutterFilterFlag(bool value) { m_ShutterFilterEnable = value; } + + int getBlendingRatioSII() const { return m_SII_BlendingRatio; } + void setBlendingRatioSII(int value) { m_SII_BlendingRatio = value; } +#endif + //====== Coding Structure ======== void setIntraPeriod (int i) { m_intraPeriod = i; } void setDecodingRefreshType ( int i ) { m_decodingRefreshType = (uint32_t)i; } @@ -1696,6 +1716,18 @@ public: void setSubpicDecodedPictureHashType(HashType m) { m_subpicDecodedPictureHashType = m; } HashType getSubpicDecodedPictureHashType() const { return m_subpicDecodedPictureHashType; } +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + void setSiiSEIEnabled(bool b) { m_siiSEIEnabled = b; } + bool getSiiSEIEnabled() { return m_siiSEIEnabled; } + void setSiiSEINumUnitsInShutterInterval(uint32_t value) { m_siiSEINumUnitsInShutterInterval = value; } + uint32_t getSiiSEINumUnitsInShutterInterval() { return m_siiSEINumUnitsInShutterInterval; } + void setSiiSEITimeScale(uint32_t value) { m_siiSEITimeScale = value; } + uint32_t getSiiSEITimeScale() { return m_siiSEITimeScale; } + uint32_t getSiiSEIMaxSubLayersMinus1() { return uint32_t(std::max(1u, uint32_t(m_siiSEISubLayerNumUnitsInSI.size())) - 1); } + bool getSiiSEIFixedSIwithinCLVS() { return m_siiSEISubLayerNumUnitsInSI.empty(); } + void setSiiSEISubLayerNumUnitsInSI(const std::vector<uint32_t>& b) { m_siiSEISubLayerNumUnitsInSI = b; } + uint32_t getSiiSEISubLayerNumUnitsInSI(uint32_t idx) const { return m_siiSEISubLayerNumUnitsInSI[idx]; } +#endif void setBufferingPeriodSEIEnabled(bool b) { m_bufferingPeriodSEIEnabled = b; } bool getBufferingPeriodSEIEnabled() const { return m_bufferingPeriodSEIEnabled; } void setPictureTimingSEIEnabled(bool b) { m_pictureTimingSEIEnabled = b; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index df0356600..c12f5fac2 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -844,6 +844,14 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS SEIConstrainedRaslIndication* seiConstrainedRasl = new SEIConstrainedRaslIndication; seiMessages.push_back(seiConstrainedRasl); } +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + if (m_pcCfg->getSiiSEIEnabled()) + { + SEIShutterIntervalInfo *seiShutterInterval = new SEIShutterIntervalInfo; + m_seiEncoder.initSEIShutterIntervalInfo(seiShutterInterval); + seiMessages.push_back(seiShutterInterval); + } +#endif } void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice) diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 685c3aaee..2480c4aa4 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -487,6 +487,16 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu #endif picCurr->poc = m_iPOCLast - 1; m_iPOCLast -= 2; + +#if JVET_Z0120_SII_SEI_PROCESSING + if (getShutterFilterFlag()) + { + int blendingRatio = getBlendingRatioSII(); + picCurr->xOutputPreFilteredPic(picCurr, &m_cListPic, blendingRatio, m_intraPeriod); + picCurr->copyToPic(sps, &picCurr->m_bufs[PIC_ORIGINAL], pcPicYuvOrg); + } +#endif + if( getUseAdaptiveQP() ) { AQpPreanalyzer::preanalyze( picCurr ); @@ -620,6 +630,15 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu pcPicCurr->poc = m_iPOCLast; +#if JVET_Z0120_SII_SEI_PROCESSING + if (getShutterFilterFlag()) + { + int blendingRatio = getBlendingRatioSII(); + pcPicCurr->xOutputPreFilteredPic(pcPicCurr, &m_cListPic, blendingRatio, m_intraPeriod); + pcPicCurr->copyToPic(pSPS, &pcPicCurr->m_bufs[PIC_ORIGINAL], pcPicYuvOrg); + } +#endif + // compute image characteristics if( getUseAdaptiveQP() ) { @@ -776,6 +795,15 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicY pcField->topField = isTopField; // interlaced requirement +#if JVET_Z0120_SII_SEI_PROCESSING + if (getShutterFilterFlag()) + { + int blendingRatio = getBlendingRatioSII(); + pcField->xOutputPreFilteredPic(pcField, &m_cListPic, blendingRatio, m_intraPeriod); + pcField->copyToPic(pSPS, &pcField->m_bufs[PIC_ORIGINAL], pcPicYuvOrg); + } +#endif + // compute image characteristics if( getUseAdaptiveQP() ) { @@ -890,9 +918,16 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict if (rpcPic==0) { rpcPic = new Picture; + +#if JVET_Z0120_SII_SEI_PROCESSING rpcPic->create(sps.getChromaFormatIdc(), Size(pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples()), - sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, false, m_layerId, + sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, false, m_layerId, getShutterFilterFlag(), getGopBasedTemporalFilterEnabled(), m_fgcSEIAnalysisEnabled); +#else + rpcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, false, m_layerId, getGopBasedTemporalFilterEnabled() + , m_fgcSEIAnalysisEnabled); +#endif + if (m_resChangeInClvsEnabled) { const PPS &pps0 = *m_ppsMap.getPS(0); diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index fe2e467a5..3422168f8 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -507,6 +507,28 @@ void SEIEncoder::initSEIExtendedDrapIndication(SEIExtendedDrapIndication *sei) } } +#if JVET_Z0120_SHUTTER_INTERVAL_SEI +void SEIEncoder::initSEIShutterIntervalInfo(SEIShutterIntervalInfo *seiShutterIntervalInfo) +{ + assert(m_isInitialized); + assert(seiShutterIntervalInfo != NULL); + seiShutterIntervalInfo->m_siiTimeScale = m_pcCfg->getSiiSEITimeScale(); + seiShutterIntervalInfo->m_siiFixedSIwithinCLVS = m_pcCfg->getSiiSEIFixedSIwithinCLVS(); + if (seiShutterIntervalInfo->m_siiFixedSIwithinCLVS == true) + { + seiShutterIntervalInfo->m_siiNumUnitsInShutterInterval = m_pcCfg->getSiiSEINumUnitsInShutterInterval(); + } + else + { + seiShutterIntervalInfo->m_siiMaxSubLayersMinus1 = m_pcCfg->getSiiSEIMaxSubLayersMinus1(); + seiShutterIntervalInfo->m_siiSubLayerNumUnitsInSI.resize(seiShutterIntervalInfo->m_siiMaxSubLayersMinus1 + 1); + for (int32_t i = 0; i <= seiShutterIntervalInfo->m_siiMaxSubLayersMinus1; i++) + { + seiShutterIntervalInfo->m_siiSubLayerNumUnitsInSI[i] = m_pcCfg->getSiiSEISubLayerNumUnitsInSI(i); + } + } +} +#endif template <typename T> static void readTokenValue(T &returnedValue, /// value returned diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h index 778455018..4382de86e 100644 --- a/source/Lib/EncoderLib/SEIEncoder.h +++ b/source/Lib/EncoderLib/SEIEncoder.h @@ -90,6 +90,9 @@ public: void initSEIColourTransformInfo(SEIColourTransformInfo* sei); void readAnnotatedRegionSEI(std::istream &fic, SEIAnnotatedRegions *seiAnnoRegion, bool &failed); void initSEIMultiviewViewPosition(SEIMultiviewViewPosition *sei); +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + void initSEIShutterIntervalInfo(SEIShutterIntervalInfo *sei); +#endif private: EncCfg* m_pcCfg; EncLib* m_pcEncLib; diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp index 4882067ef..fbceadccf 100644 --- a/source/Lib/EncoderLib/SEIwrite.cpp +++ b/source/Lib/EncoderLib/SEIwrite.cpp @@ -157,6 +157,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &h case SEI::CONSTRAINED_RASL_ENCODING: xWriteSEIConstrainedRaslIndication(*static_cast<const SEIConstrainedRaslIndication*>(&sei)); break; +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + case SEI::SHUTTER_INTERVAL_INFO: + xWriteSEIShutterInterval(*static_cast<const SEIShutterIntervalInfo*>(&sei)); + break; +#endif default: THROW("Trying to write unhandled SEI message"); break; @@ -1353,6 +1358,26 @@ void SEIWriter::xWriteSEIColourTransformInfo(const SEIColourTransformInfo& sei) } } +#if JVET_Z0120_SHUTTER_INTERVAL_SEI +void SEIWriter::xWriteSEIShutterInterval(const SEIShutterIntervalInfo &sei) +{ + WRITE_CODE(sei.m_siiTimeScale, 32, "sii_time_scale"); + WRITE_FLAG(sei.m_siiFixedSIwithinCLVS, "fixed_shutter_interval_within_clvs_flag"); + if (sei.m_siiFixedSIwithinCLVS) + { + WRITE_CODE(sei.m_siiNumUnitsInShutterInterval, 32, "sii_num_units_in_shutter_interval"); + } + else + { + WRITE_CODE(sei.m_siiMaxSubLayersMinus1, 3, "sii_max_sub_layers_minus1"); + for (unsigned i = 0; i <= sei.m_siiMaxSubLayersMinus1; i++) + { + WRITE_CODE(sei.m_siiSubLayerNumUnitsInSI[i], 32, "sub_layer_num_units_in_shutter_interval[ i ]"); + } + } +} +#endif + void SEIWriter::xWriteSEIConstrainedRaslIndication(const SEIConstrainedRaslIndication& /*sei*/) { // intentionally empty diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h index 84dbc9139..1e7b07536 100644 --- a/source/Lib/EncoderLib/SEIwrite.h +++ b/source/Lib/EncoderLib/SEIwrite.h @@ -89,6 +89,9 @@ protected: void xWriteSEIContentColourVolume(const SEIContentColourVolume &sei); void xWriteSEIColourTransformInfo(const SEIColourTransformInfo& sei); void xWriteSEIAnnotatedRegions (const SEIAnnotatedRegions& sei); +#if JVET_Z0120_SHUTTER_INTERVAL_SEI + void xWriteSEIShutterInterval(const SEIShutterIntervalInfo& sei); +#endif void xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &hrd, const uint32_t temporalId); void xWriteByteAlign(); protected: -- GitLab