From 42d0d8d9071c8feb89a5ca798960123a3564de60 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 25 Oct 2021 10:54:57 -0500 Subject: [PATCH] wmvcore/tests: Add some basic tests for streaming with the synchronous reader. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/wmvcore/tests/Makefile.in | 3 + dlls/wmvcore/tests/rsrc.rc | 25 +++ dlls/wmvcore/tests/test.wmv | Bin 0 -> 45663 bytes dlls/wmvcore/tests/wmvcore.c | 392 +++++++++++++++++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 dlls/wmvcore/tests/rsrc.rc create mode 100644 dlls/wmvcore/tests/test.wmv diff --git a/dlls/wmvcore/tests/Makefile.in b/dlls/wmvcore/tests/Makefile.in index 8054ddd0a2e..856e02d45d5 100644 --- a/dlls/wmvcore/tests/Makefile.in +++ b/dlls/wmvcore/tests/Makefile.in @@ -3,3 +3,6 @@ IMPORTS = ole32 wmvcore C_SRCS = \ wmvcore.c + +RC_SRCS = \ + rsrc.rc diff --git a/dlls/wmvcore/tests/rsrc.rc b/dlls/wmvcore/tests/rsrc.rc new file mode 100644 index 00000000000..cd642ceb1d0 --- /dev/null +++ b/dlls/wmvcore/tests/rsrc.rc @@ -0,0 +1,25 @@ +/* + * Resource file for wmvcore tests + * + * Copyright 2021 Zebediah Figura for CodeWeavers + * + * 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" + +/* ffmpeg -f lavfi -i smptebars -f lavfi -i "sine=frequency=700" -t 2.0 -f asf -vcodec wmv1 -vf scale=64x48 -acodec wmav1 test.wmv */ +/* @makedep: test.wmv */ +test.wmv RCDATA "test.wmv" diff --git a/dlls/wmvcore/tests/test.wmv b/dlls/wmvcore/tests/test.wmv new file mode 100644 index 0000000000000000000000000000000000000000..fa953771cd31213ec24bef9000127125047e0623 GIT binary patch literal 45663 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 literal 0 HcmV?d00001 diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 79bcfef0d52..dd1e3027d57 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1,6 +1,7 @@ /* * Copyright 2017 Alistair Leslie-Hughes * Copyright 2019 Vijay Kiran Kamuju + * Copyright 2021 Zebediah Figura for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,15 +17,43 @@ * 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 #define COBJMACROS #define WIN32_LEAN_AND_MEAN #include "initguid.h" #include "wmsdk.h" +#include "wmsecure.h" #include "wine/test.h" HRESULT WINAPI WMCreateWriterPriv(IWMWriter **writer); +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); + wcscat(pathW, name); + + file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s, error %u.\n", + wine_dbgstr_w(pathW), GetLastError()); + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok(!!res, "Failed to load resource, error %u.\n", GetLastError()); + ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource.\n"); + CloseHandle(file); + + return pathW; +} + #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) static HRESULT check_interface_(unsigned int line, void *iface, REFIID riid, BOOL supported) { @@ -225,6 +254,368 @@ static void test_iscontentprotected(void) ok(drm == FALSE, "got %0dx\n", drm); } +struct teststream +{ + IStream IStream_iface; + LONG refcount; + HANDLE file; +}; + +static struct teststream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct teststream, IStream_iface); +} + +static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID iid, void **out) +{ + if (winetest_debug > 1) + trace("%04x: IStream::QueryInterface(%s)\n", GetCurrentThreadId(), debugstr_guid(iid)); + + if (!IsEqualGUID(iid, &IID_IWMGetSecureChannel) && !IsEqualGUID(iid, &IID_IWMIStreamProps)) + ok(0, "Unexpected IID %s.\n", debugstr_guid(iid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI stream_AddRef(IStream *iface) +{ + struct teststream *stream = impl_from_IStream(iface); + + return InterlockedIncrement(&stream->refcount); +} + +static ULONG WINAPI stream_Release(IStream *iface) +{ + struct teststream *stream = impl_from_IStream(iface); + + return InterlockedDecrement(&stream->refcount); +} + +static HRESULT WINAPI stream_Read(IStream *iface, void *data, ULONG size, ULONG *ret_size) +{ + struct teststream *stream = impl_from_IStream(iface); + + if (winetest_debug > 2) + trace("%04x: IStream::Read(size %u)\n", GetCurrentThreadId(), size); + + ok(size > 0, "Got zero size.\n"); + ok(!!ret_size, "Got NULL ret_size pointer.\n"); + if (!ReadFile(stream->file, data, size, ret_size, NULL)) + return HRESULT_FROM_WIN32(GetLastError()); + return S_OK; +} + +static HRESULT WINAPI stream_Write(IStream *iface, const void *data, ULONG size, ULONG *ret_size) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD method, ULARGE_INTEGER *ret_offset) +{ + struct teststream *stream = impl_from_IStream(iface); + LARGE_INTEGER size; + + if (winetest_debug > 2) + trace("%04x: IStream::Seek(offset %I64u, method %#x)\n", GetCurrentThreadId(), offset.QuadPart, method); + + GetFileSizeEx(stream->file, &size); + ok(offset.QuadPart < size.QuadPart, "Expected offset less than size %I64u, got %I64u.\n", + size.QuadPart, offset.QuadPart); + + ok(method == STREAM_SEEK_SET, "Got method %#x.\n", method); + ok(!ret_offset, "Got unexpected ret_offset pointer %p\n", ret_offset); + + if (!SetFilePointerEx(stream->file, offset, &offset, method)) + return HRESULT_FROM_WIN32(GetLastError()); + return S_OK; +} + +static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *read_size, ULARGE_INTEGER *write_size) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Revert(IStream *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) +{ + struct teststream *stream = impl_from_IStream(iface); + LARGE_INTEGER size; + + if (winetest_debug > 1) + trace("%04x: IStream::Stat(flags %#x)\n", GetCurrentThreadId(), flags); + + ok(flags == STATFLAG_NONAME, "Got flags %#x.\n", flags); + + stat->type = 0xdeadbeef; + GetFileSizeEx(stream->file, &size); + stat->cbSize.QuadPart = size.QuadPart; + stat->grfMode = 0; + stat->grfLocksSupported = TRUE; + + return S_OK; +} + +static HRESULT WINAPI stream_Clone(IStream *iface, IStream **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IStreamVtbl stream_vtbl = +{ + stream_QueryInterface, + stream_AddRef, + stream_Release, + stream_Read, + stream_Write, + stream_Seek, + stream_SetSize, + stream_CopyTo, + stream_Commit, + stream_Revert, + stream_LockRegion, + stream_UnlockRegion, + stream_Stat, + stream_Clone, +}; + +static void test_sync_reader_streaming(void) +{ + DWORD size, flags, output_number, expect_output_number; + const WCHAR *filename = load_resource(L"test.wmv"); + WORD stream_numbers[2], stream_number; + IWMStreamConfig *config, *config2; + bool eos[2] = {0}, first = true; + struct teststream stream = {0}; + ULONG i, j, count, ref; + IWMSyncReader *reader; + IWMProfile *profile; + QWORD pts, duration; + INSSBuffer *sample; + HANDLE file; + HRESULT hr; + BYTE *data; + BOOL ret; + + file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u.\n", debugstr_w(file), GetLastError()); + + stream.IStream_iface.lpVtbl = &stream_vtbl; + stream.refcount = 1; + stream.file = file; + + hr = WMCreateSyncReader(NULL, 0, &reader); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IWMSyncReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile); + + hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount); + + hr = IWMProfile_GetStreamCount(profile, NULL); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + count = 0xdeadbeef; + hr = IWMProfile_GetStreamCount(profile, &count); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(count == 2, "Got count %u.\n", count); + + count = 0xdeadbeef; + hr = IWMSyncReader_GetOutputCount(reader, &count); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(count == 2, "Got count %u.\n", count); + + for (i = 0; i < 2; ++i) + { + hr = IWMProfile_GetStream(profile, i, &config); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + if (hr == S_OK) + { + hr = IWMProfile_GetStream(profile, i, &config2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(config2 != config, "Expected different objects.\n"); + ref = IWMStreamConfig_Release(config2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + stream_numbers[i] = 0xdead; + hr = IWMStreamConfig_GetStreamNumber(config, &stream_numbers[i]); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(stream_numbers[i] == i + 1, "Got stream number %u.\n", stream_numbers[i]); + + ref = IWMStreamConfig_Release(config); + ok(!ref, "Got outstanding refcount %d.\n", ref); + } + + hr = IWMSyncReader_SetReadStreamSamples(reader, stream_numbers[i], FALSE); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + } + + hr = IWMProfile_GetStream(profile, 2, &config); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + while (!eos[0] || !eos[1]) + { + for (j = 0; j < 2; ++j) + { + stream_number = pts = duration = flags = output_number = 0xdeadbeef; + hr = IWMSyncReader_GetNextSample(reader, stream_numbers[j], &sample, + &pts, &duration, &flags, &output_number, &stream_number); + if (first) + todo_wine ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr); + else if (eos[j]) + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + else + ok(hr == S_OK || hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + if (hr == S_OK) + { + hr = INSSBuffer_GetBufferAndLength(sample, &data, &size); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = INSSBuffer_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IWMSyncReader_GetOutputNumberForStream(reader, stream_number, &expect_output_number); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_number == expect_output_number, "Expected output number %u, got %u.\n", + expect_output_number, output_number); + } + else + { + ok(pts == 0xdeadbeef, "Got PTS %I64u.\n", pts); + ok(duration == 0xdeadbeef, "Got duration %I64u.\n", duration); + ok(flags == 0xdeadbeef, "Got flags %#x.\n", flags); + ok(output_number == 0xdeadbeef, "Got output number %u.\n", output_number); + eos[j] = true; + } + + todo_wine ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n", + stream_numbers[j], stream_number); + } + first = false; + } + + hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, + &pts, &duration, &flags, NULL, NULL); + todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample, + &pts, &duration, &flags, NULL, NULL); + todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_SetRange(reader, 0, 0); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, &pts, &duration, &flags, NULL, NULL); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + INSSBuffer_Release(sample); + + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, NULL); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, &output_number, NULL); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + INSSBuffer_Release(sample); + + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, &stream_number); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) + INSSBuffer_Release(sample); + + for (;;) + { + stream_number = pts = duration = flags = output_number = 0xdeadbeef; + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, + &pts, &duration, &flags, &output_number, &stream_number); + todo_wine ok(hr == S_OK || hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + if (hr == S_OK) + { + hr = INSSBuffer_GetBufferAndLength(sample, &data, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = INSSBuffer_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + } + else + { + ok(pts == 0xdeadbeef, "Got PTS %I64u.\n", pts); + ok(duration == 0xdeadbeef, "Got duration %I64u.\n", duration); + ok(flags == 0xdeadbeef, "Got flags %#x.\n", flags); + ok(output_number == 0xdeadbeef, "Got output number %u.\n", output_number); + ok(stream_number == 0xbeef, "Got stream number %u.\n", stream_number); + break; + } + } + + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, + &pts, &duration, &flags, NULL, &stream_number); + todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, + &pts, &duration, &flags, NULL, NULL); + todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample, + &pts, &duration, &flags, NULL, NULL); + todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_Close(reader); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_Close(reader); + todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr); + + ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount); + + SetFilePointer(stream.file, 0, NULL, FILE_BEGIN); + hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount); + + IWMProfile_Release(profile); + ref = IWMSyncReader_Release(reader); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount); + CloseHandle(stream.file); + ret = DeleteFileW(filename); + ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError()); +} + START_TEST(wmvcore) { HRESULT hr; @@ -241,6 +632,7 @@ START_TEST(wmvcore) test_WMCreateWriterPriv(); test_urlextension(); test_iscontentprotected(); + test_sync_reader_streaming(); CoUninitialize(); }