diff --git a/modules/rostests/winetests/quartz/CMakeLists.txt b/modules/rostests/winetests/quartz/CMakeLists.txt index e73e5310ebe..d74b8c5a6c3 100644 --- a/modules/rostests/winetests/quartz/CMakeLists.txt +++ b/modules/rostests/winetests/quartz/CMakeLists.txt @@ -16,11 +16,11 @@ list(APPEND SOURCE testlist.c) add_idl_headers(quartz_test_idlheader fil_data.idl) -add_executable(quartz_winetest ${SOURCE}) +add_executable(quartz_winetest ${SOURCE} rsrc.rc) target_link_libraries(quartz_winetest uuid) add_dependencies(quartz_winetest dxsdk quartz_test_idlheader) set_module_type(quartz_winetest win32cui) -add_importlibs(quartz_winetest ole32 oleaut32 advapi32 msvcrt kernel32) +add_importlibs(quartz_winetest ole32 oleaut32 advapi32 user32 msvcrt kernel32) if(MSVC) add_importlibs(quartz_winetest ntdll) diff --git a/modules/rostests/winetests/quartz/avisplitter.c b/modules/rostests/winetests/quartz/avisplitter.c index 78ca8b84680..8bafb141574 100644 --- a/modules/rostests/winetests/quartz/avisplitter.c +++ b/modules/rostests/winetests/quartz/avisplitter.c @@ -25,38 +25,8 @@ #include "dshow.h" #include "tlhelp32.h" -static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD); -static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32); -static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32); - static IUnknown *pAviSplitter = NULL; -static int count_threads(void) -{ - THREADENTRY32 te; - int threads; - HANDLE h; - - h = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - te.dwSize = sizeof(te); - - if (h == INVALID_HANDLE_VALUE) - return -1; - - pThread32First(h, &te); - if (te.th32OwnerProcessID == GetCurrentProcessId()) - threads = 1; - else - threads = 0; - - while (pThread32Next(h, &te)) - if (te.th32OwnerProcessID == GetCurrentProcessId()) - ++threads; - - CloseHandle(h); - return threads; -} - static BOOL create_avisplitter(void) { HRESULT hr; @@ -300,45 +270,54 @@ static void test_filesourcefilter(void) } } -static const WCHAR wfile[] = {'t','e','s','t','.','a','v','i',0}; -static const char afile[] = "test.avi"; +static const WCHAR avifile[] = {'t','e','s','t','.','a','v','i',0}; -/* This test doesn't use the quartz filtergraph because it makes it impossible - * to be certain that a thread is really one owned by the avi splitter. - * A lot of the decoder filters will also have their own thread, and Windows' - * filtergraph has a separate thread for start/stop/seeking requests. - * By avoiding the filtergraph altogether and connecting streams directly to - * the null renderer I am sure that this is not the case here. - */ -static void test_threads(void) +static WCHAR *load_resource(const WCHAR *name) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(sizeof(pathW)/sizeof(WCHAR), 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 %d\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 void test_filter_graph(void) { IFileSourceFilter *pfile = NULL; IBaseFilter *preader = NULL, *pavi = NULL; IEnumPins *enumpins = NULL; IPin *filepin = NULL, *avipin = NULL; HRESULT hr; - int baselevel, curlevel, expected; HANDLE file = NULL; PIN_DIRECTION dir = PINDIR_OUTPUT; char buffer[13]; DWORD readbytes; FILTER_STATE state; - /* We need another way of counting threads on NT4. Skip these tests (for now) */ - if (!pCreateToolhelp32Snapshot || !pThread32First || !pThread32Next) - { - win_skip("Needed thread functions are not available (NT4)\n"); - return; - } + WCHAR *filename = load_resource(avifile); - /* Before doing anything (the thread count at the start differs per OS) */ - baselevel = count_threads(); - - file = CreateFileW(wfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, + file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (file == INVALID_HANDLE_VALUE) { - skip("Could not read test file \"%s\", skipping test\n", afile); + skip("Could not read test file \"%s\", skipping test\n", wine_dbgstr_w(filename)); + DeleteFileW(filename); return; } @@ -349,7 +328,8 @@ static void test_threads(void) if (strncmp(buffer, "RIFF", 4) || strcmp(buffer + 8, "AVI ")) { skip("%s is not an avi riff file, not doing the avi splitter test\n", - afile); + wine_dbgstr_w(filename)); + DeleteFileW(filename); return; } @@ -379,10 +359,10 @@ static void test_threads(void) if (hr != S_OK) goto fail; - hr = IFileSourceFilter_Load(pfile, wfile, NULL); + hr = IFileSourceFilter_Load(pfile, filename, NULL); if (hr != S_OK) { - trace("Could not load file\n"); + trace("Could not load file: %08x\n", hr); goto fail; } @@ -409,20 +389,11 @@ static void test_threads(void) if (hr != S_OK) goto fail; - curlevel = count_threads(); - ok(curlevel == baselevel, - "The thread count should be %d not %d\n", baselevel, curlevel); - hr = IPin_Connect(filepin, avipin, NULL); ok(hr == S_OK, "Could not connect: %08x\n", hr); if (hr != S_OK) goto fail; - expected = 1 + baselevel; - curlevel = count_threads(); - ok(curlevel == expected, - "The thread count should be %d not %d\n", expected, curlevel); - IPin_Release(avipin); avipin = NULL; @@ -444,12 +415,17 @@ static void test_threads(void) hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pnull); - ok(hr == S_OK, "Could not create null renderer: %08x\n", hr); - if (hr != S_OK) + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("Null renderer not registered, skipping\n"); break; + } + ok(hr == S_OK, "Could not create null renderer: %08x\n", hr); - IBaseFilter_EnumPins(pnull, &nullenum); - IEnumPins_Next(nullenum, 1, &nullpin, NULL); + hr = IBaseFilter_EnumPins(pnull, &nullenum); + ok(hr == S_OK, "Failed to enum pins, hr %#x.\n", hr); + hr = IEnumPins_Next(nullenum, 1, &nullpin, NULL); + ok(hr == S_OK, "Failed to get next pin, hr %#x.\n", hr); IEnumPins_Release(nullenum); IPin_QueryDirection(nullpin, &dir); @@ -462,7 +438,6 @@ static void test_threads(void) break; } IBaseFilter_Run(pnull, 0); - ++expected; } IPin_Release(avipin); @@ -494,10 +469,6 @@ static void test_threads(void) IBaseFilter_Run(pavi, 0); IBaseFilter_GetState(pavi, INFINITE, &state); - curlevel = count_threads(); - ok(curlevel == expected, - "The thread count should be %d not %d\n", expected, curlevel); - IBaseFilter_Pause(pavi); IBaseFilter_Pause(preader); IBaseFilter_Stop(pavi); @@ -520,7 +491,9 @@ fail2: if (dir == PINDIR_OUTPUT) { PIN_INFO info; - IPin_QueryPinInfo(to, &info); + + hr = IPin_QueryPinInfo(to, &info); + ok(hr == S_OK, "Failed to query pin info, hr %#x.\n", hr); /* Release twice: Once normal, second from the * previous while loop @@ -569,20 +542,11 @@ fail: if (pfile) IFileSourceFilter_Release(pfile); - curlevel = count_threads(); - todo_wine - ok(curlevel == baselevel, - "The thread count should be %d not %d\n", baselevel, curlevel); + DeleteFileW(filename); } START_TEST(avisplitter) { - HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); - - pCreateToolhelp32Snapshot = (void*)GetProcAddress(kernel32, "CreateToolhelp32Snapshot"); - pThread32First = (void*)GetProcAddress(kernel32, "Thread32First"); - pThread32Next = (void*)GetProcAddress(kernel32, "Thread32Next"); - CoInitialize(NULL); if (!create_avisplitter()) @@ -594,7 +558,7 @@ START_TEST(avisplitter) test_query_interface(); test_basefilter(); test_filesourcefilter(); - test_threads(); + test_filter_graph(); release_avisplitter(); diff --git a/modules/rostests/winetests/quartz/filtergraph.c b/modules/rostests/winetests/quartz/filtergraph.c index a8950710115..5fd31072086 100644 --- a/modules/rostests/winetests/quartz/filtergraph.c +++ b/modules/rostests/winetests/quartz/filtergraph.c @@ -42,6 +42,31 @@ typedef struct TestFilterImpl static const WCHAR avifile[] = {'t','e','s','t','.','a','v','i',0}; static const WCHAR mpegfile[] = {'t','e','s','t','.','m','p','g',0}; +static WCHAR *load_resource(const WCHAR *name) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(sizeof(pathW)/sizeof(WCHAR), 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 %d\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 IGraphBuilder *pgraph; static int createfiltergraph(void) @@ -53,7 +78,7 @@ static int createfiltergraph(void) static void test_basic_video(void) { IBasicVideo* pbv; - LONG video_width, video_height; + LONG video_width, video_height, window_width; LONG left, top, width, height; HRESULT hr; @@ -158,6 +183,8 @@ static void test_basic_video(void) ok(height == video_height/4+1, "expected %d, got %d\n", video_height/4+1, height); /* test destination rectangle */ + window_width = max(video_width, GetSystemMetrics(SM_CXMIN) - 2 * GetSystemMetrics(SM_CXFRAME)); + hr = IBasicVideo_GetDestinationPosition(pbv, NULL, NULL, NULL, NULL); ok(hr == E_POINTER, "IBasicVideo_GetDestinationPosition returned: %x\n", hr); hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, NULL, NULL); @@ -168,7 +195,7 @@ static void test_basic_video(void) ok(hr == S_OK, "Cannot get destination position returned: %x\n", hr); ok(left == 0, "expected 0, got %d\n", left); ok(top == 0, "expected 0, got %d\n", top); - todo_wine ok(width == video_width, "expected %d, got %d\n", video_width, width); + todo_wine ok(width == window_width, "expected %d, got %d\n", window_width, width); todo_wine ok(height == video_height, "expected %d, got %d\n", video_height, height); hr = IBasicVideo_SetDestinationPosition(pbv, 0, 0, 0, 0); @@ -328,8 +355,7 @@ static void rungraph(void) hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent); ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr); - /* WaitForSingleObject(hEvent, INFINITE); */ - Sleep(20000); + ok(WaitForSingleObject(hEvent, 2000) == WAIT_OBJECT_0, "Wait failed\n"); hr = IMediaEvent_Release(pme); ok(hr==2, "Releasing mediaevent returned: %x\n", hr); @@ -354,26 +380,39 @@ static void test_render_run(const WCHAR *file) HANDLE h; HRESULT hr; - h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL); + WCHAR *filename = load_resource(file); + + h = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) { skip("Could not read test file %s, skipping test\n", wine_dbgstr_w(file)); + DeleteFileW(filename); return; } CloseHandle(h); if (!createfiltergraph()) + { + DeleteFileW(filename); return; + } - hr = IGraphBuilder_RenderFile(pgraph, file, NULL); - ok(hr == S_OK, "RenderFile returned: %x\n", hr); - rungraph(); + hr = IGraphBuilder_RenderFile(pgraph, filename, NULL); + if (hr == VFW_E_CANNOT_RENDER) + skip("%s: codec not supported; skipping test\n", wine_dbgstr_w(file)); + else + { + ok(hr == S_OK || hr == VFW_S_AUDIO_NOT_RENDERED, "RenderFile failed: %x\n", hr); + rungraph(); + } releasefiltergraph(); /* check reference leaks */ - h = CreateFileW(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + h = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); ok(h != INVALID_HANDLE_VALUE, "CreateFile failed: err=%d\n", GetLastError()); CloseHandle(h); + + DeleteFileW(filename); } static DWORD WINAPI call_RenderFile_multithread(LPVOID lParam) @@ -392,8 +431,9 @@ static DWORD WINAPI call_RenderFile_multithread(LPVOID lParam) CloseHandle(handle); hr = IFilterGraph2_RenderFile(filter_graph, mp3file, NULL); - todo_wine ok(hr == VFW_E_CANNOT_RENDER || /* xp or older */ - hr == VFW_E_NO_TRANSPORT, /* win7 or newer */ + todo_wine ok(hr == VFW_E_CANNOT_RENDER || /* xp or older + DirectX 9 */ + hr == VFW_E_NO_TRANSPORT || /* win7 or newer */ + broken(hr == CLASS_E_CLASSNOTAVAILABLE), /* xp or older + DirectX 8 or older */ "Expected 0x%08x or 0x%08x, returned 0x%08x\n", VFW_E_CANNOT_RENDER, VFW_E_NO_TRANSPORT, hr); DeleteFileW(mp3file); @@ -446,6 +486,7 @@ static void test_render_with_multithread(void) IFilterGraph2_Release(filter_graph); IGraphBuilder_Release(graph_builder); IClassFactory_Release(classfactory); + CloseHandle(thread); CoUninitialize(); return; } diff --git a/modules/rostests/winetests/quartz/rsrc.rc b/modules/rostests/winetests/quartz/rsrc.rc new file mode 100644 index 00000000000..9bea5be3707 --- /dev/null +++ b/modules/rostests/winetests/quartz/rsrc.rc @@ -0,0 +1,27 @@ +/* + * Resource file for quartz tests. + * + * Copyright 2017 Zebediah Figura + * + * 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.avi */ +test.avi RCDATA "test.avi" + +/* @makedep: test.mpg */ +test.mpg RCDATA "test.mpg" diff --git a/modules/rostests/winetests/quartz/test.avi b/modules/rostests/winetests/quartz/test.avi new file mode 100644 index 00000000000..bec304de1d8 Binary files /dev/null and b/modules/rostests/winetests/quartz/test.avi differ diff --git a/modules/rostests/winetests/quartz/test.mpg b/modules/rostests/winetests/quartz/test.mpg new file mode 100644 index 00000000000..7fe379aa3fc Binary files /dev/null and b/modules/rostests/winetests/quartz/test.mpg differ