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..4b11b0a06ea 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,12 @@ struct media_engine IMFPresentationDescriptor *pd; } presentation; struct + { + struct video_effect *video_effects; + size_t video_effects_count; + size_t video_effects_capacity; + } effects; + struct { LONGLONG pts; SIZE size; @@ -1018,6 +1030,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_count) + return S_OK; + + if(!(*nodes = calloc(engine->effects.video_effects_count, sizeof(**nodes)))) + return E_OUTOFMEMORY; + + for (i = 0; i < engine->effects.video_effects_count; ++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_count; ++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 +1154,19 @@ 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) +{ + size_t i; + + for (i = 0; i < engine->effects.video_effects_count; ++i) + IUnknown_Release(engine->effects.video_effects[i].object); + + free(engine->effects.video_effects); + engine->effects.video_effects = NULL; + engine->effects.video_effects_capacity = 0; + engine->effects.video_effects_count = 0; +} + static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) { IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; @@ -1190,6 +1252,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 +1286,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_count; ++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_count - 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_count; ++i) + IMFTopologyNode_Release(video_effects[i]); if (grabber_node) IMFTopologyNode_Release(grabber_node); if (video_src) @@ -1382,6 +1464,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 +2672,32 @@ 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); + 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 (!mf_array_reserve((void **)&engine->effects.video_effects, &engine->effects.video_effects_capacity, + engine->effects.video_effects_count + 1, sizeof(*engine->effects.video_effects))) + { + hr = E_OUTOFMEMORY; + } + else + { + engine->effects.video_effects[engine->effects.video_effects_count].object = effect; + IUnknown_AddRef(engine->effects.video_effects[engine->effects.video_effects_count].object); + engine->effects.video_effects[engine->effects.video_effects_count].optional = is_optional; + + engine->effects.video_effects_count++; + } + + 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))