mediafoundation: Support new MFSampleExtension for PSNR, QPMap, and BitsUsedMap.

Added a helper function MFAttachPipeResourceAsSampleExtension that converts pipe_resource into D3D12 resource, attached as IMFMediaBuffer to IMFSample.
Conditionally applied MFAttachPipeResourceAsSampleExtension to:
    MFSampleExtension_FramePsnrYuv
    MFSampleExtension_VideoEncodeQPMap
    MFSampleExtension_VideoEncodeBitsUsedMap

Reviewed-by: Yubo Xie <yuboxie@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35264>
This commit is contained in:
Wenfeng Gao 2025-05-28 16:31:36 -07:00 committed by Marge Bot
parent 4df6954219
commit 9b1c4f2e04
4 changed files with 135 additions and 6 deletions

View file

@ -253,12 +253,6 @@ typedef enum IntraRefreshMode
HMFT_INTRA_REFRESH_MODE_MAX
} IntraRefreshMode;
// MFSampleExtension_VideoEncodeQPMap {2C68A331-B712-49CA-860A-3A1D58237D88}
// Type: PTR
// Used by to return the QP map of the current frame
DEFINE_GUID( MFSampleExtension_VideoEncodeQPMap, 0x2c68a331, 0xb712, 0x49ca, 0x86, 0xa, 0x3a, 0x1d, 0x58, 0x23, 0x7d, 0x88 );
#ifndef CODECAPI_AVEncVideoEnableFramePsnrYuv
// AVEncVideoEnableFramePsnrYuv (BOOL)
// Indicates whether to enable or disable reporting frame PSNR of YUV planes for video encoding.
@ -293,6 +287,34 @@ DEFINE_CODECAPI_GUID( AVEncVideoOutputBitsUsedMapBlockSize,"6C2CD11A-CA3B-44BD-9
#define CODECAPI_AVEncVideoOutputBitsUsedMapBlockSize DEFINE_CODECAPI_GUIDNAMED( AVEncVideoOutputBitsUsedMapBlockSize )
#endif
#ifndef MFSampleExtension_FramePsnrYuv
typedef struct _MFSampleExtensionPsnrYuv
{
FLOAT psnrY; // PSNR for Y plane
FLOAT psnrU; // PSNR for U plane
FLOAT psnrV; // PSNR for V plane
} MFSampleExtensionPsnrYuv;
// MFSampleExtension_FramePsnrYuv {1C633A3D-566F-4752-833B-2907DF5415E1}
// Type: IMFMediaBuffer
// A MFSampleExtensionPsnrYuv structure that specifies the PSNR data of YUV planes of an encoded video frame.
DEFINE_GUID( MFSampleExtension_FramePsnrYuv, 0x1c633a3d, 0x566f, 0x4752, 0x83, 0x3b, 0x29, 0x07, 0xdf, 0x54, 0x15, 0xe1 );
#endif
#ifndef MFSampleExtension_VideoEncodeQPMap
// MFSampleExtension_VideoEncodeQPMap {2C68A331-B712-49CA-860A-3A1D58237D88}
// Type: IMFMediaBuffer
// The QP map of an encoded video frame.
DEFINE_GUID( MFSampleExtension_VideoEncodeQPMap, 0x2c68a331, 0xb712, 0x49ca, 0x86, 0x0a, 0x3a, 0x1d, 0x58, 0x23, 0x7d, 0x88 );
#endif
#ifndef MFSampleExtension_VideoEncodeBitsUsedMap
// MFSampleExtension_VideoEncodeBitsUsedMap {6894263D-E6E2-4BCC-849D-8570365F5114}
// Type: IMFMediaBuffer
// The bits used map of an encoded video frame.
DEFINE_GUID( MFSampleExtension_VideoEncodeBitsUsedMap, 0x6894263d, 0xe6e2, 0x4bcc, 0x84, 0x9d, 0x85, 0x70, 0x36, 0x5f, 0x51, 0x14 );
#endif
#if MFT_CODEC_H264ENC
#define HMFT_GUID "8994db7c-288a-4c62-a136-a3c3c2a208a8"
#elif MFT_CODEC_H265ENC

View file

@ -262,3 +262,59 @@ MFCopySample( IMFSample *dest, IMFSample *src, IMFMediaType *pmt )
done:
return hr;
}
//
// MFAttachPipeResourceAsSampleExtension
//
// Description:
// Converts a Gallium pipe_resource into a D3D12 resource and wraps it as an IMFMediaBuffer,
// then attaches it as a sample extension on an IMFSample using the specified GUID.
//
// Parameters:
// pPipeContext - Pointer to the Gallium pipe context.
// pPipeRes - Pointer to the pipe_resource to be wrapped.
// guidExtension - The GUID of the Media Foundation sample extension to attach the buffer as.
// pSample - The output IMFSample to attach the media buffer to.
//
// Returns:
// S_OK if the operation was successful.
// E_INVALIDARG if any required pointer is null.
// E_FAIL if resource_get_handle fails.
// E_POINTER if the returned COM object is null.
// Other HRESULT failure codes from MFCreateDXGISurfaceBuffer or SetUnknown.
//
HRESULT
MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
struct pipe_resource *pPipeRes,
REFGUID guidExtension,
IMFSample *pSample )
{
if (!pPipeContext || !pPipeRes || !pSample)
{
return E_INVALIDARG;
}
struct winsys_handle whandle = {};
whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
if( !pPipeContext->screen->resource_get_handle( pPipeContext->screen, pPipeContext, pPipeRes, &whandle, 0u ) )
{
return E_FAIL;
}
if( !whandle.com_obj )
{
return E_POINTER;
}
ID3D12Resource *pD3D12Res = static_cast<ID3D12Resource *>( whandle.com_obj );
ComPtr<IMFMediaBuffer> spMediaBuffer;
HRESULT hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, 0, FALSE, &spMediaBuffer );
if( FAILED( hr ) )
{
return hr;
}
return pSample->SetUnknown( guidExtension, spMediaBuffer.Get() );
}

