diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 1a6b7365a0b6dc76485180478b122c9c6a10171d..0c29bd61d92707fb797dafd219d91399fa3cf7d9 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -266,6 +266,10 @@ void EncApp::xInitLibCfg( int layerIdx ) m_confWinRight / SPS::getWinUnitX(m_inputChromaFormatIDC), m_confWinTop / SPS::getWinUnitY(m_inputChromaFormatIDC), m_confWinBottom / SPS::getWinUnitY(m_inputChromaFormatIDC)); +#if SCALING_WINDOW_ENABLED + m_cEncLib.setExplicitScalingWindowEnabled ( m_explicitScalingWindowEnabled ); + m_cEncLib.setScalingWindow ( m_scalWinLeft / SPS::getWinUnitX( m_inputChromaFormatIDC ), m_scalWinRight / SPS::getWinUnitX( m_inputChromaFormatIDC ), m_scalWinTop / SPS::getWinUnitY( m_inputChromaFormatIDC ), m_scalWinBottom / SPS::getWinUnitY( m_inputChromaFormatIDC ) ); +#endif m_cEncLib.setScalingRatio ( m_scalingRatioHor, m_scalingRatioVer ); m_cEncLib.setGOPBasedRPREnabledFlag (m_gopBasedRPREnabledFlag); m_cEncLib.setGOPBasedRPRQPThreshold (m_gopBasedRPRQPThreshold); @@ -1979,7 +1983,11 @@ void EncApp::xWriteOutput(int numEncoded, std::list<PelUnitBuf *> &recBufList) } else { +#if SCALING_WINDOW_ENABLED + ppsID = ((sps.getMaxPicWidthInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).width || sps.getMaxPicHeightInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).height) && !m_explicitScalingWindowEnabled) ? m_resChangeInClvsEnabled ? ENC_PPS_ID_RPR : layerId : layerId; +#else ppsID = (sps.getMaxPicWidthInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).width || sps.getMaxPicHeightInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).height) ? ENC_PPS_ID_RPR : layerId; +#endif } const PPS& pps = *m_cEncLib.getPPS(ppsID); if( m_cEncLib.isResChangeInClvsEnabled() && m_cEncLib.getUpscaledOutput() ) diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 708092258b5afa03788396e249c4d276abdfd466..d414ffea397658138aed1128819d7b72d3fd1e44 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -821,6 +821,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("ConfWinRight", m_confWinRight, 0, "Right offset for window conformance mode 3") ("ConfWinTop", m_confWinTop, 0, "Top offset for window conformance mode 3") ("ConfWinBottom", m_confWinBottom, 0, "Bottom offset for window conformance mode 3") +#if SCALING_WINDOW_ENABLED + ("ScalingWindow", m_explicitScalingWindowEnabled, false, "Enable scaling window") + ("ScalWinLeft,-swl", m_scalWinLeft, 0, "Left offset for scaling window") + ("ScalWinRight,-swr", m_scalWinRight, 0, "Right offset for scaling window") + ("ScalWinTop,-swt", m_scalWinTop, 0, "Top offset for scaling window") + ("ScalWinBottom,-swb", m_scalWinBottom, 0, "Bottom offset for scaling window") +#endif ("AccessUnitDelimiter", m_AccessUnitDelimiter, false, "Enable Access Unit Delimiter NALUs") ("EnablePictureHeaderInSliceHeader", m_enablePictureHeaderInSliceHeader, true, "Enable Picture Header in Slice Header") ("FrameRate,-fr", frameRate, std::to_string(0), "Frame rate") @@ -4287,6 +4294,26 @@ bool EncAppCfg::xCheckParameter() "Top conformance window offset must be an integer multiple of the specified chroma subsampling"); xConfirmPara(m_confWinBottom % SPS::getWinUnitY(m_chromaFormatIdc) != 0, "Bottom conformance window offset must be an integer multiple of the specified chroma subsampling"); +#if SCALING_WINDOW_ENABLED + xConfirmPara(m_explicitScalingWindowEnabled && (m_scalingRatioHor != 1.0 || m_scalingRatioVer != 1.0 || m_gopBasedRPREnabledFlag), "ScalingWindow cannot be enabled when GOPBasedRPR is enabled"); + xConfirmPara(m_scalWinLeft % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Left scaling window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara(m_scalWinRight % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Right scaling window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara(m_scalWinTop % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Top scaling window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara(m_scalWinBottom % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Bottom scaling window offset must be an integer multiple of the specified chroma subsampling"); + xConfirmPara((m_scalWinLeft < -m_sourceWidth * 15) || (m_scalWinLeft >= m_sourceWidth), + "The values of SubWidthC * pps_scaling_win_left_offset shall be greater than or equal to -pps_pic_width_in_luma_samples * 15 and less than pps_pic_width_in_luma_samples"); + xConfirmPara((m_scalWinRight < -m_sourceWidth * 15) || (m_scalWinRight >= m_sourceWidth), + "The values of SubWidthC * pps_scaling_win_right_offset shall be greater than or equal to -pps_pic_width_in_luma_samples * 15 and less than pps_pic_width_in_luma_samples"); + xConfirmPara((m_scalWinTop < -m_sourceHeight * 15) || (m_scalWinTop >= m_sourceHeight), + "The values of SubHeightC * pps_scaling_win_top_offset shall be greater than or equal to -pps_pic_height_in_luma_samples * 15 and less than pps_pic_height_in_luma_samples"); + xConfirmPara((m_scalWinBottom < -m_sourceHeight * 15) || (m_scalWinBottom >= m_sourceHeight), + "The values of SubHeightC * pps_scaling_win_bottom_offset shall be greater than or equal to -pps_pic_height_in_luma_samples * 15 and less than pps_pic_height_in_luma_samples"); + xConfirmPara(((m_scalWinLeft+m_scalWinRight) < -m_sourceWidth * 15) || ((m_scalWinLeft+m_scalWinRight) >= m_sourceWidth), + "The values of SubWidthC * (pps_scaling_win_left_offset + pps_scaling_win_right_offset) shall be greater than or equal to -pps_pic_width_in_luma_samples * 15 and less than pps_pic_width_in_luma_samples"); + xConfirmPara(((m_scalWinTop+m_scalWinBottom) < -m_sourceHeight * 15) || ((m_scalWinTop+m_scalWinBottom) >= m_sourceHeight), + "The values of SubHeightC * (pps_scaling_win_top_offset + pps_scaling_win_bottom_offset) shall be greater than or equal to -pps_pic_height_in_luma_samples * 15 and less than pps_pic_height_in_luma_samples"); +#endif + // max CU width and height should be power of 2 uint32_t ui = m_maxCuWidth; diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 609385864ea28253b5ade88c180075a712a31c68..5d7d1422620f676db1c7abdf8362f0e0b125479c 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -111,6 +111,13 @@ protected: int m_confWinRight; int m_confWinTop; int m_confWinBottom; +#if SCALING_WINDOW_ENABLED + bool m_explicitScalingWindowEnabled; + int m_scalWinLeft; + int m_scalWinRight; + int m_scalWinTop; + int m_scalWinBottom; +#endif int m_sourcePadding[2]; ///< number of padded pixels for width and height int m_firstValidFrame; int m_lastValidFrame; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index c5f23c85fb555f5b5a9eca64246390202b67a2f7..d1484a231315afed8687ba99ed66ba26eb6cb5d3 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -148,6 +148,19 @@ #define ENABLE_USER_DEFINED_WEIGHTS 0 // User can specify weights for both current and previous picture, such that their sum = 1 #endif +#ifndef SCALING_WINDOW_ENABLED +#define SCALING_WINDOW_ENABLED 1 +#endif +#ifndef NHK_20230407_1 +#define NHK_20230407_1 1 // bug fix +#endif +#ifndef NHK_20230407_2 +#define NHK_20230407_2 1 // fixed in VTM20.0 +#endif +#ifndef NHK_20230418 +#define NHK_20230418 1 // bug fix +#endif + // clang-format on // ==================================================================================================================== diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 851100a4c379e314129fe896fb91aa4f0e68c34e..c0a1988b50b2962816ef3b8cc4d1b420f0f41f8c 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -161,6 +161,10 @@ protected: int m_sourceWidth; int m_sourceHeight; Window m_conformanceWindow; +#if SCALING_WINDOW_ENABLED + bool m_explicitScalingWindowEnabled; + Window m_scalingWindow; +#endif int m_sourcePadding[2]; int m_framesToBeEncoded; int m_firstValidFrame; @@ -1223,6 +1227,10 @@ public: Window &getConformanceWindow() { return m_conformanceWindow; } void setConformanceWindow (int confLeft, int confRight, int confTop, int confBottom ) { m_conformanceWindow.setWindow (confLeft, confRight, confTop, confBottom); } +#if SCALING_WINDOW_ENABLED + void setExplicitScalingWindowEnabled(bool enabled) { m_explicitScalingWindowEnabled = enabled; } + void setScalingWindow (int scalingLeft, int scalingRight, int scalingTop, int scalingBottom ) { m_scalingWindow.setWindow (scalingLeft, scalingRight, scalingTop, scalingBottom); } +#endif void setFramesToBeEncoded ( int i ) { m_framesToBeEncoded = i; } diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 332211baaad92b4b46390e5f15fc6c190313b65f..10a2a5eeadae23c0cda77c2920e770c2f194bd6d 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -197,6 +197,13 @@ void EncLib::init(AUWriterIf *auWriterIf) pps0.setConformanceWindow( m_conformanceWindow ); pps0.setConformanceWindowFlag( m_conformanceWindow.getWindowEnabledFlag() ); } +#if SCALING_WINDOW_ENABLED + if (m_explicitScalingWindowEnabled) + { + pps0.setExplicitScalingWindowFlag(true); + pps0.setScalingWindow(m_scalingWindow); + } +#endif if (!pps0.getExplicitScalingWindowFlag()) { pps0.setScalingWindow(pps0.getConformanceWindow()); @@ -1451,6 +1458,64 @@ void EncLib::xInitSPS( SPS& sps ) sps.setMaxPicWidthInLumaSamples( m_sourceWidth ); sps.setMaxPicHeightInLumaSamples( m_sourceHeight ); +#if SCALING_WINDOW_ENABLED + bool scalingWindowResChanged = false; + if (m_multiLayerEnabledFlag && m_vps->getMaxLayers() > 0) { + const int minCuSize = std::max(8, 1 << m_log2MinCUSize); + int currPicScaledWidth = m_sourceWidth - SPS::getWinUnitX(m_chromaFormatIDC) * (m_scalingWindow.getWindowLeftOffset() + m_scalingWindow.getWindowRightOffset()); + int currPicScaledHeight = m_sourceHeight - SPS::getWinUnitY( m_chromaFormatIDC) * (m_scalingWindow.getWindowTopOffset() + m_scalingWindow.getWindowBottomOffset()); + + int refPicScaledWidth = currPicScaledWidth; + int refPicScaledHeight = currPicScaledHeight; + const int layerIdx = m_vps->getGeneralLayerIdx(m_layerId); + if (getNumRefLayers(layerIdx) > 0) { + int dWidth = 0; + int dHeight = 0; + for (int refLayerIdx = 0; refLayerIdx < layerIdx; refLayerIdx++) { + if (m_vps->getDirectRefLayerFlag(layerIdx, refLayerIdx)) { + const PPS& refPPS = *getPPS(refLayerIdx); + int scaledWidth = refPPS.getPicWidthInLumaSamples() - SPS::getWinUnitX(m_chromaFormatIDC) * (refPPS.getScalingWindow().getWindowLeftOffset() + refPPS.getScalingWindow().getWindowRightOffset()); + int scaledHeight = refPPS.getPicHeightInLumaSamples() - SPS::getWinUnitY( m_chromaFormatIDC) * (refPPS.getScalingWindow().getWindowTopOffset() + refPPS.getScalingWindow().getWindowBottomOffset()); + CHECK(currPicScaledWidth * 2 < scaledWidth, "CurrPicScalWinWidthL * 2 shall be greater than or equal to refPicScalWinWidthL"); + CHECK(currPicScaledHeight * 2 < scaledHeight, "CurrPicScalWinHeightL * 2 shall be greater than or equal to refPicScalWinHeightL"); + CHECK(currPicScaledWidth > scaledWidth * 8, "CurrPicScalWinWidthL shall be less than or equal to refPicScalWinWidthL * 8"); + CHECK(currPicScaledHeight > scaledHeight * 8, "CurrPicScalWinHeightL shall be less than or equal to refPicScalWinHeightL * 8"); + + int dW = abs(scaledWidth - currPicScaledWidth); + int dH = abs(scaledHeight - currPicScaledHeight); + if (scaledWidth > currPicScaledWidth && dW > dWidth) + { + refPicScaledWidth = scaledWidth; dWidth = dW; + } + if (scaledHeight > currPicScaledHeight && dH > dHeight) + { + refPicScaledHeight = scaledHeight; dHeight = dH; + } + } + } + } + + int maxPicWidth = std::max(m_sourceWidth, ((m_sourceWidth - minCuSize) * refPicScaledWidth + currPicScaledWidth - 1) / currPicScaledWidth); + int maxPicHeight = std::max(m_sourceHeight, ((m_sourceHeight - minCuSize) * refPicScaledHeight + currPicScaledHeight - 1) / currPicScaledHeight); + if (maxPicWidth % minCuSize) + { + maxPicWidth += ((maxPicWidth / minCuSize) + 1) * minCuSize - maxPicWidth; + } + if (maxPicHeight % minCuSize) + { + maxPicHeight += ((maxPicHeight / minCuSize) + 1) * minCuSize - maxPicHeight; + } + if (maxPicWidth > m_sourceWidth || maxPicHeight > m_sourceHeight) + scalingWindowResChanged = true; + CHECK((currPicScaledWidth * maxPicWidth) < refPicScaledWidth * (m_sourceWidth - minCuSize), + "(CurrPicScalWinWidthL * sps_pic_width_max_in_luma_samples) shall be greater than or equal to (refPicScalWinWidthL * (pps_pic_width_in_luma_samples - Max(8, MinCbSizeY)))"); + CHECK((currPicScaledHeight * maxPicHeight) < refPicScaledHeight * (m_sourceHeight - minCuSize), + "(CurrPicScalWinHeightL * sps_pic_height_max_in_luma_samples) shall be greater than or equal to (refPicScalWinHeightL * (pps_pic_height_in_luma_samples - Max(8, MinCbSizeY)))"); + sps.setMaxPicWidthInLumaSamples(maxPicWidth); + sps.setMaxPicHeightInLumaSamples(maxPicHeight); + } +#endif + if (m_resChangeInClvsEnabled) { int maxPicWidth = std::max(m_sourceWidth, (int)((double)m_sourceWidth / m_scalingRatioHor + 0.5)); @@ -1738,8 +1803,13 @@ void EncLib::xInitSPS( SPS& sps ) sps.setInterLayerPresentFlag( m_layerId > 0 && m_vps->getMaxLayers() > 1 && !m_vps->getAllIndependentLayersFlag() && !m_vps->getIndependentLayerFlag( m_vps->getGeneralLayerIdx( m_layerId ) ) ); CHECK( m_vps->getIndependentLayerFlag( m_vps->getGeneralLayerIdx( m_layerId ) ) && sps.getInterLayerPresentFlag(), " When vps_independent_layer_flag[GeneralLayerIdx[nuh_layer_id ]] is equal to 1, the value of inter_layer_ref_pics_present_flag shall be equal to 0." ); +#if SCALING_WINDOW_ENABLED + sps.setResChangeInClvsEnabledFlag(m_resChangeInClvsEnabled || m_constrainedRaslEncoding || scalingWindowResChanged); + sps.setRprEnabledFlag(m_rprEnabledFlag || m_explicitScalingWindowEnabled || scalingWindowResChanged); +#else sps.setResChangeInClvsEnabledFlag(m_resChangeInClvsEnabled || m_constrainedRaslEncoding); sps.setRprEnabledFlag(m_rprEnabledFlag); +#endif #if JVET_AD0045 sps.setGOPBasedRPREnabledFlag(m_gopBasedRPREnabledFlag); #endif