Signed-off-by: Zebediah Figura zfigura@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..2a337648761 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, 1000); + 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, 1000); + 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(); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wmvcore/tests/wmvcore.c | 254 ++++++++++++++++++++++++++++++++++- 1 file changed, 253 insertions(+), 1 deletion(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 2a337648761..8f4cc6eb482 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -34,7 +34,17 @@ HRESULT WINAPI WMCreateWriterPriv(IWMWriter **writer);
static BOOL compare_media_types(const WM_MEDIA_TYPE *a, const WM_MEDIA_TYPE *b) { - return !memcmp(a, b, offsetof(WM_MEDIA_TYPE, pbFormat)) + /* We can't use memcmp(), because WM_MEDIA_TYPE has a hole, which sometimes + * contains junk. */ + + return IsEqualGUID(&a->majortype, &b->majortype) + && IsEqualGUID(&a->subtype, &b->subtype) + && a->bFixedSizeSamples == b->bFixedSizeSamples + && a->bTemporalCompression == b->bTemporalCompression + && a->lSampleSize == b->lSampleSize + && IsEqualGUID(&a->formattype, &b->formattype) + && a->pUnk == b->pUnk + && a->cbFormat == b->cbFormat && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); }
@@ -1325,6 +1335,247 @@ out: ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_async_reader_types(void) +{ + char mt_buffer[2000], mt2_buffer[2000]; + const WCHAR *filename = load_resource(L"test.wmv"); + IWMOutputMediaProps *output_props, *output_props2; + WM_MEDIA_TYPE *mt2 = (WM_MEDIA_TYPE *)mt2_buffer; + WM_MEDIA_TYPE *mt = (WM_MEDIA_TYPE *)mt_buffer; + bool got_video = false, got_audio = false; + DWORD size, ret_size, output_number; + IWMReaderAdvanced2 *advanced; + struct teststream stream; + struct callback callback; + IWMStreamConfig *config; + ULONG count, ref, i, j; + IWMProfile *profile; + IWMReader *reader; + GUID majortype; + 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"); + + for (i = 0; i < 2; ++i) + { + winetest_push_context("Stream %u", i); + + hr = IWMProfile_GetStream(profile, i, &config); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMStreamConfig_GetStreamType(config, &majortype); + ok(hr == S_OK, "Got hr %#x.\n", hr); + if (!i) + ok(IsEqualGUID(&majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&majortype)); + else + ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype)); + + ref = IWMStreamConfig_Release(config); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + winetest_pop_context(); + } + + for (i = 0; i < 2; ++i) + { + winetest_push_context("Output %u", i); + output_number = i; + + hr = IWMReader_GetOutputProps(reader, output_number, &output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + ret_size = sizeof(mt_buffer); + hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + majortype = mt->majortype; + if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) + { + got_audio = true; + check_audio_type(mt); + + /* R.U.S.E. enumerates all audio formats, picks the first one it + * likes, and then sets the wrong stream to that format. + * Accordingly we need the first audio format to be the default + * format, and we need it to be a format that the game is happy + * with. In particular it has to be PCM. */ + + hr = IWMReader_GetOutputFormat(reader, output_number, 0, &output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + if (hr == S_OK) + { + ret_size = sizeof(mt2_buffer); + hr = IWMOutputMediaProps_GetMediaType(output_props, mt2, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + /* The sample size might differ. */ + mt2->lSampleSize = mt->lSampleSize; + ok(compare_media_types(mt, mt2), "Media types didn't match.\n"); + } + } + else + { + ok(IsEqualGUID(&majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&majortype)); + got_video = true; + check_video_type(mt); + } + + count = 0; + hr = IWMReader_GetOutputFormatCount(reader, output_number, &count); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(count > 0, "Got count %u.\n", count); + + for (j = 0; j < count; ++j) + { + winetest_push_context("Format %u", j); + + hr = IWMReader_GetOutputFormat(reader, output_number, j, &output_props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMReader_GetOutputFormat(reader, output_number, j, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n"); + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + size = 0xdeadbeef; + hr = IWMOutputMediaProps_GetMediaType(output_props, NULL, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(size != 0xdeadbeef && size >= sizeof(WM_MEDIA_TYPE), "Got size %u.\n", size); + + ret_size = size - 1; + hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); + ok(hr == ASF_E_BUFFERTOOSMALL, "Got hr %#x.\n", hr); + ok(ret_size == size, "Expected size %u, got %u.\n", size, ret_size); + + ret_size = sizeof(mt_buffer); + memset(mt_buffer, 0xcc, sizeof(mt_buffer)); + hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(ret_size == size, "Expected size %u, got %u.\n", size, ret_size); + ok(size == sizeof(WM_MEDIA_TYPE) + mt->cbFormat, "Expected size %u, got %u.\n", + sizeof(WM_MEDIA_TYPE) + mt->cbFormat, size); + + ok(IsEqualGUID(&mt->majortype, &majortype), "Got major type %s.\n", debugstr_guid(&mt->majortype)); + + if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)) + check_audio_type(mt); + else + check_video_type(mt); + + hr = IWMReader_SetOutputProps(reader, output_number, output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr != S_OK) + { + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + winetest_pop_context(); + continue; + } + hr = IWMReader_SetOutputProps(reader, 1 - output_number, output_props); + if (!i) + ok(hr == NS_E_INCOMPATIBLE_FORMAT /* win < 8, win10 1507-1809 */ + || hr == ASF_E_BADMEDIATYPE /* win8, win10 1909+ */, "Got hr %#x.\n", hr); + else + todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr); + hr = IWMReader_SetOutputProps(reader, 2, output_props); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IWMReader_GetOutputProps(reader, output_number, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n"); + + ret_size = sizeof(mt2_buffer); + hr = IWMOutputMediaProps_GetMediaType(output_props2, mt2, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(mt, mt2), "Media types didn't match.\n"); + + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + winetest_pop_context(); + } + + hr = IWMReader_GetOutputFormat(reader, output_number, count, &output_props); + todo_wine ok(hr == NS_E_INVALID_OUTPUT_FORMAT, "Got hr %#x.\n", hr); + + hr = IWMReader_GetOutputProps(reader, output_number, &output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + if (hr == S_OK) + { + hr = IWMReader_GetOutputProps(reader, output_number, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n"); + + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + } + + winetest_pop_context(); + } + + todo_wine ok(got_audio, "No audio stream was enumerated.\n"); + todo_wine ok(got_video, "No video stream was enumerated.\n"); + + count = 0xdeadbeef; + hr = IWMReader_GetOutputFormatCount(reader, 2, &count); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(count == 0xdeadbeef, "Got count %#x.\n", count); + + output_props = (void *)0xdeadbeef; + hr = IWMReader_GetOutputProps(reader, 2, &output_props); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props); + + output_props = (void *)0xdeadbeef; + hr = IWMReader_GetOutputFormat(reader, 2, 0, &output_props); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props); + +out: + IWMReaderAdvanced2_Release(advanced); + IWMProfile_Release(profile); + ref = IWMReader_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; @@ -1345,6 +1596,7 @@ START_TEST(wmvcore) test_sync_reader_types(); test_sync_reader_file(); test_async_reader_streaming(); + test_async_reader_types();
CoUninitialize(); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_asyncreader.c | 58 +++++++++++++++++++++++++---- dlls/wmvcore/tests/wmvcore.c | 21 +++++------ 2 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 4fec89a2100..3448e156fa0 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -31,8 +31,20 @@ struct async_reader IWMReaderStreamClock IWMReaderStreamClock_iface; IWMReaderTypeNegotiation IWMReaderTypeNegotiation_iface; IReferenceClock IReferenceClock_iface; + + IWMReaderCallback *callback; + void *context; };
+static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) +{ + static const DWORD zero; + + IWMReaderCallback_AddRef(reader->callback = callback); + reader->context = context; + IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); +} + static struct async_reader *impl_from_IWMReader(IWMReader *iface) { return CONTAINING_RECORD(iface, struct async_reader, IWMReader_iface); @@ -68,9 +80,26 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url, IWMReade
static HRESULT WINAPI WMReader_Close(IWMReader *iface) { - struct async_reader *This = impl_from_IWMReader(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + struct async_reader *reader = impl_from_IWMReader(iface); + static const DWORD zero; + HRESULT hr; + + TRACE("reader %p.\n", reader); + + EnterCriticalSection(&reader->reader.cs); + + hr = wm_reader_close(&reader->reader); + if (reader->callback) + { + IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + IWMReaderCallback_Release(reader->callback); + } + reader->callback = NULL; + + LeaveCriticalSection(&reader->reader.cs); + + return hr; }
static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *outputs) @@ -427,12 +456,21 @@ static HRESULT WINAPI WMReaderAdvanced2_StopBuffering(IWMReaderAdvanced6 *iface) return E_NOTIMPL; }
-static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface, IStream *stream, - IWMReaderCallback *callback, void *context) +static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface, + IStream *stream, IWMReaderCallback *callback, void *context) { - struct async_reader *This = impl_from_IWMReaderAdvanced6(iface); - FIXME("(%p)->(%p %p %p)\n", This, stream, callback, context); - return E_NOTIMPL; + struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface); + HRESULT hr; + + TRACE("reader %p, stream %p, callback %p, context %p.\n", reader, stream, callback, context); + + EnterCriticalSection(&reader->reader.cs); + + if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream))) + open_stream(reader, callback, context); + + LeaveCriticalSection(&reader->reader.cs); + return hr; }
static HRESULT WINAPI WMReaderAdvanced3_StopNetStreaming(IWMReaderAdvanced6 *iface) @@ -1256,6 +1294,10 @@ static void async_reader_destroy(struct wm_reader *iface) TRACE("reader %p.\n", reader);
wm_reader_close(&reader->reader); + + if (reader->callback) + IWMReaderCallback_Release(reader->callback); + wm_reader_cleanup(&reader->reader); free(reader); } diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 8f4cc6eb482..9d9c4a571f2 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1255,9 +1255,7 @@ static void test_async_reader_streaming(void) 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(hr == S_OK, "Got hr %#x.\n", hr); 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); @@ -1315,19 +1313,18 @@ static void test_async_reader_streaming(void) 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(hr == S_OK, "Got hr %#x.\n", hr); + 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); + ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
IWMReaderAdvanced2_Release(advanced); IWMProfile_Release(profile); @@ -1368,9 +1365,7 @@ static void test_async_reader_types(void) 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(hr == S_OK, "Got hr %#x.\n", hr); 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); @@ -1403,6 +1398,11 @@ static void test_async_reader_types(void)
hr = IWMReader_GetOutputProps(reader, output_number, &output_props); todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr != S_OK) + { + winetest_pop_context(); + continue; + }
ret_size = sizeof(mt_buffer); hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); @@ -1564,7 +1564,6 @@ static void test_async_reader_types(void) todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props);
-out: IWMReaderAdvanced2_Release(advanced); IWMProfile_Release(profile); ref = IWMReader_Release(reader);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_asyncreader.c | 12 ++++++------ dlls/wmvcore/tests/wmvcore.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 3448e156fa0..8caf21a2de0 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -102,15 +102,15 @@ static HRESULT WINAPI WMReader_Close(IWMReader *iface) return hr; }
-static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *outputs) +static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *count) { - struct async_reader *This = impl_from_IWMReader(iface); - FIXME("(%p)->(%p)\n", This, outputs); + struct async_reader *reader = impl_from_IWMReader(iface);
- if(!outputs) - return E_INVALIDARG; + TRACE("reader %p, count %p.\n", reader, count);
- *outputs = 0; + EnterCriticalSection(&reader->reader.cs); + *count = reader->reader.stream_count; + LeaveCriticalSection(&reader->reader.cs); return S_OK; }
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 9d9c4a571f2..553f79656d6 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1264,7 +1264,7 @@ static void test_async_reader_streaming(void) 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); + ok(count == 2, "Got count %u.\n", count);
for (i = 0; i < 2; ++i) {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_asyncreader.c | 10 +++++---- dlls/wmvcore/tests/wmvcore.c | 32 +++++++++++------------------ 2 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 8caf21a2de0..6771b590a71 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -114,11 +114,13 @@ static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *count) return S_OK; }
-static HRESULT WINAPI WMReader_GetOutputProps(IWMReader *iface, DWORD output_num, IWMOutputMediaProps **output) +static HRESULT WINAPI WMReader_GetOutputProps(IWMReader *iface, DWORD output, IWMOutputMediaProps **props) { - struct async_reader *This = impl_from_IWMReader(iface); - FIXME("(%p)->(%u %p)\n", This, output_num, output); - return E_NOTIMPL; + struct async_reader *reader = impl_from_IWMReader(iface); + + TRACE("reader %p, output %u, props %p.\n", reader, output, props); + + return wm_reader_get_output_props(&reader->reader, output, props); }
static HRESULT WINAPI WMReader_SetOutputProps(IWMReader *iface, DWORD output_num, IWMOutputMediaProps *output) diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 553f79656d6..148b4f5f373 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1397,12 +1397,7 @@ static void test_async_reader_types(void) output_number = i;
hr = IWMReader_GetOutputProps(reader, output_number, &output_props); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr != S_OK) - { - winetest_pop_context(); - continue; - } + ok(hr == S_OK, "Got hr %#x.\n", hr);
ret_size = sizeof(mt_buffer); hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); @@ -1529,25 +1524,22 @@ static void test_async_reader_types(void) todo_wine ok(hr == NS_E_INVALID_OUTPUT_FORMAT, "Got hr %#x.\n", hr);
hr = IWMReader_GetOutputProps(reader, output_number, &output_props); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- if (hr == S_OK) - { - hr = IWMReader_GetOutputProps(reader, output_number, &output_props2); - ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(output_props2 != output_props, "Expected different objects.\n"); + hr = IWMReader_GetOutputProps(reader, output_number, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n");
- ref = IWMOutputMediaProps_Release(output_props2); - ok(!ref, "Got outstanding refcount %d.\n", ref); - ref = IWMOutputMediaProps_Release(output_props); - ok(!ref, "Got outstanding refcount %d.\n", ref); - } + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref);
winetest_pop_context(); }
- todo_wine ok(got_audio, "No audio stream was enumerated.\n"); - todo_wine ok(got_video, "No video stream was enumerated.\n"); + ok(got_audio, "No audio stream was enumerated.\n"); + ok(got_video, "No video stream was enumerated.\n");
count = 0xdeadbeef; hr = IWMReader_GetOutputFormatCount(reader, 2, &count); @@ -1556,7 +1548,7 @@ static void test_async_reader_types(void)
output_props = (void *)0xdeadbeef; hr = IWMReader_GetOutputProps(reader, 2, &output_props); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props);
output_props = (void *)0xdeadbeef;