aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/mfenc.c
diff options
context:
space:
mode:
authorTrystan Mata <trystan.mata@tytanium.xyz>2022-05-25 12:54:01 +0200
committerMartin Storsjö <martin@martin.st>2022-05-25 23:45:42 +0300
commit1cb601ad10313981209a5918fc36a968068fc0ec (patch)
tree3e72921c9fc9930807cb5f16e44960715f9aa948 /libavcodec/mfenc.c
parent478e1a98a289bbc777bddc02fdcefeaa3c416a63 (diff)
downloadffmpeg-1cb601ad10313981209a5918fc36a968068fc0ec.tar.gz
avcodec/mfenc: Dynamically load MFPlat.DLL
Allows non-UWP builds of FFmpeg with MediaFoundation to work on N editions of Windows which are without MediaFoundation by default. On UWP target, FFmpeg is linked directly against MediaFoundation since LoadLibrary is not available. This commit adresses https://trac.ffmpeg.org/ticket/9788 Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavcodec/mfenc.c')
-rw-r--r--libavcodec/mfenc.c93
1 files changed, 84 insertions, 9 deletions
diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c
index 280941cf2e..17d0ec60bd 100644
--- a/libavcodec/mfenc.c
+++ b/libavcodec/mfenc.c
@@ -32,6 +32,8 @@
typedef struct MFContext {
AVClass *av_class;
+ HMODULE library;
+ MFFunctions functions;
AVFrame *frame;
int is_video, is_audio;
GUID main_subtype;
@@ -292,7 +294,8 @@ 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->functions, 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,8 @@ 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->functions, NULL, size,
+ c->in_info.cbAlignment);
if (!sample)
return NULL;
@@ -422,7 +426,9 @@ 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->functions, NULL,
+ c->out_info.cbSize,
+ c->out_info.cbAlignment);
if (!sample)
return AVERROR(ENOMEM);
}
@@ -777,7 +783,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->functions.MFCreateMediaType(&out_type);
if (FAILED(hr)) {
ret = AVERROR(ENOMEM);
goto done;
@@ -1005,7 +1011,8 @@ err:
return res;
}
-static int mf_create(void *log, IMFTransform **mft, const AVCodec *codec, int use_hw)
+static int mf_create(void *log, MFFunctions *f, 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 +1035,13 @@ 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(log, f, category, NULL, &reg, use_hw, mft)) < 0)
return ret;
return 0;
}
-static int mf_init(AVCodecContext *avctx)
+static int mf_init_encoder(AVCodecContext *avctx)
{
MFContext *c = avctx->priv_data;
HRESULT hr;
@@ -1058,7 +1065,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(avctx, &c->functions, &c->mft, avctx->codec, use_hw)) < 0)
return ret;
if ((ret = mf_unlock_async(avctx)) < 0)
@@ -1122,6 +1129,54 @@ static int mf_init(AVCodecContext *avctx)
return 0;
}
+#if !HAVE_UWP
+#define LOAD_MF_FUNCTION(context, func_name) \
+ context->functions.func_name = (void *)GetProcAddress(context->library, #func_name); \
+ if (!context->functions.func_name) { \
+ av_log(context, AV_LOG_ERROR, "DLL mfplat.dll failed to find function "\
+ #func_name "\n"); \
+ return AVERROR_UNKNOWN; \
+ }
+#else
+// In UWP (which lacks LoadLibrary), just link directly against
+// the functions - this requires building with new/complete enough
+// import libraries.
+#define LOAD_MF_FUNCTION(context, func_name) \
+ context->functions.func_name = func_name; \
+ if (!context->functions.func_name) { \
+ av_log(context, AV_LOG_ERROR, "Failed to find function " #func_name \
+ "\n"); \
+ return AVERROR_UNKNOWN; \
+ }
+#endif
+
+// 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.
+static int mf_load_library(AVCodecContext *avctx)
+{
+ MFContext *c = avctx->priv_data;
+
+#if !HAVE_UWP
+ c->library = LoadLibraryA("mfplat.dll");
+
+ if (!c->library) {
+ av_log(c, AV_LOG_ERROR, "DLL mfplat.dll failed to open\n");
+ return AVERROR_UNKNOWN;
+ }
+#endif
+
+ LOAD_MF_FUNCTION(c, MFStartup);
+ LOAD_MF_FUNCTION(c, MFShutdown);
+ LOAD_MF_FUNCTION(c, MFCreateAlignedMemoryBuffer);
+ LOAD_MF_FUNCTION(c, MFCreateSample);
+ LOAD_MF_FUNCTION(c, MFCreateMediaType);
+ // MFTEnumEx is missing in Windows Vista's mfplat.dll.
+ LOAD_MF_FUNCTION(c, MFTEnumEx);
+
+ return 0;
+}
+
static int mf_close(AVCodecContext *avctx)
{
MFContext *c = avctx->priv_data;
@@ -1132,7 +1187,15 @@ static int mf_close(AVCodecContext *avctx)
if (c->async_events)
IMFMediaEventGenerator_Release(c->async_events);
- ff_free_mf(&c->mft);
+#if !HAVE_UWP
+ if (c->library)
+ ff_free_mf(&c->functions, &c->mft);
+
+ FreeLibrary(c->library);
+ c->library = NULL;
+#else
+ ff_free_mf(&c->functions, &c->mft);
+#endif
av_frame_free(&c->frame);
@@ -1142,6 +1205,18 @@ 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) \