From: "Martin Storsjö" <martin@martin.st> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Subject: Re: [FFmpeg-devel] [PATCH v5] avcodec/mfenc: Dynamically load MFPlat.DLL Date: Tue, 24 May 2022 11:46:15 +0300 (EEST) Message-ID: <b812eec0-be15-c73-6c6c-f823f1a1f1ff@martin.st> (raw) In-Reply-To: <a97a6596-0921-f4a1-edc4-b8384dbc79f2@tytanium.xyz> On Sat, 21 May 2022, Trystan Mata wrote: > 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. 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; +} You shouldn't use win32_dlopen directly (there's no preexisting code that does that). If you want to use the helpers from w32dlfcn.h, call dlopen and dlclose, which then redirect to those functions. But here I don't see any need to use that wrapper when you probably could just call LoadLibrary directly. (There's no need for using wchar APIs and long path handling and all that, when it's just given the hardcoded path "mfplat.dll".) Secondly, this won't probably work as intended if you have two mfenc instances running at the same time - you'd load the library twice but only unload it once. To work around that, you can either add some sort of reference counting around the library, or keep the library reference in a per-encoder struct. In this case I think I would prefer to keep it in a struct. + +#define GET_MF_FUNCTION(ptr, func_name) \ + ptr = (void *)GetProcAddress(mf_library, #func_name ""); \ Why the extra "" here? + 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); For functions like this, fetching the function pointer every time it's called probably is fine (as it's only called once on startup), but ... + 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); This is called once per frame at least, right? For such cases I think it would be much better if we'd keep the function pointer in a struct (which then would be owned/contained in MFContext) so we don't need to look it up every time. @@ -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 + This feels a bit messy with the same function defined differently between the desktop/UWP cases. Wouldn't it be more straightforward to just keep all the code for the desktop case, and add ifdefs within e.g. ff_mf_load_library and ff_mf_unload_library, so that those functions are simple no-ops if building for UWP? // Martin _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2022-05-24 8:46 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-05-21 19:31 Trystan Mata 2022-05-24 8:46 ` Martin Storsjö [this message] 2022-05-25 6:44 ` Trystan Mata 2022-05-25 6:48 ` Trystan Mata
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=b812eec0-be15-c73-6c6c-f823f1a1f1ff@martin.st \ --to=martin@martin.st \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git