View file

@ -44,3 +44,11 @@ MFTypeToImageSize( IMFMediaType *pType, UINT32 *pcbSize );
// Copy a sample from src to dst for the given media type (copies buffer contents)
HRESULT
MFCopySample( IMFSample *dest, IMFSample *src, IMFMediaType *pmt );
// Converts a Gallium pipe_resource into a D3D12 resource and wraps it as an IMFMediaBuffer,
// then attaches it as a sample extension on an IMFSample using the specified GUID.
HRESULT
MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
struct pipe_resource *pPipeRes,
REFGUID guidExtension,
IMFSample *pSample );

View file

@ -25,6 +25,7 @@
#include "hmft_entrypoints.h"
#include "mfpipeinterop.h"
#include "wpptrace.h"
#include "mfbufferhelp.h"
#include "mftransform.tmh"
@ -1340,6 +1341,48 @@ CDX12EncHMFT::xThreadProc( void *pCtx )
pDX12EncodeContext->longTermReferenceFrameInfo );
}
// Conditionally attach frame PSNR
if( pThis->m_bVideoEnableFramePsnrYuv && pDX12EncodeContext->pPipeResourcePSNRStats != nullptr )
{
HRESULT hr = MFAttachPipeResourceAsSampleExtension( pThis->m_pPipeContext,
pDX12EncodeContext->pPipeResourcePSNRStats,
MFSampleExtension_FramePsnrYuv,
spOutputSample.Get() );
if( FAILED( hr ) )
{
MFE_INFO( "[dx12 hmft 0x%p] PSNR: MFAttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr );
}
}
// Conditionally attach output QP map
if( pThis->m_uiVideoOutputQPMapBlockSize && pDX12EncodeContext->pPipeResourceQPMapStats != nullptr )
{
HRESULT hr = MFAttachPipeResourceAsSampleExtension( pThis->m_pPipeContext,
pDX12EncodeContext->pPipeResourceQPMapStats,
MFSampleExtension_VideoEncodeQPMap,
spOutputSample.Get() );
if( FAILED( hr ) )
{
MFE_INFO( "[dx12 hmft 0x%p] QPMap: MFAttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr );
}
}
// Conditionally attach output bits used map
if( pThis->m_uiVideoOutputBitsUsedMapBlockSize && pDX12EncodeContext->pPipeResourceRCBitAllocMapStats != nullptr )
{
HRESULT hr = MFAttachPipeResourceAsSampleExtension( pThis->m_pPipeContext,
pDX12EncodeContext->pPipeResourceRCBitAllocMapStats,
MFSampleExtension_VideoEncodeBitsUsedMap,
spOutputSample.Get() );
if( FAILED( hr ) )
{
MFE_INFO( "[dx12 hmft 0x%p] BitsUsed: MFAttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr );
}
}
// If sliced fences supported, we asynchronously copied every slice as it was ready (see above)
// into spMemoryBuffer. Otherwise, let's copy all the sliced together here after full frame completion
#if (USE_D3D12_PREVIEW_HEADERS && (D3D12_PREVIEW_SDK_VERSION >= 717))