[PATCH 2/3] mfplay: Handle shutdown state in media item methods.

Nikolay Sivov nsivov at codeweavers.com
Mon Feb 14 05:49:12 CST 2022


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplay/player.c          | 214 ++++++++++++++++++++++++++--------
 dlls/mfplay/tests/Makefile.in |   4 +-
 dlls/mfplay/tests/mfplay.c    | 147 ++++++++++++++++++++++-
 dlls/mfplay/tests/resource.rc |  22 ++++
 dlls/mfplay/tests/test.mp4    | Bin 0 -> 1554 bytes
 5 files changed, 336 insertions(+), 51 deletions(-)
 create mode 100644 dlls/mfplay/tests/resource.rc
 create mode 100644 dlls/mfplay/tests/test.mp4

diff --git a/dlls/mfplay/player.c b/dlls/mfplay/player.c
index 31c8e094cd2..d8c13cc22a8 100644
--- a/dlls/mfplay/player.c
+++ b/dlls/mfplay/player.c
@@ -59,11 +59,13 @@ static inline const char *debugstr_normalized_rect(const MFVideoNormalizedRect *
     return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)", rect->left, rect->top, rect->right, rect->bottom);
 }
 
+struct media_player;
+
 struct media_item
 {
     IMFPMediaItem IMFPMediaItem_iface;
     LONG refcount;
-    IMFPMediaPlayer *player;
+    struct media_player *player;
     IMFMediaSource *source;
     IMFPresentationDescriptor *pd;
     DWORD_PTR user_data;
@@ -308,6 +310,16 @@ static void media_player_set_state(struct media_player *player, MFP_MEDIAPLAYER_
     }
 }
 
+static HRESULT media_item_get_pd(const struct media_item *item, IMFPresentationDescriptor **pd)
+{
+    if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
+        return MF_E_SHUTDOWN;
+
+    *pd = item->pd;
+    IMFPresentationDescriptor_AddRef(*pd);
+    return S_OK;
+}
+
 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
 {
     TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
@@ -345,7 +357,7 @@ static ULONG WINAPI media_item_Release(IMFPMediaItem *iface)
     if (!refcount)
     {
         if (item->player)
-            IMFPMediaPlayer_Release(item->player);
+            IMFPMediaPlayer_Release(&item->player->IMFPMediaPlayer_iface);
         if (item->source)
             IMFMediaSource_Release(item->source);
         if (item->pd)
@@ -363,45 +375,70 @@ static HRESULT WINAPI media_item_GetMediaPlayer(IMFPMediaItem *iface,
         IMFPMediaPlayer **player)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    HRESULT hr = S_OK;
 
     TRACE("%p, %p.\n", iface, player);
 
-    *player = item->player;
-    IMFPMediaPlayer_AddRef(*player);
+    EnterCriticalSection(&item->player->cs);
+    if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
+    {
+        hr = MF_E_SHUTDOWN;
+        *player = NULL;
+    }
+    else
+    {
+        *player = &item->player->IMFPMediaPlayer_iface;
+        IMFPMediaPlayer_AddRef(*player);
+    }
+    LeaveCriticalSection(&item->player->cs);
 
-    return S_OK;
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetURL(IMFPMediaItem *iface, LPWSTR *url)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    HRESULT hr = S_OK;
 
     TRACE("%p, %p.\n", iface, url);
 
-    if (!item->url)
-        return MF_E_NOT_FOUND;
-
-    if (!(*url = CoTaskMemAlloc((wcslen(item->url) + 1) * sizeof(*item->url))))
-        return E_OUTOFMEMORY;
-
-    wcscpy(*url, item->url);
+    EnterCriticalSection(&item->player->cs);
+    if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
+        hr = MF_E_SHUTDOWN;
+    else if (!item->url)
+        hr = MF_E_NOT_FOUND;
+    else
+    {
+        if (!(*url = CoTaskMemAlloc((wcslen(item->url) + 1) * sizeof(*item->url))))
+            hr = E_OUTOFMEMORY;
+        if (*url)
+            wcscpy(*url, item->url);
+    }
+    LeaveCriticalSection(&item->player->cs);
 
-    return S_OK;
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetObject(IMFPMediaItem *iface, IUnknown **object)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    HRESULT hr = S_OK;
 
     TRACE("%p, %p.\n", iface, object);
 
-    if (!item->object)
-        return MF_E_NOT_FOUND;
-
-    *object = item->object;
-    IUnknown_AddRef(*object);
+    EnterCriticalSection(&item->player->cs);
+    if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
+        hr = MF_E_SHUTDOWN;
+    else if (!item->object)
+        hr = MF_E_NOT_FOUND;
+    else
+    {
+        *object = item->object;
+        IUnknown_AddRef(*object);
+    }
+    LeaveCriticalSection(&item->player->cs);
 
-    return S_OK;
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetUserData(IMFPMediaItem *iface, DWORD_PTR *user_data)
@@ -530,28 +567,38 @@ static HRESULT media_item_get_stream_type(IMFStreamDescriptor *sd, GUID *major)
 
 static HRESULT media_item_has_stream(struct media_item *item, const GUID *major, BOOL *has_stream, BOOL *is_selected)
 {
+    IMFPresentationDescriptor *pd;
     IMFStreamDescriptor *sd;
     unsigned int idx = 0;
     BOOL selected;
+    HRESULT hr;
     GUID guid;
 
-    *has_stream = *is_selected = FALSE;
+    EnterCriticalSection(&item->player->cs);
 
-    while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
     {
-        if (SUCCEEDED(media_item_get_stream_type(sd, &guid)) && IsEqualGUID(&guid, major))
+        *has_stream = *is_selected = FALSE;
+
+        while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, idx++, &selected, &sd)))
         {
-            *has_stream = TRUE;
-            *is_selected = selected;
-        }
+            if (SUCCEEDED(media_item_get_stream_type(sd, &guid)) && IsEqualGUID(&guid, major))
+            {
+                *has_stream = TRUE;
+                *is_selected = selected;
+            }
 
-        IMFStreamDescriptor_Release(sd);
+            IMFStreamDescriptor_Release(sd);
 
-        if (*has_stream && *is_selected)
-            break;
+            if (*has_stream && *is_selected)
+                break;
+        }
+        IMFPresentationDescriptor_Release(pd);
     }
 
