diff --git a/src/gallium/frontends/mediafoundation/hmft_entrypoints.h b/src/gallium/frontends/mediafoundation/hmft_entrypoints.h index c360765998f..490f1d721bf 100644 --- a/src/gallium/frontends/mediafoundation/hmft_entrypoints.h +++ b/src/gallium/frontends/mediafoundation/hmft_entrypoints.h @@ -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 diff --git a/src/gallium/frontends/mediafoundation/mfbufferhelp.cpp b/src/gallium/frontends/mediafoundation/mfbufferhelp.cpp index bec1dd2c17c..a2cdbf946ff 100644 --- a/src/gallium/frontends/mediafoundation/mfbufferhelp.cpp +++ b/src/gallium/frontends/mediafoundation/mfbufferhelp.cpp @@ -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( whandle.com_obj ); + ComPtr spMediaBuffer; + HRESULT hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, 0, FALSE, &spMediaBuffer ); + + if( FAILED( hr ) ) + { + return hr; + } + + return pSample->SetUnknown( guidExtension, spMediaBuffer.Get() ); +} diff --git a/src/gallium/frontends/mediafoundation/mfbufferhelp.h b/src/gallium/frontends/mediafoundation/mfbufferhelp.h index 6578c617121..fc308c9747c 100644 --- a/src/gallium/frontends/mediafoundation/mfbufferhelp.h +++ b/src/gallium/frontends/mediafoundation/mfbufferhelp.h @@ -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 ); diff --git a/src/gallium/frontends/mediafoundation/mftransform.cpp b/src/gallium/frontends/mediafoundation/mftransform.cpp index 067eef3cd16..4d3b15bbb8b 100644 --- a/src/gallium/frontends/mediafoundation/mftransform.cpp +++ b/src/gallium/frontends/mediafoundation/mftransform.cpp @@ -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))