Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 39 +++++++++++++++++++++--- dlls/mfmediaengine/tests/mfmediaengine.c | 32 ++++++++++--------- 2 files changed, 51 insertions(+), 20 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index d77b1e4afee..dba55bb937d 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -84,6 +84,7 @@ struct media_engine double default_playback_rate; double volume; double duration; + MF_MEDIA_ENGINE_ERR error_code; IMFMediaSession *session; IMFSourceResolver *resolver; CRITICAL_SECTION cs; @@ -512,16 +513,44 @@ static ULONG WINAPI media_engine_Release(IMFMediaEngine *iface)
static HRESULT WINAPI media_engine_GetError(IMFMediaEngine *iface, IMFMediaError **error) { - FIXME("(%p, %p): stub.\n", iface, error); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, error); + + *error = NULL; + + EnterCriticalSection(&engine->cs); + if (engine->flags & FLAGS_ENGINE_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (engine->error_code) + { + if (SUCCEEDED(hr = create_media_error(error))) + IMFMediaError_SetErrorCode(*error, engine->error_code); + } + LeaveCriticalSection(&engine->cs); + + return hr; }
-static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngine *iface, MF_MEDIA_ENGINE_ERR error) +static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngine *iface, MF_MEDIA_ENGINE_ERR code) { - FIXME("(%p, %d): stub.\n", iface, error); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u.\n", iface, code); + + if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED) + return E_INVALIDARG; + + EnterCriticalSection(&engine->cs); + if (engine->flags & FLAGS_ENGINE_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else + engine->error_code = code; + LeaveCriticalSection(&engine->cs); + + return hr; }
static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngine *iface, IMFMediaEngineSrcElements *elements) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 2f114db7e9e..660e5b95331 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -503,45 +503,47 @@ static void test_error(void)
eo = (void *)0xdeadbeef; hr = IMFMediaEngine_GetError(media_engine, &eo); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!eo, "Unexpected instance.\n"); -} + hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_ENCRYPTED + 1); -todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_ABORTED); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
eo = NULL; hr = IMFMediaEngine_GetError(media_engine, &eo); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!!eo, "Unexpected instance.\n"); -} + eo2 = NULL; hr = IMFMediaEngine_GetError(media_engine, &eo2); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(eo2 != eo, "Unexpected instance.\n"); -} - if (eo2) - IMFMediaError_Release(eo2); - if (eo) - IMFMediaError_Release(eo); + + IMFMediaError_Release(eo2); + IMFMediaError_Release(eo);
hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_NOERROR); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
eo = (void *)0xdeadbeef; hr = IMFMediaEngine_GetError(media_engine, &eo); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!eo, "Unexpected instance.\n"); -} + + hr = IMFMediaEngine_Shutdown(media_engine); + ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr); + + eo = (void *)0xdeadbeef; + hr = IMFMediaEngine_GetError(media_engine, &eo); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + ok(!eo, "Unexpected instance.\n"); + + hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_NOERROR); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + IMFMediaEngine_Release(media_engine);
/* Error object. */
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index dba55bb937d..7693205238a 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -85,6 +85,7 @@ struct media_engine double volume; double duration; MF_MEDIA_ENGINE_ERR error_code; + HRESULT extended_code; IMFMediaSession *session; IMFSourceResolver *resolver; CRITICAL_SECTION cs; @@ -440,8 +441,12 @@ static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, }
if (FAILED(hr)) - IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, - MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED, hr); + { + engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED; + engine->extended_code = hr; + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code, + engine->extended_code); + }
LeaveCriticalSection(&engine->cs);
@@ -526,7 +531,10 @@ static HRESULT WINAPI media_engine_GetError(IMFMediaEngine *iface, IMFMediaError else if (engine->error_code) { if (SUCCEEDED(hr = create_media_error(error))) + { IMFMediaError_SetErrorCode(*error, engine->error_code); + IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code); + } } LeaveCriticalSection(&engine->cs);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/Makefile.in | 2 +- dlls/mfmediaengine/main.c | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/Makefile.in b/dlls/mfmediaengine/Makefile.in index cb593cb7edf..b97e9eec331 100644 --- a/dlls/mfmediaengine/Makefile.in +++ b/dlls/mfmediaengine/Makefile.in @@ -1,6 +1,6 @@ MODULE = mfmediaengine.dll IMPORTLIB = mfmediaengine -IMPORTS = mfplat mf mfuuid uuid +IMPORTS = oleaut32 mfplat mf mfuuid uuid
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 7693205238a..2f4a38936c4 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -88,6 +88,7 @@ struct media_engine HRESULT extended_code; IMFMediaSession *session; IMFSourceResolver *resolver; + BSTR current_source; CRITICAL_SECTION cs; };
@@ -499,6 +500,7 @@ static void free_media_engine(struct media_engine *engine) IMFAttributes_Release(engine->attributes); if (engine->resolver) IMFSourceResolver_Release(engine->resolver); + SysFreeString(engine->current_source); DeleteCriticalSection(&engine->cs); heap_free(engine); } @@ -577,6 +579,11 @@ static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url)
EnterCriticalSection(&engine->cs);
+ SysFreeString(engine->current_source); + engine->current_source = NULL; + if (url) + engine->current_source = SysAllocString(url); + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
if (url) @@ -602,9 +609,22 @@ static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url)
static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngine *iface, BSTR *url) { - FIXME("(%p, %p): stub.\n", iface, url); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, url); + + *url = NULL; + + EnterCriticalSection(&engine->cs); + if (engine->current_source) + { + if (!(*url = SysAllocString(engine->current_source))) + hr = E_OUTOFMEMORY; + } + LeaveCriticalSection(&engine->cs); + + return hr; }
static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngine *iface)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 19 +++++++++++++++++-- include/mfmediaengine.idl | 9 +++++++++ 2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 2f4a38936c4..fee5f6338d5 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -86,6 +86,7 @@ struct media_engine double duration; MF_MEDIA_ENGINE_ERR error_code; HRESULT extended_code; + MF_MEDIA_ENGINE_READY ready_state; IMFMediaSession *session; IMFSourceResolver *resolver; BSTR current_source; @@ -400,8 +401,13 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi else engine->duration = INFINITY;
+ engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA; + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0); + + engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA; + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
/* TODO: set up topology nodes */ @@ -584,6 +590,8 @@ static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url) if (url) engine->current_source = SysAllocString(url);
+ engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING; + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
if (url) @@ -671,9 +679,16 @@ static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngine *iface, BSTR type,
static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngine *iface) { - FIXME("(%p): stub.\n", iface); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + unsigned short state;
- return 0; + TRACE("%p.\n", iface); + + EnterCriticalSection(&engine->cs); + state = engine->ready_state; + LeaveCriticalSection(&engine->cs); + + return state; }
static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngine *iface) diff --git a/include/mfmediaengine.idl b/include/mfmediaengine.idl index 4ea3d834cf2..b914cb3600b 100644 --- a/include/mfmediaengine.idl +++ b/include/mfmediaengine.idl @@ -137,6 +137,15 @@ typedef enum MF_MEDIA_ENGINE_EVENT MF_MEDIA_ENGINE_EVENT_AUDIOENDPOINTCHANGE = 1016, } MF_MEDIA_ENGINE_EVENT;
+typedef enum MF_MEDIA_ENGINE_READY +{ + MF_MEDIA_ENGINE_READY_HAVE_NOTHING, + MF_MEDIA_ENGINE_READY_HAVE_METADATA, + MF_MEDIA_ENGINE_READY_HAVE_CURRENT_DATA, + MF_MEDIA_ENGINE_READY_HAVE_FUTURE_DATA, + MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA, +} MF_MEDIA_ENGINE_READY; + [ object, uuid(fc0e10d2-ab2a-4501-a951-06bb1075184c),
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 77 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index fee5f6338d5..d93e2b2f38c 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -329,11 +329,55 @@ static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface) return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface); }
+static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd, + IMFTopologyNode **node) +{ + HRESULT hr; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node))) + return hr; + + IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)source); + IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); + IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); + + return S_OK; +} + +static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) +{ + unsigned int category, role; + IMFActivate *sar_activate; + HRESULT hr; + + *node = NULL; + + if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate))) + return hr; + + /* Configuration attributes keys differ between Engine and SAR. */ + if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category))) + IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category); + if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role))) + IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role); + + if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node))) + { + IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate); + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + } + + IMFActivate_Release(sar_activate); + + return hr; +} + static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) { IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; unsigned int stream_count = 0, i; IMFPresentationDescriptor *pd; + IMFTopology *topology; UINT64 duration; HRESULT hr;
@@ -410,7 +454,36 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
- /* TODO: set up topology nodes */ + /* TODO: set up video stream nodes */ + + if (SUCCEEDED(hr = MFCreateTopology(&topology))) + { + IMFTopologyNode *sar_node = NULL, *audio_src = NULL; + + if (sd_audio) + { + if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src))) + WARN("Failed to create audio source node, hr %#x.\n", hr); + + if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node))) + WARN("Failed to create audio renderer node, hr %#x.\n", hr); + + if (sar_node && audio_src) + { + IMFTopology_AddNode(topology, audio_src); + IMFTopology_AddNode(topology, sar_node); + IMFTopologyNode_ConnectOutput(audio_src, 0, sar_node, 0); + } + + if (sar_node) + IMFTopologyNode_Release(sar_node); + if (audio_src) + IMFTopologyNode_Release(audio_src); + } + } + + if (topology) + IMFTopology_Release(topology);
if (sd_video) IMFStreamDescriptor_Release(sd_video); @@ -419,7 +492,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
IMFPresentationDescriptor_Release(pd);
- return S_OK; + return hr; }
static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)