-    return S_OK;
+    LeaveCriticalSection(&item->player->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_item_HasVideo(IMFPMediaItem *iface, BOOL *has_video, BOOL *selected)
@@ -575,42 +622,77 @@ static HRESULT WINAPI media_item_HasAudio(IMFPMediaItem *iface, BOOL *has_audio,
 static HRESULT WINAPI media_item_IsProtected(IMFPMediaItem *iface, BOOL *protected)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
+    HRESULT hr;
 
     TRACE("%p, %p.\n", iface, protected);
 
-    *protected = MFRequireProtectedEnvironment(item->pd) == S_OK;
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
+    {
+        *protected = MFRequireProtectedEnvironment(pd) == S_OK;
+        IMFPresentationDescriptor_Release(pd);
+    }
+    LeaveCriticalSection(&item->player->cs);
 
-    return S_OK;
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetDuration(IMFPMediaItem *iface, REFGUID format, PROPVARIANT *value)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
+    HRESULT hr;
 
     TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), value);
 
-    return IMFPresentationDescriptor_GetItem(item->pd, &MF_PD_DURATION, value);
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
+    {
+        hr = IMFPresentationDescriptor_GetItem(pd, &MF_PD_DURATION, value);
+        IMFPresentationDescriptor_Release(pd);
+    }
+    LeaveCriticalSection(&item->player->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetNumberOfStreams(IMFPMediaItem *iface, DWORD *count)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
+    HRESULT hr;
 
     TRACE("%p, %p.\n", iface, count);
 
-    return IMFPresentationDescriptor_GetStreamDescriptorCount(item->pd, count);
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
+    {
+        hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, count);
+        IMFPresentationDescriptor_Release(pd);
+    }
+    LeaveCriticalSection(&item->player->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL *selected)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
     IMFStreamDescriptor *sd;
     HRESULT hr;
 
     TRACE("%p, %lu, %p.\n", iface, index, selected);
 
-    if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, selected, &sd)))
-        IMFStreamDescriptor_Release(sd);
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
+    {
+        if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, selected, &sd)))
+            IMFStreamDescriptor_Release(sd);
+        IMFPresentationDescriptor_Release(pd);
+    }
+    LeaveCriticalSection(&item->player->cs);
 
     return hr;
 }
@@ -618,28 +700,45 @@ static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD
 static HRESULT WINAPI media_item_SetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL select)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
+    HRESULT hr;
 
     TRACE("%p, %lu, %d.\n", iface, index, select);
 
