diff mbox series

[FFmpeg-devel,v3] avcodec/mfenc: Dynamically load MFPlat.DLL

Message ID c1020a63-6b9a-5182-fa42-65c17772078c@tytanium.xyz
State New
Headers show
Series [FFmpeg-devel,v3] avcodec/mfenc: Dynamically load MFPlat.DLL | expand

Checks

Context Check Description
yinshiyou/configure_loongarch64 warning Failed to apply patch
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Trystan Mata May 20, 2022, 7:44 p.m. UTC

Comments

Martin Storsjö May 20, 2022, 8:05 p.m. UTC | #1
On Fri, 20 May 2022, Trystan Mata wrote:

> From 2bdef1bdb93efa40b7d3fe21270f9f23465bee90 Mon Sep 17 00:00:00 2001
> From: Trystan Mata <trystan.mata@tytanium.xyz>
> Date: Fri, 20 May 2022 14:26:49 +0200
> Subject: [PATCH] avcodec/mfenc: Dynamically load MFPlat.DLL
> 
> Allow builds of FFmpeg with MediaFoundation to work under N editions of
> Windows which are without MediaFoundation by default.
> 
> Signed-off-by: Trystan Mata <trystan.mata@tytanium.xyz>
> ---
>  configure             |  4 +-
>  libavcodec/mf_utils.c | 26 +++++++------
>  libavcodec/mf_utils.h | 16 ++++++--
>  libavcodec/mfenc.c    | 91 ++++++++++++++++++++++++++++++++++++-------
>  4 files changed, 107 insertions(+), 30 deletions(-)

This patch on its own breaks builds for UWP targets (where LoadLibrary 
isn't available). Or more precisely, previously mfenc was enabled, now it 
no longer is available.

For such targets, one can unconditionally assume that the functions are 
available and can link directly against them. See ff_MFTEnumEx in 
mf_utils.c how that's done so far. Doing the same instead of LoadLibrary 
probably shouldn't be an issue for you, but I think we'd need to drop the 
dependency on LoadLibrary in configure. (I think that's fine, we don't 
really lose anything by doing that.)

Btw, when sending updates to an earlier posted patch, it'd be nice if 
you'd mention somewhere what changed compared to the previous revision of 
the patch.

// Martin
Trystan Mata May 20, 2022, 8:48 p.m. UTC | #2
Firstly, I'm sorry about those patches without changes mentioned.

As changes, there was just a whitespace that I removed.

I'm not used at all to sending matches through mailing list. And Patchwork 
failed to apply my patches, so I resend it trying to see if the way I sent the 
patch was wrong.

If I understood correctly, I need to change my patch to link FFmpeg against 
MFPlat.DLL on UWP targets.

And for the symbols, I try to "load" them à la ff_MFTEnumEx. And so dynamically 
load MFPlat.DLL on non-UWP targets.

Thank you for your review and you time.

// Trystan
diff mbox series

Patch

From 2bdef1bdb93efa40b7d3fe21270f9f23465bee90 Mon Sep 17 00:00:00 2001
From: Trystan Mata <trystan.mata@tytanium.xyz>
Date: Fri, 20 May 2022 14:26:49 +0200
Subject: [PATCH] avcodec/mfenc: Dynamically load MFPlat.DLL

Allow builds of FFmpeg with MediaFoundation to work under N editions of
Windows which are without MediaFoundation by default.

Signed-off-by: Trystan Mata <trystan.mata@tytanium.xyz>
---
 configure             |  4 +-
 libavcodec/mf_utils.c | 26 +++++++------
 libavcodec/mf_utils.h | 16 ++++++--
 libavcodec/mfenc.c    | 91 ++++++++++++++++++++++++++++++++++++-------
 4 files changed, 107 insertions(+), 30 deletions(-)

diff --git a/configure b/configure
index f115b21064..f16fbb320a 100755
--- a/configure
+++ b/configure
@@ -3129,8 +3129,8 @@  wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
 wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel"
 
 # hardware-accelerated codecs
-mediafoundation_deps="mftransform_h MFCreateAlignedMemoryBuffer"
-mediafoundation_extralibs="-lmfplat -lmfuuid -lole32 -lstrmiids"
+mediafoundation_deps="LoadLibrary mftransform_h MFCreateAlignedMemoryBuffer"
+mediafoundation_extralibs="-lole32 -lstrmiids"
 omx_deps="libdl pthreads"
 omx_rpi_select="omx"
 qsv_deps="libmfx"
diff --git a/libavcodec/mf_utils.c b/libavcodec/mf_utils.c
index eeabd0ce0b..9a83f71692 100644
--- a/libavcodec/mf_utils.c
+++ b/libavcodec/mf_utils.c
@@ -106,19 +106,20 @@  char *ff_hr_str_buf(char *buf, size_t size, HRESULT hr)
 // If fill_data!=NULL, initialize the buffer and set the length. (This is a
 // subtle but important difference: some decoders want CurrentLength==0 on
 // provided output buffers.)
-IMFSample *ff_create_memory_sample(void *fill_data, size_t size, size_t align)
+IMFSample *ff_create_memory_sample(const MFSymbols *symbols, void *fill_data,
+                                   size_t size, size_t align)
 {
     HRESULT hr;
     IMFSample *sample;
     IMFMediaBuffer *buffer;
 
-    hr = MFCreateSample(&sample);
+    hr = symbols->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 = symbols->MFCreateAlignedMemoryBuffer(size, align - 1, &buffer);
     if (FAILED(hr))
         return NULL;
 
@@ -548,7 +549,7 @@  const CLSID *ff_codec_to_mf_subtype(enum AVCodecID codec)
     }
 }
 
