Changes since the v4:
- Avoid having two mf_init function declared (missing #if !HAVE_UWP)
- Better commit message about linking with UWP
Changes since the v3:
- Library handle and function pointer are no longer in MFContext.
- If UWP is enabled, avcodec will be linked directly against MFPlat.DLL.
- MediaFoundation functions are now called like MFTEnumEx, like Martin
Storsjö suggested in his review of the v3.
I forgot to mention it on earlier versions, this patch addresses
https://trac.ffmpeg.org/ticket/9788.
// Trystan
From 9115df2346e23d2e3eff4fb78cbd80419267eb7d Mon Sep 17 00:00:00 2001
From: Trystan Mata <trystan.m...@tytanium.xyz>
Date: Sat, 21 May 2022 16:26:56 +0200
Subject: [PATCH] avcodec/mfenc: Dynamically load MediaFoundation library
Allows non-UWP builds of FFmpeg with MediaFoundation to work on
N editions of Windows which are without MediaFoundation by default.
On UWP target, avcodec is link directly against MediaFoundation since
LoadLibrary is not available.
This commit adresses https://trac.ffmpeg.org/ticket/9788
Signed-off-by: Trystan Mata <trystan.m...@tytanium.xyz>
---
configure | 5 +-
libavcodec/mf_utils.c | 106 ++++++++++++++++++++++++++++++++++--------
libavcodec/mf_utils.h | 19 ++++++--
libavcodec/mfenc.c | 25 +++++++++-
4 files changed, 131 insertions(+), 24 deletions(-)
diff --git a/configure b/configure
index f115b21064..432a0d163d 100755
--- a/configure
+++ b/configure
@@ -3130,7 +3130,6 @@ wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel"
# hardware-accelerated codecs
mediafoundation_deps="mftransform_h MFCreateAlignedMemoryBuffer"
-mediafoundation_extralibs="-lmfplat -lmfuuid -lole32 -lstrmiids"
omx_deps="libdl pthreads"
omx_rpi_select="omx"
qsv_deps="libmfx"
@@ -6876,6 +6875,10 @@ test_cpp <<EOF && enable uwp && d3d11va_extralibs="-ldxgi -ld3d11"
#endif
EOF
+# mediafoundation requires linking directly to mfplat and mfuuid if building
+# for uwp target
+enabled uwp && mediafoundation_extralibs="-lmfplat -lmfuuid -lole32 -lstrmiids" || mediafoundation_extralibs="-lole32 -lstrmiids"
+
enabled libdrm &&
check_pkg_config libdrm_getfb2 libdrm "xf86drmMode.h" drmModeGetFB2
diff --git a/libavcodec/mf_utils.c b/libavcodec/mf_utils.c
index eeabd0ce0b..b8756cccea 100644
--- a/libavcodec/mf_utils.c
+++ b/libavcodec/mf_utils.c
@@ -24,6 +24,7 @@
#include "mf_utils.h"
#include "libavutil/pixdesc.h"
+#include "compat/w32dlfcn.h"
HRESULT ff_MFGetAttributeSize(IMFAttributes *pattr, REFGUID guid,
UINT32 *pw, UINT32 *ph)
@@ -47,9 +48,83 @@ HRESULT ff_MFSetAttributeSize(IMFAttributes *pattr, REFGUID guid,
#define ff_MFSetAttributeRatio ff_MFSetAttributeSize
#define ff_MFGetAttributeRatio ff_MFGetAttributeSize
-// MFTEnumEx was missing from mingw-w64's mfplat import library until
-// mingw-w64 v6.0.0, thus wrap it and load it using GetProcAddress.
-// It's also missing in Windows Vista's mfplat.dll.
+// Windows N editions does not provide MediaFoundation by default.
+// So to avoid DLL loading error, MediaFoundation is dynamically loaded except
+// on UWP build since LoadLibrary is not available on it.
+#if !HAVE_UWP
+static HMODULE mf_library = NULL;
+
+int ff_mf_load_library(void *log)
+{
+ mf_library = win32_dlopen("mfplat.dll");
+
+ if (!mf_library) {
+ av_log(log, AV_LOG_ERROR, "DLL mfplat.dll failed to open\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+void ff_mf_unload_library(void)
+{
+ FreeLibrary(mf_library);
+ mf_library = NULL;
+}
+
+#define GET_MF_FUNCTION(ptr, func_name) \
+ ptr = (void *)GetProcAddress(mf_library, #func_name ""); \
+ if (!ptr) \
+ return E_FAIL;
+#else
+// In UWP (which lacks LoadLibrary), just link directly against
+// the functions - this requires building with new/complete enough
+// import libraries.
+#define GET_MF_FUNCTION(ptr, func_name) \
+ ptr = func_name; \
+ if (!ptr) \
+ return E_FAIL;
+#endif
+
+HRESULT ff_MFStartup(ULONG Version, DWORD dwFlags)
+{
+ HRESULT (WINAPI *MFStartup_ptr)(ULONG Version, DWORD dwFlags) = NULL;
+ GET_MF_FUNCTION(MFStartup_ptr, MFStartup);
+ return MFStartup_ptr(Version, dwFlags);
+}
+
+HRESULT ff_MFShutdown(void)
+{
+ HRESULT (WINAPI *MFShutdown_ptr)(void) = NULL;
+ GET_MF_FUNCTION(MFShutdown_ptr, MFShutdown);
+ return MFShutdown_ptr();
+}
+
+HRESULT ff_MFCreateSample(IMFSample **ppIMFSample)
+{
+ HRESULT (WINAPI *MFCreateSample_ptr)(IMFSample **ppIMFSample) = NULL;
+ GET_MF_FUNCTION(MFCreateSample_ptr, MFCreateSample);
+ return MFCreateSample_ptr(ppIMFSample);
+}
+
+HRESULT ff_MFCreateAlignedMemoryBuffer(DWORD cbMaxLength, DWORD cbAligment,
+ IMFMediaBuffer **ppBuffer)
+{
+ HRESULT (WINAPI *MFCreateAlignedMemoryBuffer_ptr)(DWORD cbMaxLength,
+ DWORD cbAligment,
+ IMFMediaBuffer **ppBuffer) = NULL;
+ GET_MF_FUNCTION(MFCreateAlignedMemoryBuffer_ptr, MFCreateAlignedMemoryBuffer);
+ return MFCreateAlignedMemoryBuffer_ptr(cbMaxLength, cbAligment, ppBuffer);
+}
+
+HRESULT ff_MFCreateMediaType(IMFMediaType **ppMFType)
+{
+ HRESULT (WINAPI *MFCreateMediaType_ptr)(IMFMediaType **ppMFType) = NULL;
+ GET_MF_FUNCTION(MFCreateMediaType_ptr, MFCreateMediaType);
+ return MFCreateMediaType_ptr(ppMFType);
+}
+
+// MFTEnumEx is missing in Windows Vista's mfplat.dll.
HRESULT ff_MFTEnumEx(GUID guidCategory, UINT32 Flags,
const MFT_REGISTER_TYPE_INFO *pInputType,
const MFT_REGISTER_TYPE_INFO *pOutputType,
@@ -60,18 +135,7 @@ HRESULT ff_MFTEnumEx(GUID guidCategory, UINT32 Flags,
const MFT_REGISTER_TYPE_INFO *pOutputType,
IMFActivate ***pppMFTActivate,
UINT32 *pnumMFTActivate) = NULL;
-#if !HAVE_UWP
- HANDLE lib = GetModuleHandleW(L"mfplat.dll");
- if (lib)
- MFTEnumEx_ptr = (void *)GetProcAddress(lib, "MFTEnumEx");
-#else
- // In UWP (which lacks GetModuleHandle), just link directly against
- // the functions - this requires building with new/complete enough
- // import libraries.
- MFTEnumEx_ptr = MFTEnumEx;
-#endif
- if (!MFTEnumEx_ptr)
- return E_FAIL;
+ GET_MF_FUNCTION(MFTEnumEx_ptr, MFTEnumEx);
return MFTEnumEx_ptr(guidCategory,
Flags,
pInputType,
@@ -112,13 +176,13 @@ IMFSample *ff_create_memory_sample(void *fill_data, size_t size, size_t align)
IMFSample *sample;
IMFMediaBuffer *buffer;
- hr = MFCreateSample(&sample);
+ hr = ff_MFCreateSample(&sample);
if (FAILED(hr))
return NULL;
align = FFMAX(align, 16); // 16 is "recommended", even if not required
- hr = MFCreateAlignedMemoryBuffer(size, align - 1, &buffer);
+ hr = ff_MFCreateAlignedMemoryBuffer(size, align - 1, &buffer);
if (FAILED(hr))
return NULL;
@@ -561,7 +625,7 @@ static int init_com_mf(void *log)
return AVERROR(ENOSYS);
}
- hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
+ hr = ff_MFStartup(MF_VERSION, MFSTARTUP_FULL);
if (FAILED(hr)) {
av_log(log, AV_LOG_ERROR, "could not initialize MediaFoundation\n");
CoUninitialize();
@@ -573,7 +637,7 @@ static int init_com_mf(void *log)
static void uninit_com_mf(void)
{
- MFShutdown();
+ ff_MFShutdown();
CoUninitialize();
}
@@ -673,6 +737,10 @@ error_uninit_mf:
void ff_free_mf(IMFTransform **mft)
{
+#if !HAVE_UWP
+ if (!mf_library)
+ return;
+#endif
if (*mft)
IMFTransform_Release(*mft);
*mft = NULL;
diff --git a/libavcodec/mf_utils.h b/libavcodec/mf_utils.h
index d514723c3b..6384bc2133 100644
--- a/libavcodec/mf_utils.h
+++ b/libavcodec/mf_utils.h
@@ -50,9 +50,22 @@ HRESULT ff_MFSetAttributeSize(IMFAttributes *pattr, REFGUID guid,
#define ff_MFSetAttributeRatio ff_MFSetAttributeSize
#define ff_MFGetAttributeRatio ff_MFGetAttributeSize
-// MFTEnumEx was missing from mingw-w64's mfplat import library until
-// mingw-w64 v6.0.0, thus wrap it and load it using GetProcAddress.
-// It's also missing in Windows Vista's mfplat.dll.
+// Windows N editions does not provide MediaFoundation by default.
+// So to avoid DLL loading error, MediaFoundation is dynamically loaded except
+// on UWP build since LoadLibrary is not available on it.
+#if !HAVE_UWP
+int ff_mf_load_library(void *log);
+void ff_mf_unload_library(void);
+#endif
+
+HRESULT ff_MFCreateSample(IMFSample **ppIMFSample);
+HRESULT ff_MFCreateAlignedMemoryBuffer(DWORD cbMaxLength, DWORD cbAligment,
+ IMFMediaBuffer **ppBuffer);
+HRESULT ff_MFStartup(ULONG Version, DWORD dwFlags);
+HRESULT ff_MFShutdown(void);
+HRESULT ff_MFCreateMediaType(IMFMediaType **ppMFType);
+
+// MFTEnumEx is missing in Windows Vista's mfplat.dll.
HRESULT ff_MFTEnumEx(GUID guidCategory, UINT32 Flags,
const MFT_REGISTER_TYPE_INFO *pInputType,
const MFT_REGISTER_TYPE_INFO *pOutputType,
diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c
index 280941cf2e..60815455b7 100644
--- a/libavcodec/mfenc.c
+++ b/libavcodec/mfenc.c
@@ -777,7 +777,7 @@ static int mf_choose_output_type(AVCodecContext *avctx)
if (out_type) {
av_log(avctx, AV_LOG_VERBOSE, "picking output type %d.\n", out_type_index);
} else {
- hr = MFCreateMediaType(&out_type);
+ hr = ff_MFCreateMediaType(&out_type);
if (FAILED(hr)) {
ret = AVERROR(ENOMEM);
goto done;
@@ -1034,7 +1034,11 @@ static int mf_create(void *log, IMFTransform **mft, const AVCodec *codec, int us
return 0;
}
+#if !HAVE_UWP
+static int mf_init_encoder(AVCodecContext *avctx)
+#else
static int mf_init(AVCodecContext *avctx)
+#endif
{
MFContext *c = avctx->priv_data;
HRESULT hr;
@@ -1134,6 +1138,10 @@ static int mf_close(AVCodecContext *avctx)
ff_free_mf(&c->mft);
+#if !HAVE_UWP
+ ff_mf_unload_library();
+#endif
+
av_frame_free(&c->frame);
av_freep(&avctx->extradata);
@@ -1142,6 +1150,21 @@ static int mf_close(AVCodecContext *avctx)
return 0;
}
+#if !HAVE_UWP
+static int mf_init(AVCodecContext *avctx)
+{
+ int ret;
+
+ if ((ret = ff_mf_load_library(avctx)) == 0) {
+ if ((ret = mf_init_encoder(avctx)) == 0) {
+ return 0;
+ }
+ }
+ mf_close(avctx);
+ return ret;
+}
+#endif
+
#define OFFSET(x) offsetof(MFContext, x)
#define MF_ENCODER(MEDIATYPE, NAME, ID, OPTS, EXTRA) \
--
2.36.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".