-    return select ? IMFPresentationDescriptor_SelectStream(item->pd, index) :
-            IMFPresentationDescriptor_DeselectStream(item->pd, index);
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
+    {
+        hr = select ? IMFPresentationDescriptor_SelectStream(pd, index) :
+                IMFPresentationDescriptor_DeselectStream(pd, index);
+        IMFPresentationDescriptor_Release(pd);
+    }
+    LeaveCriticalSection(&item->player->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetStreamAttribute(IMFPMediaItem *iface, DWORD index, REFGUID key,
         PROPVARIANT *value)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
     IMFStreamDescriptor *sd;
     BOOL selected;
     HRESULT hr;
 
     TRACE("%p, %lu, %s, %p.\n", iface, index, debugstr_guid(key), value);
 
-    if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
     {
-        hr = IMFStreamDescriptor_GetItem(sd, key, value);
-        IMFStreamDescriptor_Release(sd);
+        if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, &selected, &sd)))
+        {
+            hr = IMFStreamDescriptor_GetItem(sd, key, value);
+            IMFStreamDescriptor_Release(sd);
+        }
+        IMFPresentationDescriptor_Release(pd);
     }
+    LeaveCriticalSection(&item->player->cs);
 
     return hr;
 }
@@ -648,10 +747,20 @@ static HRESULT WINAPI media_item_GetPresentationAttribute(IMFPMediaItem *iface,
         PROPVARIANT *value)
 {
     struct media_item *item = impl_from_IMFPMediaItem(iface);
+    IMFPresentationDescriptor *pd;
+    HRESULT hr;
 
     TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
 
-    return IMFPresentationDescriptor_GetItem(item->pd, key, value);
+    EnterCriticalSection(&item->player->cs);
+    if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
+    {
+        hr = IMFPresentationDescriptor_GetItem(pd, key, value);
+        IMFPresentationDescriptor_Release(pd);
+    }
+    LeaveCriticalSection(&item->player->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_MEDIAITEM_CHARACTERISTICS *flags)
@@ -664,11 +773,18 @@ static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_ME
 
     *flags = 0;
 
-    if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, &value)))
+    EnterCriticalSection(&item->player->cs);
+    if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
+        hr = MF_E_SHUTDOWN;
+    else
     {
-        *flags = value & (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK |
-                          MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
+        if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, &value)))
+        {
+            *flags = value & (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK
+                    | MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
+        }
     }
+    LeaveCriticalSection(&item->player->cs);
 
     return hr;
 }
@@ -749,7 +865,7 @@ static struct media_item *unsafe_impl_from_IMFPMediaItem(IMFPMediaItem *iface)
     return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
 }
 
