Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- include/mferror.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/include/mferror.h b/include/mferror.h index 523800d7f02..28910d25682 100644 --- a/include/mferror.h +++ b/include/mferror.h @@ -77,12 +77,28 @@ #define MF_E_DISABLED_IN_SAFEMODE _HRESULT_TYPEDEF_(0xc00d36ef) #define MF_E_CANNOT_PARSE_BYTESTREAM _HRESULT_TYPEDEF_(0xc00d36f0) #define MF_E_SOURCERESOLVER_MUTUALLY_EXCLUSIVE_FLAGS _HRESULT_TYPEDEF_(0xc00d36f1) +#define MF_E_CANNOT_CREATE_SINK _HRESULT_TYPEDEF_(0xc00d36fa) #define MF_E_BYTESTREAM_UNKNOWN_LENGTH _HRESULT_TYPEDEF_(0xc00d36fb) +#define MF_E_SESSION_PAUSEWHILESTOPPED _HRESULT_TYPEDEF_(0xc00d36fc) +#define MF_S_ACTIVATE_REPLACED _HRESULT_TYPEDEF_(0x000d36fd) +#define MF_E_FORMAT_CHANGE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0xc00d36fe) #define MF_E_INVALID_WORKQUEUE _HRESULT_TYPEDEF_(0xc00d36ff) +#define MF_E_DRM_UNSUPPORTED _HRESULT_TYPEDEF_(0xc00d3700) +#define MF_E_UNAUTHORIZED _HRESULT_TYPEDEF_(0xc00d3701) +#define MF_E_OUT_OF_RANGE _HRESULT_TYPEDEF_(0xc00d3702) +#define MF_E_INVALID_CODEC_MERIT _HRESULT_TYPEDEF_(0xc00d3703) +#define MF_E_HW_MFT_FAILED_START_STREAMING _HRESULT_TYPEDEF_(0xc00d3704) +#define MF_E_OPERATION_IN_PROGRESS _HRESULT_TYPEDEF_(0xc00d3705) +#define MF_E_HARDWARE_DRM_UNSUPPORTED _HRESULT_TYPEDEF_(0xc00d3706) +#define MF_E_DURATION_TOO_LONG _HRESULT_TYPEDEF_(0xc00d3707) #define MF_E_NO_EVENTS_AVAILABLE _HRESULT_TYPEDEF_(0xc00d3e80) #define MF_E_INVALID_STATE_TRANSITION _HRESULT_TYPEDEF_(0xc00d3e82) #define MF_E_END_OF_STREAM _HRESULT_TYPEDEF_(0xc00d3e84) #define MF_E_SHUTDOWN _HRESULT_TYPEDEF_(0xc00d3e85) +#define MF_E_MP3_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d3e86) +#define MF_E_MP3_OUT_OF_DATA _HRESULT_TYPEDEF_(0xc00d3e87) +#define MF_E_MP3_NOTMP3 _HRESULT_TYPEDEF_(0xc00d3e88) +#define MF_E_MP3_NOTSUPPORTED _HRESULT_TYPEDEF_(0xc00d3e89) #define MF_E_NO_DURATION _HRESULT_TYPEDEF_(0xc00d3e8a) #define MF_E_INVALID_FORMAT _HRESULT_TYPEDEF_(0xc00d3e8c) #define MF_E_PROPERTY_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d3e8d) @@ -90,9 +106,17 @@ #define MF_E_PROPERTY_NOT_ALLOWED _HRESULT_TYPEDEF_(0xc00d3e8f) #define MF_E_MEDIA_SOURCE_NOT_STARTED _HRESULT_TYPEDEF_(0xc00d3e91) #define MF_E_UNSUPPORTED_FORMAT _HRESULT_TYPEDEF_(0xc00d3e98) +#define MF_E_MP3_BAD_CRC _HRESULT_TYPEDEF_(0xc00d3e99) +#define MF_E_NOT_PROTECTED _HRESULT_TYPEDEF_(0xc00d3e9a) #define MF_E_MEDIA_SOURCE_WRONGSTATE _HRESULT_TYPEDEF_(0xc00d3e9b) #define MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED _HRESULT_TYPEDEF_(0xc00d3e9c) +#define MF_E_CANNOT_FIND_KEYFRAME_SAMPLE _HRESULT_TYPEDEF_(0xc00d3e9d) #define MF_E_UNSUPPORTED_CHARACTERISTICS _HRESULT_TYPEDEF_(0xc00d3e9e) +#define MF_E_NO_AUDIO_RECORDING_DEVICE _HRESULT_TYPEDEF_(0xc00d3e9f) +#define MF_E_AUDIO_RECORDING_DEVICE_IN_USE _HRESULT_TYPEDEF_(0xc00d3ea0) +#define MF_E_AUDIO_RECORDING_DEVICE_INVALIDATED _HRESULT_TYPEDEF_(0xc00d3ea1) +#define MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED _HRESULT_TYPEDEF_(0xc00d3ea2) +#define MF_E_VIDEO_RECORDING_DEVICE_PREEMPTED _HRESULT_TYPEDEF_(0xc00d3ea3)
#define MF_E_STREAMSINK_REMOVED _HRESULT_TYPEDEF_(0xc00d4a38) #define MF_E_STREAMSINKS_OUT_OF_SYNC _HRESULT_TYPEDEF_(0xc00d4a3a)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 203 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 193 insertions(+), 10 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index b9a5fb46d6f..4136382566d 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -65,12 +65,15 @@ enum media_engine_flags FLAGS_ENGINE_PAUSED = 0x100, FLAGS_ENGINE_WAITING = 0x200, FLAGS_ENGINE_MUTED = 0x400, + FLAGS_ENGINE_HAS_AUDIO = 0x800, + FLAGS_ENGINE_HAS_VIDEO = 0x1000, };
struct media_engine { IMFMediaEngine IMFMediaEngine_iface; IMFAsyncCallback session_events; + IMFAsyncCallback load_handler; LONG refcount; IMFMediaEngineNotify *callback; IMFAttributes *attributes; @@ -80,6 +83,7 @@ struct media_engine double default_playback_rate; double volume; IMFMediaSession *session; + IMFSourceResolver *resolver; CRITICAL_SECTION cs; };
@@ -101,7 +105,12 @@ static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCa return CONTAINING_RECORD(iface, struct media_engine, session_events); }
-static HRESULT WINAPI media_engine_session_events_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct media_engine, load_handler); +} + +static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown)) @@ -128,7 +137,7 @@ static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface) return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface); }
-static HRESULT WINAPI media_engine_session_events_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) { return E_NOTIMPL; } @@ -175,13 +184,142 @@ failed:
static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl = { - media_engine_session_events_QueryInterface, + media_engine_callback_QueryInterface, media_engine_session_events_AddRef, media_engine_session_events_Release, - media_engine_session_events_GetParameters, + media_engine_callback_GetParameters, media_engine_session_events_Invoke, };
+static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface) +{ + struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface); + return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface); +} + +static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface) +{ + struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface); + return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface); +} + +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; + HRESULT hr; + + if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd))) + return hr; + + if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count))) + WARN("Failed to get stream count, hr %#x.\n", hr); + + /* Enable first video stream and first audio stream. */ + + for (i = 0; i < stream_count; ++i) + { + IMFMediaTypeHandler *type_handler; + IMFStreamDescriptor *sd; + BOOL selected; + + IMFPresentationDescriptor_DeselectStream(pd, i); + + if (sd_audio && sd_video) + continue; + + IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd); + + if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler))) + { + GUID major = { 0 }; + + IMFMediaTypeHandler_GetMajorType(type_handler, &major); + + if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio) + { + sd_audio = sd; + IMFStreamDescriptor_AddRef(sd_audio); + IMFPresentationDescriptor_SelectStream(pd, i); + } + else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY)) + { + sd_video = sd; + IMFStreamDescriptor_AddRef(sd_video); + IMFPresentationDescriptor_SelectStream(pd, i); + } + + IMFMediaTypeHandler_Release(type_handler); + } + } + + if (!sd_video && !sd_audio) + { + IMFPresentationDescriptor_Release(pd); + return E_UNEXPECTED; + } + + if (sd_video) + engine->flags |= FLAGS_ENGINE_HAS_VIDEO; + if (sd_audio) + engine->flags |= FLAGS_ENGINE_HAS_AUDIO; + + /* TODO: set duration */ + + if (sd_video) + IMFStreamDescriptor_Release(sd_video); + if (sd_audio) + IMFStreamDescriptor_Release(sd_audio); + + IMFPresentationDescriptor_Release(pd); + + return S_OK; +} + +static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface); + MF_OBJECT_TYPE obj_type; + IMFMediaSource *source; + IUnknown *object = NULL; + HRESULT hr; + + EnterCriticalSection(&engine->cs); + + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0); + + if (FAILED(hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object))) + WARN("Failed to create source object, hr %#x.\n", hr); + + if (object) + { + if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source))) + { + hr = media_engine_create_topology(engine, source); + IMFMediaSource_Release(source); + } + IUnknown_Release(object); + } + + if (FAILED(hr)) + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, + MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED, hr); + + LeaveCriticalSection(&engine->cs); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl = +{ + media_engine_callback_QueryInterface, + media_engine_load_handler_AddRef, + media_engine_load_handler_Release, + media_engine_callback_GetParameters, + media_engine_load_handler_Invoke, +}; + static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngine *iface, REFIID riid, void **obj) { TRACE("(%p, %s, %p).\n", iface, debugstr_guid(riid), obj); @@ -217,6 +355,8 @@ static void free_media_engine(struct media_engine *engine) IMFMediaSession_Release(engine->session); if (engine->attributes) IMFAttributes_Release(engine->attributes); + if (engine->resolver) + IMFSourceResolver_Release(engine->resolver); DeleteCriticalSection(&engine->cs); heap_free(engine); } @@ -257,9 +397,34 @@ static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngine *iface, IMFM
static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url) { - FIXME("(%p, %s): stub.\n", iface, debugstr_w(url)); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %s.\n", iface, debugstr_w(url)); + + EnterCriticalSection(&engine->cs); + + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0); + + if (url) + { + IPropertyStore *props = NULL; + unsigned int flags; + + flags = MF_RESOLUTION_MEDIASOURCE; + if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS) + flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS; + + IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE, + &IID_IPropertyStore, (void **)&props); + hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL, &engine->load_handler, NULL); + if (props) + IPropertyStore_Release(props); + } + + LeaveCriticalSection(&engine->cs); + + return hr; }
static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngine *iface, BSTR *url) @@ -633,16 +798,30 @@ static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngine *iface, double volum
static BOOL WINAPI media_engine_HasVideo(IMFMediaEngine *iface) { - FIXME("(%p): stub.\n", iface); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + BOOL value;
- return FALSE; + TRACE("%p.\n", iface); + + EnterCriticalSection(&engine->cs); + value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO); + LeaveCriticalSection(&engine->cs); + + return value; }
static BOOL WINAPI media_engine_HasAudio(IMFMediaEngine *iface) { - FIXME("(%p): stub.\n", iface); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + BOOL value;
- return FALSE; + TRACE("%p.\n", iface); + + EnterCriticalSection(&engine->cs); + value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO); + LeaveCriticalSection(&engine->cs); + + return value; }
static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngine *iface, DWORD *cx, DWORD *cy) @@ -777,6 +956,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct
engine->IMFMediaEngine_iface.lpVtbl = &media_engine_vtbl; engine->session_events.lpVtbl = &media_engine_session_events_vtbl; + engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl; engine->refcount = 1; engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED; engine->default_playback_rate = 1.0; @@ -795,6 +975,9 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL))) return hr;
+ if (FAILED(hr = MFCreateSourceResolver(&engine->resolver))) + return hr; + if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0))) return hr;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 4136382566d..e39009b30b4 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -18,6 +18,7 @@
#define COBJMACROS
+#include <math.h> #include <stdarg.h>
#include "windef.h" @@ -82,6 +83,7 @@ struct media_engine double playback_rate; double default_playback_rate; double volume; + double duration; IMFMediaSession *session; IMFSourceResolver *resolver; CRITICAL_SECTION cs; @@ -208,6 +210,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; unsigned int stream_count = 0, i; IMFPresentationDescriptor *pd; + UINT64 duration; HRESULT hr;
if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd))) @@ -265,7 +268,20 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (sd_audio) engine->flags |= FLAGS_ENGINE_HAS_AUDIO;
- /* TODO: set duration */ + /* Assume live source if duration was not provided. */ + if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration))) + { + /* Convert 100ns to seconds. */ + engine->duration = duration / 10000000; + } + else + engine->duration = INFINITY; + + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0); + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0); + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0); + + /* TODO: set up topology nodes */
if (sd_video) IMFStreamDescriptor_Release(sd_video); @@ -513,9 +529,16 @@ static double WINAPI media_engine_GetStartTime(IMFMediaEngine *iface)
static double WINAPI media_engine_GetDuration(IMFMediaEngine *iface) { - FIXME("(%p): stub.\n", iface); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + double value;
- return 0.0; + TRACE("%p.\n", iface); + + EnterCriticalSection(&engine->cs); + value = engine->duration; + LeaveCriticalSection(&engine->cs); + + return value; }
static BOOL WINAPI media_engine_IsPaused(IMFMediaEngine *iface) @@ -962,6 +985,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct engine->default_playback_rate = 1.0; engine->playback_rate = 1.0; engine->volume = 1.0; + engine->duration = NAN; InitializeCriticalSection(&engine->cs);
hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/tests/mfmediaengine.c | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+)
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index a5b80ef25f4..59154c8d4f0 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -490,6 +490,60 @@ static void test_mute(void) IMFMediaEngine_Release(media_engine); }
+static void test_error(void) +{ + struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1}; + IMFMediaEngineNotify *callback = ¬ify_impl.IMFMediaEngineNotify_iface; + IMFMediaEngine *media_engine; + IMFMediaError *eo, *eo2; + HRESULT hr; + + media_engine = create_media_engine(callback); + + 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); + + 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"); +} + IMFMediaEngine_Release(media_engine); +} + START_TEST(mfmediaengine) { HRESULT hr; @@ -516,6 +570,7 @@ START_TEST(mfmediaengine) test_Play(); test_playback_rate(); test_mute(); + test_error();
IMFMediaEngineClassFactory_Release(factory);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 124 ++++++++++++++++++++++- dlls/mfmediaengine/tests/mfmediaengine.c | 28 +++++ 2 files changed, 150 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index e39009b30b4..d77b1e4afee 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -89,6 +89,126 @@ struct media_engine CRITICAL_SECTION cs; };
+struct media_error +{ + IMFMediaError IMFMediaError_iface; + LONG refcount; + unsigned int code; + HRESULT extended_code; +}; + +static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface) +{ + return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface); +} + +static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFMediaError) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFMediaError_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI media_error_AddRef(IMFMediaError *iface) +{ + struct media_error *me = impl_from_IMFMediaError(iface); + ULONG refcount = InterlockedIncrement(&me->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI media_error_Release(IMFMediaError *iface) +{ + struct media_error *me = impl_from_IMFMediaError(iface); + ULONG refcount = InterlockedDecrement(&me->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + heap_free(me); + + return refcount; +} + +static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface) +{ + struct media_error *me = impl_from_IMFMediaError(iface); + TRACE("%p.\n", iface); + return me->code; +} + +static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface) +{ + struct media_error *me = impl_from_IMFMediaError(iface); + TRACE("%p.\n", iface); + return me->extended_code; +} + +static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code) +{ + struct media_error *me = impl_from_IMFMediaError(iface); + + TRACE("%p, %u.\n", iface, code); + + if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED) + return E_INVALIDARG; + + me->code = code; + + return S_OK; +} + +static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code) +{ + struct media_error *me = impl_from_IMFMediaError(iface); + + TRACE("%p, %#x.\n", iface, code); + + me->extended_code = code; + + return S_OK; +} + +static const IMFMediaErrorVtbl media_error_vtbl = +{ + media_error_QueryInterface, + media_error_AddRef, + media_error_Release, + media_error_GetErrorCode, + media_error_GetExtendedErrorCode, + media_error_SetErrorCode, + media_error_SetExtendedErrorCode, +}; + +static HRESULT create_media_error(IMFMediaError **ret) +{ + struct media_error *object; + + *ret = NULL; + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFMediaError_iface.lpVtbl = &media_error_vtbl; + object->refcount = 1; + + *ret = &object->IMFMediaError_iface; + + return S_OK; +} + static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value) { if (value) @@ -1060,9 +1180,9 @@ static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFa
static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error) { - FIXME("(%p, %p): stub.\n", iface, error); + TRACE("%p, %p.\n", iface, error);
- return E_NOTIMPL; + return create_media_error(error); }
static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl = diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 59154c8d4f0..2f114db7e9e 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -496,6 +496,7 @@ static void test_error(void) IMFMediaEngineNotify *callback = ¬ify_impl.IMFMediaEngineNotify_iface; IMFMediaEngine *media_engine; IMFMediaError *eo, *eo2; + unsigned int code; HRESULT hr;
media_engine = create_media_engine(callback); @@ -542,6 +543,33 @@ todo_wine { ok(!eo, "Unexpected instance.\n"); } IMFMediaEngine_Release(media_engine); + + /* Error object. */ + hr = IMFMediaEngineClassFactory_CreateError(factory, &eo); + ok(hr == S_OK, "Failed to create error object, hr %#x.\n", hr); + + code = IMFMediaError_GetErrorCode(eo); + ok(code == MF_MEDIA_ENGINE_ERR_NOERROR, "Unexpected code %u.\n", code); + + hr = IMFMediaError_GetExtendedErrorCode(eo); + ok(hr == S_OK, "Unexpected code %#x.\n", hr); + + hr = IMFMediaError_SetErrorCode(eo, MF_MEDIA_ENGINE_ERR_ENCRYPTED + 1); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaError_SetErrorCode(eo, MF_MEDIA_ENGINE_ERR_ABORTED); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + code = IMFMediaError_GetErrorCode(eo); + ok(code == MF_MEDIA_ENGINE_ERR_ABORTED, "Unexpected code %u.\n", code); + + hr = IMFMediaError_SetExtendedErrorCode(eo, E_FAIL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaError_GetExtendedErrorCode(eo); + ok(hr == E_FAIL, "Unexpected code %#x.\n", hr); + + IMFMediaError_Release(eo); }
START_TEST(mfmediaengine)