Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/wmvcore/tests/wmvcore.c | 291 ++++++++++++++++++++++++++++++++++-
1 file changed, 283 insertions(+), 8 deletions(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index eae320c4d2e..ac4239f1d24 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -420,6 +420,14 @@ static const IStreamVtbl stream_vtbl =
stream_Clone,
};
+static void teststream_init(struct teststream *stream, HANDLE file)
+{
+ memset(stream, 0, sizeof(*stream));
+ stream->IStream_iface.lpVtbl = &stream_vtbl;
+ stream->refcount = 1;
+ stream->file = file;
+}
+
static void test_reader_attributes(IWMProfile *profile)
{
WORD size, stream_number, ret_stream_number;
@@ -578,7 +586,7 @@ static void test_sync_reader_streaming(void)
WORD stream_numbers[2], stream_number;
IWMStreamConfig *config, *config2;
bool eos[2] = {0}, first = true;
- struct teststream stream = {{0}};
+ struct teststream stream;
ULONG i, j, count, ref;
IWMSyncReader *reader;
IWMProfile *profile;
@@ -592,9 +600,7 @@ static void test_sync_reader_streaming(void)
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;
+ teststream_init(&stream, file);
hr = WMCreateSyncReader(NULL, 0, &reader);
ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -816,7 +822,7 @@ static void test_sync_reader_types(void)
bool got_video = false, got_audio = false;
DWORD size, ret_size, output_number;
WORD stream_number, stream_number2;
- struct teststream stream = {{0}};
+ struct teststream stream;
IWMStreamConfig *config;
ULONG count, ref, i, j;
IWMSyncReader *reader;
@@ -829,9 +835,7 @@ static void test_sync_reader_types(void)
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;
+ teststream_init(&stream, file);
hr = WMCreateSyncReader(NULL, 0, &reader);
ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -1051,6 +1055,276 @@ static void test_sync_reader_file(void)
ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
}
+struct callback
+{
+ IWMReaderCallback IWMReaderCallback_iface;
+ LONG refcount;
+ HANDLE got_opened, got_stopped, eof_event;
+ unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof;
+};
+
+static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct callback, IWMReaderCallback_iface);
+}
+
+static HRESULT WINAPI callback_QueryInterface(IWMReaderCallback *iface, REFIID iid, void **out)
+{
+ if (winetest_debug > 1)
+ trace("%04x: IWMReaderCallback::QueryInterface(%s)\n", GetCurrentThreadId(), debugstr_guid(iid));
+
+ if (!IsEqualGUID(iid, &IID_IWMReaderCallbackAdvanced) && !IsEqualGUID(iid, &IID_IWMCredentialCallback))
+ ok(0, "Unexpected IID %s.\n", debugstr_guid(iid));
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI callback_AddRef(IWMReaderCallback *iface)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ return InterlockedIncrement(&callback->refcount);
+}
+
+static ULONG WINAPI callback_Release(IWMReaderCallback *iface)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ return InterlockedDecrement(&callback->refcount);
+}
+
+static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS status,
+ HRESULT hr, WMT_ATTR_DATATYPE type, BYTE *value, void *context)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallback::OnStatus(status %u, hr %#x, type %#x, value %p)\n",
+ GetTickCount(), GetCurrentThreadId(), status, hr, type, value);
+
+ switch (status)
+ {
+ case WMT_OPENED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context);
+ SetEvent(callback->got_opened);
+ break;
+
+ case WMT_STARTED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ++callback->got_started;
+ break;
+
+ case WMT_STOPPED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ SetEvent(callback->got_stopped);
+ break;
+
+ case WMT_CLOSED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ todo_wine ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ++callback->got_closed;
+ break;
+
+ case WMT_END_OF_STREAMING:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ ++callback->got_end_of_streaming;
+ break;
+
+ case WMT_EOF:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(callback->got_sample > 0, "Got no samples.\n");
+ ok(callback->got_end_of_streaming == 1, "Got %u WMT_END_OF_STREAMING callbacks.\n",
+ callback->got_end_of_streaming);
+ ++callback->got_eof;
+ SetEvent(callback->eof_event);
+ break;
+
+ /* Not sent when not using IWMReaderAdvanced::DeliverTime(). */
+ case WMT_END_OF_SEGMENT:
+ ok(type == WMT_TYPE_QWORD, "Got type %#x.\n", type);
+ ok(*(QWORD *)value == 3000, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(callback->got_sample > 0, "Got no samples.\n");
+ ok(callback->got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ break;
+
+ default:
+ ok(0, "Unexpected status %#x.\n", status);
+ }
+
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ return S_OK;
+}
+
+static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
+ QWORD time, QWORD duration, DWORD flags, INSSBuffer *sample, void *context)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+ HRESULT hr;
+ DWORD size;
+ BYTE *data;
+
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallback::OnSample(output %u, time %I64u, duration %I64u, flags %#x)\n",
+ GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
+
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+
+ hr = INSSBuffer_GetBufferAndLength(sample, &data, &size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started);
+ ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ ++callback->got_sample;
+
+ return S_OK;
+}
+
+static const IWMReaderCallbackVtbl callback_vtbl =
+{
+ callback_QueryInterface,
+ callback_AddRef,
+ callback_Release,
+ callback_OnStatus,
+ callback_OnSample,
+};
+
+static void callback_init(struct callback *callback)
+{
+ memset(callback, 0, sizeof(*callback));
+ callback->IWMReaderCallback_iface.lpVtbl = &callback_vtbl;
+ callback->refcount = 1;
+ callback->got_opened = CreateEventW(NULL, FALSE, FALSE, NULL);
+ callback->got_stopped = CreateEventW(NULL, FALSE, FALSE, NULL);
+ callback->eof_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+}
+
+static void callback_cleanup(struct callback *callback)
+{
+ CloseHandle(callback->got_opened);
+ CloseHandle(callback->got_stopped);
+ CloseHandle(callback->eof_event);
+}
+
+static void test_async_reader_streaming(void)
+{
+ const WCHAR *filename = load_resource(L"test.wmv");
+ IWMReaderAdvanced2 *advanced;
+ struct teststream stream;
+ struct callback callback;
+ IWMStreamConfig *config;
+ WORD stream_numbers[2];
+ IWMProfile *profile;
+ ULONG i, count, ref;
+ IWMReader *reader;
+ HANDLE file;
+ HRESULT hr;
+ 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());
+
+ teststream_init(&stream, file);
+ callback_init(&callback);
+
+ hr = WMCreateReader(NULL, 0, &reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IWMReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile);
+ IWMReader_QueryInterface(reader, &IID_IWMReaderAdvanced2, (void **)&advanced);
+
+ hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbeef);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr != S_OK)
+ goto out;
+ ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
+ ok(callback.refcount > 1, "Got refcount %d.\n", callback.refcount);
+ ret = WaitForSingleObject(callback.got_opened, 1000);
+ ok(!ret, "Wait timed out.\n");
+
+ count = 0xdeadbeef;
+ hr = IWMReader_GetOutputCount(reader, &count);
+ 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);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ 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 = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ if (hr == S_OK)
+ {
+ /* By default the reader will time itself, and attempt to deliver samples
+ * according to their presentation time. Call DeliverTime with the file
+ * duration in order to request all samples as fast as possible. */
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ret = WaitForSingleObject(callback.eof_event, 20000);
+ ok(!ret, "Wait timed out.\n");
+ ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
+
+ hr = IWMReader_Stop(reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ret = WaitForSingleObject(callback.got_stopped, 5000);
+ ok(!ret, "Wait timed out.\n");
+
+ hr = IWMReader_Stop(reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
+ }
+
+ test_reader_attributes(profile);
+
+ hr = IWMReader_Close(reader);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(callback.got_closed == 1, "Got %u WMT_CLOSED callbacks.\n", callback.got_closed);
+ ok(callback.refcount == 1, "Got outstanding refcount %d.\n", callback.refcount);
+ callback_cleanup(&callback);
+
+out:
+ 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());
+
+ hr = IWMReader_Close(reader);
+ todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
+
+ IWMReaderAdvanced2_Release(advanced);
+ IWMProfile_Release(profile);
+ ref = IWMReader_Release(reader);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+}
+
START_TEST(wmvcore)
{
HRESULT hr;
@@ -1070,6 +1344,7 @@ START_TEST(wmvcore)
test_sync_reader_streaming();
test_sync_reader_types();
test_sync_reader_file();
+ test_async_reader_streaming();
CoUninitialize();
}
--
2.33.0