From d2ad51fc0a6e03a1f23033f278724925fc8baa49 Mon Sep 17 00:00:00 2001 From: "Pohsiang (John) Hsu" Date: Wed, 18 Mar 2026 12:38:26 -0700 Subject: [PATCH] mediafoundation: set reasonable number of reference frames if the user didn't set CODECAPI_AVEncVideoMaxNumRefFrame Reviewed-by: Yubo Xie Part-of: --- .../frontends/mediafoundation/codecapi.cpp | 5 ++-- .../frontends/mediafoundation/encode_h264.cpp | 8 ++++-- .../frontends/mediafoundation/encode_hevc.cpp | 10 ++++--- .../frontends/mediafoundation/mftransform.cpp | 26 ++++++++++--------- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/gallium/frontends/mediafoundation/codecapi.cpp b/src/gallium/frontends/mediafoundation/codecapi.cpp index 816ec5ad7c6..f25f4fcebb5 100644 --- a/src/gallium/frontends/mediafoundation/codecapi.cpp +++ b/src/gallium/frontends/mediafoundation/codecapi.cpp @@ -615,7 +615,7 @@ CDX12EncHMFT::GetParameterRange( const GUID *Api, VARIANT *ValueMin, VARIANT *Va ValueMin->ulVal = 1; ValueMax->vt = VT_UI4; - ValueMax->ulVal = m_uiMaxNumRefFrame; + ValueMax->ulVal = GetMaxReferences( m_uiOutputWidth, m_uiOutputHeight ); SteppingDelta->vt = VT_UI4; SteppingDelta->ulVal = 1; @@ -1572,7 +1572,8 @@ CDX12EncHMFT::SetValue( const GUID *Api, VARIANT *Value ) else if( *Api == CODECAPI_AVEncVideoMaxNumRefFrame ) { debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncVideoMaxNumRefFrame - %u\n", this, Value->ulVal ); - if( Value->vt != VT_UI4 ) + UINT32 maxReferences = GetMaxReferences( m_uiOutputWidth, m_uiOutputHeight ); + if( Value->vt != VT_UI4 || Value->ulVal > maxReferences ) { CHECKHR_GOTO( E_INVALIDARG, done ); } diff --git a/src/gallium/frontends/mediafoundation/encode_h264.cpp b/src/gallium/frontends/mediafoundation/encode_h264.cpp index 70d42df1173..a3f50a16fa9 100644 --- a/src/gallium/frontends/mediafoundation/encode_h264.cpp +++ b/src/gallium/frontends/mediafoundation/encode_h264.cpp @@ -1143,8 +1143,12 @@ GetMaxDPBSize( int width, int height, eAVEncH264VLevel level_idc ) UINT32 CDX12EncHMFT::GetMaxReferences( unsigned int width, unsigned int height ) { - int maxDPBSize = GetMaxDPBSize( width, height, m_uiLevel ); - UINT32 uiMaxReferences = std::min( (int) m_EncoderCapabilities.m_uiMaxHWSupportedDPBCapacity, maxDPBSize ); + UINT32 uiMaxReferences = m_EncoderCapabilities.m_uiMaxHWSupportedDPBCapacity; + if( width != 0 && height != 0 ) + { + int maxDPBSize = GetMaxDPBSize( width, height, m_uiLevel ); + uiMaxReferences = std::min( (int) m_EncoderCapabilities.m_uiMaxHWSupportedDPBCapacity, maxDPBSize ); + } return uiMaxReferences; } diff --git a/src/gallium/frontends/mediafoundation/encode_hevc.cpp b/src/gallium/frontends/mediafoundation/encode_hevc.cpp index 283b255a665..0c79bc5ea25 100644 --- a/src/gallium/frontends/mediafoundation/encode_hevc.cpp +++ b/src/gallium/frontends/mediafoundation/encode_hevc.cpp @@ -980,9 +980,13 @@ GetMaxDPBSize( int width, int height, eAVEncH265VLevel level_idc, int minCBSizeY UINT32 CDX12EncHMFT::GetMaxReferences( unsigned int width, unsigned int height ) { - const int minCbSizeY = 1 << ( m_EncoderCapabilities.m_HWSupportH265BlockSizes.bits.log2_min_luma_coding_block_size_minus3 + 3 ); - int maxDPBSize = GetMaxDPBSize( width, height, m_uiLevel, minCbSizeY ); - UINT32 uiMaxReferences = std::min( (int) m_EncoderCapabilities.m_uiMaxHWSupportedDPBCapacity, maxDPBSize ); + UINT32 uiMaxReferences = m_EncoderCapabilities.m_uiMaxHWSupportedDPBCapacity; + if( width != 0 && height != 0 ) + { + const int minCbSizeY = 1 << ( m_EncoderCapabilities.m_HWSupportH265BlockSizes.bits.log2_min_luma_coding_block_size_minus3 + 3 ); + int maxDPBSize = GetMaxDPBSize( width, height, m_uiLevel, minCbSizeY ); + uiMaxReferences = std::min( (int) m_EncoderCapabilities.m_uiMaxHWSupportedDPBCapacity, maxDPBSize ); + } return uiMaxReferences; } diff --git a/src/gallium/frontends/mediafoundation/mftransform.cpp b/src/gallium/frontends/mediafoundation/mftransform.cpp index 2e118c974f3..555b4c37725 100644 --- a/src/gallium/frontends/mediafoundation/mftransform.cpp +++ b/src/gallium/frontends/mediafoundation/mftransform.cpp @@ -888,23 +888,25 @@ CDX12EncHMFT::InitializeEncoder( pipe_video_profile videoProfile, UINT32 Width, CHECKHR_GOTO( MF_E_OUT_OF_RANGE, done ); } - // Please note in scenarios (e.g LTR or SVC) the backend may need to keep track of more references - // than the m_uiMaxNumRefFrame, since the references may be more in the past (up to 16, 8 frames max before - // depending on the codec) - // TODO: If we know at this point that we're not using LTR nor SVC we can set max_references to - // m_uiMaxNumRefFrame and use less ram, but not sure how would this work with codecapi reconfigurations/dynamic - // LTR/SVC requests - // max_references is the number of previous submitted frame recon pics the frontend reference // pic trackers will keep track of and can be indexed by current frame submissions by from the L0/L1 reference lists - UINT32 uiMaxNumRefFrame = GetMaxReferences( Width, Height ); - // if user sets m_uiMaxNumRefFrame, use that to limit - if( m_bMaxNumRefFrameSet ) + // if user didn't set max reference, try to set a reasonable amount + if( !m_bMaxNumRefFrameSet ) { - uiMaxNumRefFrame = std::min( uiMaxNumRefFrame, m_uiMaxNumRefFrame ); + UINT32 uiMaxNumRefFrame = GetMaxReferences( Width, Height ); + UINT32 uiEstimatedRefFrame = 1 /*current frame*/ + 1 /* slack */ + m_uiMaxLongTermReferences; + if( m_uiLayerCount > 1 ) + { + uiEstimatedRefFrame += ( m_uiLayerCount - 1 ); + } + if( uiEstimatedRefFrame > uiMaxNumRefFrame ) + { + CHECKHR_GOTO( E_INVALIDARG, done ); + } + MFE_INFO( "[dx12 hmft 0x%p] HMFT adjusted max_references from %u to %u", this, uiMaxNumRefFrame, uiEstimatedRefFrame ); + m_uiMaxNumRefFrame = uiEstimatedRefFrame; // update CodecAPI value. } - m_uiMaxNumRefFrame = uiMaxNumRefFrame; // update CodecAPI value. encoderSettings.profile = videoProfile; encoderSettings.level = m_uiLevel;