-static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, struct media_item **item)
+static HRESULT create_media_item(struct media_player *player, DWORD_PTR user_data, struct media_item **item)
 {
     struct media_item *object;
 
@@ -760,7 +876,7 @@ static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, s
     object->refcount = 1;
     object->user_data = user_data;
     object->player = player;
-    IMFPMediaPlayer_AddRef(object->player);
+    IMFPMediaPlayer_AddRef(&object->player->IMFPMediaPlayer_iface);
 
     *item = object;
 
@@ -1034,7 +1150,7 @@ static HRESULT media_player_create_item_from_url(struct media_player *player,
         return MF_E_INVALIDREQUEST;
     }
 
-    if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
+    if (FAILED(hr = create_media_item(player, user_data, &item)))
         return hr;
 
     if (url && !(item->url = wcsdup(url)))
@@ -1105,7 +1221,7 @@ static HRESULT media_player_create_item_from_object(struct media_player *player,
 
     *ret = NULL;
 
-    if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
+    if (FAILED(hr = create_media_item(player, user_data, &item)))
         return hr;
 
     item->object = object;
@@ -1302,7 +1418,7 @@ static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMedi
         return E_POINTER;
 
     item = unsafe_impl_from_IMFPMediaItem(item_iface);
-    if (item->player != iface)
+    if (item->player != player)
         return E_INVALIDARG;
 
     if (FAILED(hr = media_item_create_topology(player, item, &topology)))
diff --git a/dlls/mfplay/tests/Makefile.in b/dlls/mfplay/tests/Makefile.in
index 4eabb5ae0ab..e790fa3e2ad 100644
--- a/dlls/mfplay/tests/Makefile.in
+++ b/dlls/mfplay/tests/Makefile.in
@@ -1,5 +1,7 @@
 TESTDLL   = mfplay.dll
-IMPORTS   = mfplay user32 uuid mfuuid
+IMPORTS   = mfplay user32 uuid mfuuid mfplat
 
 C_SRCS = \
 	mfplay.c
+
+RC_SRCS = resource.rc
diff --git a/dlls/mfplay/tests/mfplay.c b/dlls/mfplay/tests/mfplay.c
index 44526801c22..c58f34e8b31 100644
--- a/dlls/mfplay/tests/mfplay.c
+++ b/dlls/mfplay/tests/mfplay.c
@@ -42,6 +42,34 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO
         IUnknown_Release(unk);
 }
 
+static WCHAR *load_resource(const WCHAR *name)
+{
+    static WCHAR pathW[MAX_PATH];
+    DWORD written;
+    HANDLE file;
+    HRSRC res;
+    void *ptr;
+
+    GetTempPathW(ARRAY_SIZE(pathW), pathW);
+    lstrcatW(pathW, name);
+
+    file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0,
+                       NULL, CREATE_ALWAYS, 0, 0);
+    ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld.\n",
+       wine_dbgstr_w(pathW), GetLastError());
+
+    res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA);
+    ok(res != 0, "couldn't find resource\n");
+    ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
+    WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res),
+               &written, NULL);
+    ok(written == SizeofResource(GetModuleHandleA(NULL), res),
+       "couldn't write resource\n" );
+    CloseHandle(file);
+
+    return pathW;
+}
+
 static HRESULT WINAPI test_callback_QueryInterface(IMFPMediaPlayerCallback *iface, REFIID riid, void **obj)
 {
     if (IsEqualIID(riid, &IID_IMFPMediaPlayerCallback) ||
@@ -243,8 +271,15 @@ static void test_shutdown(void)
 
 static void test_media_item(void)
 {
-    IMFPMediaPlayer *player;
+    IMFPMediaPlayer *player, *player2;
+    WCHAR *filename, *url;
     IMFPMediaItem *item;
+    DWORD_PTR user_data;
+    PROPVARIANT propvar;
+    unsigned int flags;
+    BOOL ret, selected;
+    IUnknown *object;
+    DWORD count;
     HRESULT hr;
 
     hr = MFPCreateMediaPlayer(NULL, FALSE, 0, NULL, NULL, &player);
@@ -263,6 +298,116 @@ static void test_media_item(void)
     hr = IMFPMediaPlayer_CreateMediaItemFromURL(player, L"url", TRUE, 0, NULL);
     ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
 
+    filename = load_resource(L"test.mp4");
+
+    hr = IMFPMediaPlayer_CreateMediaItemFromURL(player, filename, TRUE, 123, &item);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetMediaPlayer(item, &player2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(player2 == player, "Unexpected player pointer.\n");
+    IMFPMediaPlayer_Release(player2);
+
+    hr = IMFPMediaItem_GetURL(item, &url);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetObject(item, &object);
+    ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetUserData(item, &user_data);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(user_data == 123, "Unexpected user data %#Ix.\n", user_data);
+
+    hr = IMFPMediaItem_SetUserData(item, 124);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_HasVideo(item, &ret, &selected);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(ret && selected, "Unexpected flags.\n");
+
+    hr = IMFPMediaItem_HasAudio(item, &ret, &selected);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_IsProtected(item, &ret);
+    todo_wine
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetDuration(item, &MFP_POSITIONTYPE_100NS, &propvar);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetNumberOfStreams(item, &count);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetStreamSelection(item, 0, &ret);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_SetStreamSelection(item, 0, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetStreamAttribute(item, 0, &MF_SD_LANGUAGE, &propvar);
+    ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetPresentationAttribute(item, &MF_PD_DURATION, &propvar);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetCharacteristics(item, &flags);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* Player shutdown affects created items. */
+    hr = IMFPMediaPlayer_Shutdown(player);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetMediaPlayer(item, &player2);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+    ok(!player2, "Unexpected pointer %p.\n", player2);
+
+    hr = IMFPMediaItem_GetURL(item, &url);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetObject(item, &object);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetUserData(item, &user_data);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(user_data == 124, "Unexpected user data %#Ix.\n", user_data);
+
+    hr = IMFPMediaItem_SetUserData(item, 125);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_HasVideo(item, &ret, &selected);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_HasAudio(item, &ret, &selected);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_IsProtected(item, &ret);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetDuration(item, &MFP_POSITIONTYPE_100NS, &propvar);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetNumberOfStreams(item, &count);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetStreamSelection(item, 0, &ret);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_SetStreamSelection(item, 0, FALSE);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetStreamAttribute(item, 0, &MF_SD_LANGUAGE, &propvar);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetPresentationAttribute(item, &MF_PD_DURATION, &propvar);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    hr = IMFPMediaItem_GetCharacteristics(item, &flags);
+    ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+
+    IMFPMediaItem_Release(item);
+
+    DeleteFileW(filename);
+
     IMFPMediaPlayer_Release(player);
 }
 
diff --git a/dlls/mfplay/tests/resource.rc b/dlls/mfplay/tests/resource.rc
new file mode 100644
index 00000000000..38c4a5f9e01
--- /dev/null
+++ b/dlls/mfplay/tests/resource.rc
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018 Sven Baars
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+
+/* @makedep: test.mp4 */
+test.mp4 RCDATA test.mp4
diff --git a/dlls/mfplay/tests/test.mp4 b/dlls/mfplay/tests/test.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..a5bbca6bbf7692eab047050b79b8ccc83516e6b4
GIT binary patch
literal 1554
zcmZuxeN0nV6u<3bttg}g3M<<3v4A5C7=;cYskS&=aH+Gw(TQ=|2k#+BpKbac6$q26
zgvfMZE^O--6L1NclR1flh8QLw4%rM5#eGC{R2Jv(j|s9(8MANazOwnmo#gk<x#yhw
zyZ4 at R-$e*%%DGx+CF@`ik|L}DS&UP!LkKM^chNNX_cIj9Atd<{DdnJiN*lZEK&*TH
zLUnilE|&Pi#`t<(V2JeCh0xUFbE~$JpP!3QD)e^to at B05Kdu~jt~KuYz}1=h$wy;^
z-(P&iYuL#r*6qMlmYD;w&8gboiuVmim)E`@VY(w}d_`I2ihOP3>WzsJPV$oN<)LWX
zeE-6+iWMz`xA<B45szMa^nqwQ5w>wzrc-v;{3ns3&Hgygab at co_v%sWh^~kxZdgv1
zG$e27=y&X0FwfM)&vJ1wQfF>hX5`>p!|hca@<xwAt#6-gnD>;lG>BPmWrt3nUp`73
z+Yr|+TbnzS=UsV1v;C6gviW|rw)-!S-=bHn;0v1+QGDC}Ia|1D&?ob%jF`h$Wc#Ew
zV;vf3`obS*$vM<kEDwCQ`|#nw>4L6xr#4wnKY06wGT*}wdIn7LW=}zVn#?n%4mVMz
zS*QG<-xMcs%$)a1n<6jX{=IjfF~joa!xMeyYRwY|Cr0Vm>*3w%uu#*`=0;_WapAn$
zU<`El at AbuA79AjpWMkq|c1;#tZJ#~+J(2cx>Nm%BvdmP*5AP|wGW~$TESZLVhn6a1
ztO^C+GL%><v}DW7eXsQJ-HUG|I!ZcwqEv0#Ya at m<t5KG7N5rlo$2IYtr*eGsbj8h0
z?c at jJ8?GH6PW~!_$shUIcJraKf^47ff8>qKKRQs;^7r5rKP{`hCoZsRD*LTIOV>}^
zv}Z#0Dsy%(f4!(s5zT+wRX-W1@{bU&DxT$gcYNB95Wz4GhZ`=WopD!CphZIb3Y&Tt
zN#HB;J~@EE6G4Pb;@qcgDO~ywITu+4q3v9iuqGi&TV#WEm&%fL{&(FFn1q2)5>0U|
zXbo*=;Rh207#4X2E~$c{DoKbWFx1ksXMtOViZ2NB(km#tOR(VMuB70{eJoZOI||7?
zl%2*olCw<Zo^mi$Zbl##Z##(!#x#_R#yMDUJgnMfPYBwQI+iQ7gFVc0?7t1cIX-wf
zaHFt at IfI@MICdeJ7+9Xp2>Ks?)jSUa8_iO<Oo;G!Jey%!2<ZHT2<$>SD4dRa20SkU
zV;68rdYYqx<dOt*;hjTh6eXe7GH{(SlkT#Yax=1Y8M;ip4CY9n)kw{9LK`q0-qUjY
z7J{U}>4bH`mH}`KUjy7ccnDD_0CJHA at _=3toU_OwXamIR7Gqf9{35_wfE7@%h&<3n
zKs;bQARC}!xiSZ6ESNJ5P+CoKB<O7nEod-NqPX>NU0kHoiM#Wkq*n&-SMq0^0~2cD
TJ;x-N6hTeOp(eUDP!ruh^$B~#

literal 0
HcmV?d00001

-- 
2.34.1




More information about the wine-devel mailing list