From: Bernhard Kölbl besentv@gmail.com
--- dlls/mfmediaengine/main.c | 112 ++++++++++++++++++++++- dlls/mfmediaengine/tests/mfmediaengine.c | 7 +- 2 files changed, 113 insertions(+), 6 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index b3ac236c78e..2f20e568128 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -113,6 +113,12 @@ struct rect float left, top, right, bottom; };
+struct video_effect +{ + IUnknown *object; + BOOL optional; +}; + struct media_engine { IMFMediaEngineEx IMFMediaEngineEx_iface; @@ -146,6 +152,11 @@ struct media_engine IMFPresentationDescriptor *pd; } presentation; struct + { + struct video_effect *video_effects; + DWORD video_effects_size; + } effects; + struct { LONGLONG pts; SIZE size; @@ -1018,6 +1029,43 @@ static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresen return S_OK; }
+static HRESULT media_engine_create_video_effects(struct media_engine *engine, IMFTopologyNode ***nodes) +{ + HRESULT hr = S_OK; + UINT i; + + if (!engine->effects.video_effects_size) + return S_OK; + + if(!(*nodes = calloc(engine->effects.video_effects_size, sizeof(**nodes)))) + return E_OUTOFMEMORY; + + for (i = 0; i < engine->effects.video_effects_size; ++i) + { + IMFTopologyNode *node = NULL; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node))) + goto failed; + + IMFTopologyNode_SetObject(node, (IUnknown *)engine->effects.video_effects[i].object); + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + + if (engine->effects.video_effects[i].optional) + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_AS_OPTIONAL); + + (*nodes)[i] = node; + } + + return S_OK; + +failed: + for (i = 0; i < engine->effects.video_effects_size; ++i) + if ((*nodes)[i]) IMFTopologyNode_Release((*nodes)[i]); + + *nodes = NULL; + return hr; +} + static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; @@ -1105,6 +1153,18 @@ static void media_engine_clear_presentation(struct media_engine *engine) memset(&engine->presentation, 0, sizeof(engine->presentation)); }
+static void media_engine_clear_effects(struct media_engine *engine) +{ + UINT i; + + for (i = 0; i < engine->effects.video_effects_size; ++i) + IUnknown_Release(engine->effects.video_effects[i].object); + + free(engine->effects.video_effects); + engine->effects.video_effects = NULL; + engine->effects.video_effects_size = 0; +} + static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) { IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; @@ -1190,6 +1250,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi { IMFTopologyNode *sar_node = NULL, *audio_src = NULL; IMFTopologyNode *grabber_node = NULL, *video_src = NULL; + IMFTopologyNode **video_effects = NULL;
if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE) IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE); @@ -1223,16 +1284,35 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node))) WARN("Failed to create video grabber node, hr %#lx.\n", hr);
+ if (FAILED(media_engine_create_video_effects(engine, &video_effects))) + WARN("Failed to create video effect nodes, hr %#lx.\n", hr); + if (grabber_node && video_src) { IMFTopology_AddNode(topology, video_src); IMFTopology_AddNode(topology, grabber_node); - IMFTopologyNode_ConnectOutput(video_src, 0, grabber_node, 0); + + for (i = 0; video_effects && i < engine->effects.video_effects_size; ++i) + { + IMFTopology_AddNode(topology, video_effects[i]); + if (i > 0) + IMFTopologyNode_ConnectOutput(video_effects[i - 1], 0, video_effects[i], 0); + } + + if (video_effects) + { + IMFTopologyNode_ConnectOutput(video_src, 0, video_effects[0], 0); + IMFTopologyNode_ConnectOutput(video_effects[engine->effects.video_effects_size - 1], 0, grabber_node, 0); + } + else + IMFTopologyNode_ConnectOutput(video_src, 0, grabber_node, 0); }
if (SUCCEEDED(hr)) IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
+ for (i = 0; video_effects && i < engine->effects.video_effects_size; ++i) + IMFTopologyNode_Release(video_effects[i]); if (grabber_node) IMFTopologyNode_Release(grabber_node); if (video_src) @@ -1382,6 +1462,7 @@ static void free_media_engine(struct media_engine *engine) IMFAttributes_Release(engine->attributes); if (engine->resolver) IMFSourceResolver_Release(engine->resolver); + media_engine_clear_effects(engine); media_engine_release_video_frame_resources(engine); media_engine_clear_presentation(engine); if (engine->device_manager) @@ -2589,9 +2670,34 @@ static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *pr
static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { - FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); + struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); + struct video_effect *tmp; + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p, %d.\n", iface, effect, is_optional); + + EnterCriticalSection(&engine->cs); + + if (engine->flags & FLAGS_ENGINE_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (!(tmp = realloc(engine->effects.video_effects, + sizeof(*engine->effects.video_effects) * (engine->effects.video_effects_size + 1)))) + { + hr = MF_E_INVALIDREQUEST; + } + else + { + tmp[engine->effects.video_effects_size].object = effect; + IUnknown_AddRef(tmp[engine->effects.video_effects_size].object); + tmp[engine->effects.video_effects_size].optional = is_optional; + + engine->effects.video_effects = tmp; + engine->effects.video_effects_size++; + } + + LeaveCriticalSection(&engine->cs); + + return hr; }
static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index c4d444b1aa2..26ec957253c 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1376,6 +1376,7 @@ static ULONG WINAPI static_color_effect_AddRef(IMFTransform *iface) { struct static_color_effect *impl = impl_from_IMFTransform(iface); ULONG refcount = InterlockedIncrement(&impl->refcount); + return refcount; }
@@ -2013,15 +2014,15 @@ static void test_video_effect(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect->IMFTransform_iface, FALSE); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); EXPECT_REF(&video_effect->IMFTransform_iface, 2);
hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect2->IMFTransform_iface, FALSE); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); EXPECT_REF(&video_effect2->IMFTransform_iface, 2);
hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect3->IMFTransform_iface, FALSE); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); EXPECT_REF(&video_effect3->IMFTransform_iface, 2);
if (FAILED(hr))