-static int init_com_mf(void *log)
+static int init_com_mf(const MFSymbols *symbols, void *log)
 {
     HRESULT hr;
 
@@ -561,7 +562,7 @@  static int init_com_mf(void *log)
         return AVERROR(ENOSYS);
     }
 
-    hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
+    hr = symbols->MFStartup(MF_VERSION, MFSTARTUP_FULL);
     if (FAILED(hr)) {
         av_log(log, AV_LOG_ERROR, "could not initialize MediaFoundation\n");
         CoUninitialize();
@@ -571,15 +572,16 @@  static int init_com_mf(void *log)
     return 0;
 }
 
-static void uninit_com_mf(void)
+static void uninit_com_mf(const MFSymbols *symbols)
 {
-    MFShutdown();
+    symbols->MFShutdown();
     CoUninitialize();
 }
 
 // Find and create a IMFTransform with the given input/output types. When done,
 // you should use ff_free_mf() to destroy it, which will also uninit COM.
-int ff_instantiate_mf(void *log,
+int ff_instantiate_mf(const MFSymbols *symbols,
+                      void *log,
                       GUID category,
                       MFT_REGISTER_TYPE_INFO *in_type,
                       MFT_REGISTER_TYPE_INFO *out_type,
@@ -594,7 +596,7 @@  int ff_instantiate_mf(void *log,
     IMFActivate *winner = 0;
     UINT32 flags;
 
-    ret = init_com_mf(log);
+    ret = init_com_mf(symbols, log);
     if (ret < 0)
         return ret;
 
@@ -667,14 +669,14 @@  int ff_instantiate_mf(void *log,
     return 0;
 
 error_uninit_mf:
-    uninit_com_mf();
+    uninit_com_mf(symbols);
     return AVERROR(ENOSYS);
 }
 
-void ff_free_mf(IMFTransform **mft)
+void ff_free_mf(const MFSymbols *symbols, IMFTransform **mft)
 {
     if (*mft)
         IMFTransform_Release(*mft);
     *mft = NULL;
-    uninit_com_mf();
+    uninit_com_mf(symbols);
 }
diff --git a/libavcodec/mf_utils.h b/libavcodec/mf_utils.h
index d514723c3b..1b1041bb29 100644
--- a/libavcodec/mf_utils.h
+++ b/libavcodec/mf_utils.h
@@ -41,6 +41,15 @@ 
 
 #include "avcodec.h"
 
+typedef struct MFSymbols {
+    HRESULT (*MFCreateSample) (IMFSample **ppIMFSample);
+    HRESULT (*MFCreateAlignedMemoryBuffer) (DWORD cbMaxLength, DWORD cbAligment,
+                                            IMFMediaBuffer **ppBuffer);
+    HRESULT (*MFStartup) (ULONG Version, DWORD dwFlags);
+    HRESULT (*MFShutdown) (void);
+    HRESULT (*MFCreateMediaType) (IMFMediaType **ppMFType);
+} MFSymbols;
+
 // These functions do exist in mfapi.h, but are only available within
 // __cplusplus ifdefs.
 HRESULT ff_MFGetAttributeSize(IMFAttributes *pattr, REFGUID guid,
@@ -150,7 +159,8 @@  char *ff_hr_str_buf(char *buf, size_t size, HRESULT hr);
 #define FF_VAL_VT_UI4(v) FF_VARIANT_VALUE(VT_UI4, .ulVal = (v))
 #define FF_VAL_VT_BOOL(v) FF_VARIANT_VALUE(VT_BOOL, .boolVal = (v))
 
-IMFSample *ff_create_memory_sample(void *fill_data, size_t size, size_t align);
+IMFSample *ff_create_memory_sample(const MFSymbols *symbols, void *fill_data,
+                                   size_t size, size_t align);
 enum AVSampleFormat ff_media_type_to_sample_fmt(IMFAttributes *type);
 enum AVPixelFormat ff_media_type_to_pix_fmt(IMFAttributes *type);
 const GUID *ff_pix_fmt_to_guid(enum AVPixelFormat pix_fmt);
@@ -160,10 +170,10 @@  char *ff_guid_str_buf(char *buf, size_t buf_size, const GUID *guid);
 void ff_attributes_dump(void *log, IMFAttributes *attrs);
 void ff_media_type_dump(void *log, IMFMediaType *type);
 const CLSID *ff_codec_to_mf_subtype(enum AVCodecID codec);
-int ff_instantiate_mf(void *log, GUID category,
+int ff_instantiate_mf(const MFSymbols *symbols, void *log, GUID category,
                       MFT_REGISTER_TYPE_INFO *in_type,
                       MFT_REGISTER_TYPE_INFO *out_type,
                       int use_hw, IMFTransform **res);
-void ff_free_mf(IMFTransform **mft);
+void ff_free_mf(const MFSymbols *symbols, IMFTransform **mft);
 
 #endif
diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c
index 280941cf2e..0444d5af38 100644
--- a/libavcodec/mfenc.c
+++ b/libavcodec/mfenc.c
@@ -29,9 +29,12 @@ 
 #include "libavutil/time.h"
 #include "codec_internal.h"
 #include "internal.h"
+#include "compat/w32dlfcn.h"
 
 typedef struct MFContext {
     AVClass *av_class;
+    void *library;
+    MFSymbols symbols;
     AVFrame *frame;
     int is_video, is_audio;
     GUID main_subtype;
@@ -292,7 +295,7 @@  static IMFSample *mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *f
     bps = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels;
     len = frame->nb_samples * bps;
 
-    sample = ff_create_memory_sample(frame->data[0], len, c->in_info.cbAlignment);
+    sample = ff_create_memory_sample(&c->symbols, frame->data[0], len, c->in_info.cbAlignment);
     if (sample)
         IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->nb_samples));
     return sample;
@@ -312,7 +315,7 @@  static IMFSample *mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *f
     if (size < 0)
         return NULL;
 
-    sample = ff_create_memory_sample(NULL, size, c->in_info.cbAlignment);
+    sample = ff_create_memory_sample(&c->symbols, NULL, size, c->in_info.cbAlignment);
     if (!sample)
         return NULL;
 
@@ -422,7 +425,7 @@  static int mf_receive_sample(AVCodecContext *avctx, IMFSample **out_sample)
         }
 
         if (!c->out_stream_provides_samples) {
-            sample = ff_create_memory_sample(NULL, c->out_info.cbSize, c->out_info.cbAlignment);
+            sample = ff_create_memory_sample(&c->symbols, NULL, c->out_info.cbSize, c->out_info.cbAlignment);
             if (!sample)
                 return AVERROR(ENOMEM);
         }
@@ -777,7 +780,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 = c->symbols.MFCreateMediaType(&out_type);
         if (FAILED(hr)) {
             ret = AVERROR(ENOMEM);
             goto done;
@@ -1005,7 +1008,7 @@  err:
     return res;
 }
 
-static int mf_create(void *log, IMFTransform **mft, const AVCodec *codec, int use_hw)
+static int mf_create(const MFSymbols *symbols, void *log, IMFTransform **mft, const AVCodec *codec, int use_hw)
 {
     int is_audio = codec->type == AVMEDIA_TYPE_AUDIO;
     const CLSID *subtype = ff_codec_to_mf_subtype(codec->id);
@@ -1028,13 +1031,57 @@  static int mf_create(void *log, IMFTransform **mft, const AVCodec *codec, int us
         category = MFT_CATEGORY_VIDEO_ENCODER;
     }
 
-    if ((ret = ff_instantiate_mf(log, category, NULL, &reg, use_hw, mft)) < 0)
+    if ((ret = ff_instantiate_mf(symbols, log, category, NULL, &reg, use_hw, mft)) < 0)
         return ret;
 
     return 0;
 }
 
-static int mf_init(AVCodecContext *avctx)
+static int mf_load_library(AVCodecContext *avctx)
+{
+    MFContext *c = avctx->priv_data;
+
+    c->library = dlopen("MFPlat.DLL", RTLD_NOW | RTLD_LOCAL);
+
+    if (c->library == NULL) {
+        av_log(c, AV_LOG_ERROR, "DLL MFPlat.DLL failed to open\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    c->symbols.MFCreateSample = dlsym(c->library, "MFCreateSample");
+    if (c->symbols.MFCreateSample == NULL) {
+        av_log(c, AV_LOG_ERROR, "DLL MFPlat.DLL failed to find function MFCreateSample\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    c->symbols.MFCreateAlignedMemoryBuffer = dlsym(c->library, "MFCreateAlignedMemoryBuffer");
+    if (c->symbols.MFCreateAlignedMemoryBuffer == NULL) {
+        av_log(c, AV_LOG_ERROR, "DLL MFPlat.DLL failed to find function MFCreateAlignedMemoryBuffer\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    c->symbols.MFStartup = dlsym(c->library, "MFStartup");
+    if (c->symbols.MFStartup == NULL) {
+        av_log(c, AV_LOG_ERROR, "DLL MFPlat.DLL failed to find function MFStartup\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    c->symbols.MFShutdown = dlsym(c->library, "MFShutdown");
+    if (c->symbols.MFShutdown == NULL) {
+        av_log(c, AV_LOG_ERROR, "DLL MFPlat.DLL failed to find function MFShutdown\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    c->symbols.MFCreateMediaType = dlsym(c->library, "MFCreateMediaType");
+    if (c->symbols.MFCreateMediaType == NULL) {
+        av_log(c, AV_LOG_ERROR, "DLL MFPlat.DLL failed to find function MFCreateMediaType\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+};
+
+static int mf_init_encoder(AVCodecContext *avctx)
 {
     MFContext *c = avctx->priv_data;
     HRESULT hr;
@@ -1058,7 +1105,7 @@  static int mf_init(AVCodecContext *avctx)
 
     c->main_subtype = *subtype;
 
-    if ((ret = mf_create(avctx, &c->mft, avctx->codec, use_hw)) < 0)
+    if ((ret = mf_create(&c->symbols, avctx, &c->mft, avctx->codec, use_hw)) < 0)
         return ret;
 
     if ((ret = mf_unlock_async(avctx)) < 0)
@@ -1126,13 +1173,18 @@  static int mf_close(AVCodecContext *avctx)
 {
     MFContext *c = avctx->priv_data;
 
-    if (c->codec_api)
-        ICodecAPI_Release(c->codec_api);
+    if (c->library) {
+        if (c->codec_api)
+            ICodecAPI_Release(c->codec_api);
 
-    if (c->async_events)
-        IMFMediaEventGenerator_Release(c->async_events);
+        if (c->async_events)
+            IMFMediaEventGenerator_Release(c->async_events);
 
-    ff_free_mf(&c->mft);
+        ff_free_mf(&c->symbols, &c->mft);
+
+        dlclose(c->library);
+        c->library = NULL;
+    }
 
     av_frame_free(&c->frame);
 
@@ -1142,6 +1194,19 @@  static int mf_close(AVCodecContext *avctx)
     return 0;
 }
 
+static int mf_init(AVCodecContext *avctx)
+{
+    int ret;
+
+    if ((ret = mf_load_library(avctx)) == 0) {
+           if ((ret = mf_init_encoder(avctx)) == 0) {
+                return 0;
+        }
+    }
+    mf_close(avctx);
+    return ret;
+}
+
 #define OFFSET(x) offsetof(MFContext, x)
 
 #define MF_ENCODER(MEDIATYPE, NAME, ID, OPTS, EXTRA) \
-- 
2.33.1.windows.1