From: R��mi Bernon rbernon@codeweavers.com
--- dlls/qasf/tests/asfreader.c | 458 ++++++++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+)
diff --git a/dlls/qasf/tests/asfreader.c b/dlls/qasf/tests/asfreader.c index 1fbc64f8e36..2daa9e4c955 100644 --- a/dlls/qasf/tests/asfreader.c +++ b/dlls/qasf/tests/asfreader.c @@ -95,6 +95,264 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO IUnknown_Release(unk); }
+struct test_pin +{ + IPin IPin_iface; + IMemInputPin IMemInputPin_iface; + + DWORD receive_tid; + HANDLE receive_event; + BOOL receive_can_block; + IMemAllocator *allocator; +}; + +static inline struct test_pin *impl_from_IPin(IPin *iface) +{ + return CONTAINING_RECORD(iface, struct test_pin, IPin_iface); +} + +static HRESULT WINAPI test_pin_QueryInterface(IPin *iface, REFIID iid, void **out) +{ + struct test_pin *pin = impl_from_IPin(iface); + + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IPin)) + { + *out = &pin->IPin_iface; + IPin_AddRef(*out); + return S_OK; + } + + if (IsEqualGUID(iid, &IID_IMemInputPin)) + { + *out = &pin->IMemInputPin_iface; + IMemInputPin_AddRef(*out); + return S_OK; + } + + ok(0, "%s not implemented!\n", debugstr_guid(iid)); + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_pin_AddRef(IPin *iface) +{ + return 2; +} + +static ULONG WINAPI test_pin_Release(IPin *iface) +{ + return 1; +} + +static HRESULT WINAPI test_pin_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + return S_OK; +} + +static HRESULT WINAPI test_pin_Disconnect(IPin *iface) +{ + return S_OK; +} + +static HRESULT WINAPI test_pin_ConnectedTo(IPin *iface, IPin **peer) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_QueryPinInfo(IPin *iface, PIN_INFO *info) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_QueryDirection(IPin *iface, PIN_DIRECTION *dir) +{ + *dir = PINDIR_INPUT; + return S_OK; +} + +static HRESULT WINAPI test_pin_QueryId(IPin *iface, WCHAR **id) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_QueryInternalConnections(IPin *iface, IPin **out, ULONG *count) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_EndOfStream(IPin *iface) +{ + return S_OK; +} + +static HRESULT WINAPI test_pin_BeginFlush(IPin *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_EndFlush(IPin * iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_pin_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate) +{ + return S_OK; +} + +static const IPinVtbl test_pin_vtbl = +{ + test_pin_QueryInterface, + test_pin_AddRef, + test_pin_Release, + test_pin_Connect, + test_pin_ReceiveConnection, + test_pin_Disconnect, + test_pin_ConnectedTo, + test_pin_ConnectionMediaType, + test_pin_QueryPinInfo, + test_pin_QueryDirection, + test_pin_QueryId, + test_pin_QueryAccept, + test_pin_EnumMediaTypes, + test_pin_QueryInternalConnections, + test_pin_EndOfStream, + test_pin_BeginFlush, + test_pin_EndFlush, + test_pin_NewSegment, +}; + +static inline struct test_pin *impl_from_IMemInputPin(IMemInputPin *iface) +{ + return CONTAINING_RECORD(iface, struct test_pin, IMemInputPin_iface); +} + +static HRESULT WINAPI test_mem_input_pin_QueryInterface(IMemInputPin *iface, REFIID iid, void **out) +{ + struct test_pin *pin = impl_from_IMemInputPin(iface); + return IPin_QueryInterface(&pin->IPin_iface, iid, out); +} + +static ULONG WINAPI test_mem_input_pin_AddRef(IMemInputPin *iface) +{ + struct test_pin *pin = impl_from_IMemInputPin(iface); + return IPin_AddRef(&pin->IPin_iface); +} + +static ULONG WINAPI test_mem_input_pin_Release(IMemInputPin *iface) +{ + struct test_pin *pin = impl_from_IMemInputPin(iface); + return IPin_Release(&pin->IPin_iface); +} + +static HRESULT WINAPI test_mem_input_pin_GetAllocator(IMemInputPin *iface, + IMemAllocator **allocator) +{ + struct test_pin *impl = impl_from_IMemInputPin(iface); + if (!impl->allocator) + return VFW_E_NO_ALLOCATOR; + IMemAllocator_AddRef((*allocator = impl->allocator)); + return S_OK; +} + +static HRESULT WINAPI test_mem_input_pin_NotifyAllocator(IMemInputPin *iface, + IMemAllocator *allocator, BOOL read_only) +{ + struct test_pin *impl = impl_from_IMemInputPin(iface); + IMemAllocator_AddRef((impl->allocator = allocator)); + return S_OK; +} + +static HRESULT WINAPI test_mem_input_pin_GetAllocatorRequirements(IMemInputPin *iface, + ALLOCATOR_PROPERTIES *props) +{ + memset(props, 0, sizeof(*props)); + return S_OK; +} + +static HRESULT WINAPI test_mem_input_pin_Receive(IMemInputPin *iface, + IMediaSample *sample) +{ + struct test_pin *impl = impl_from_IMemInputPin(iface); + + impl->receive_tid = GetCurrentThreadId(); + SetEvent(impl->receive_event); + + todo_wine + ok(0, "Unexpected call.\n"); + + return S_OK; +} + +static HRESULT WINAPI test_mem_input_pin_ReceiveMultiple(IMemInputPin *iface, + IMediaSample **samples, long count, long *processed) +{ + struct test_pin *impl = impl_from_IMemInputPin(iface); + + impl->receive_tid = GetCurrentThreadId(); + SetEvent(impl->receive_event); + + *processed = count; + return S_OK; +} + +static HRESULT WINAPI test_mem_input_pin_ReceiveCanBlock(IMemInputPin *iface) +{ + struct test_pin *impl = impl_from_IMemInputPin(iface); + return impl->receive_can_block ? S_OK : S_FALSE; +} + +static const IMemInputPinVtbl test_mem_input_pin_vtbl = +{ + test_mem_input_pin_QueryInterface, + test_mem_input_pin_AddRef, + test_mem_input_pin_Release, + test_mem_input_pin_GetAllocator, + test_mem_input_pin_NotifyAllocator, + test_mem_input_pin_GetAllocatorRequirements, + test_mem_input_pin_Receive, + test_mem_input_pin_ReceiveMultiple, + test_mem_input_pin_ReceiveCanBlock, +}; + +static const struct test_pin default_test_pin = +{ + .IPin_iface.lpVtbl = &test_pin_vtbl, + .IMemInputPin_iface.lpVtbl = &test_mem_input_pin_vtbl, +}; + static void test_interfaces(void) { IBaseFilter *filter = create_asf_reader(); @@ -606,6 +864,204 @@ static void test_filter_state(void) ok(!ref, "Got ref %ld.\n", ref); }
+static void test_threading(BOOL receive_can_block) +{ + static const WAVEFORMATEX pcm_format = + { + .wFormatTag = WAVE_FORMAT_MSAUDIO1, + .nChannels = 1, + .nSamplesPerSec = 44100, + .nBlockAlign = 2, + .nAvgBytesPerSec = 88200, + .wBitsPerSample = 16, + .cbSize = 0, + }; + static const VIDEOINFOHEADER nv12_info = + { + .rcSource = {0, 0, 64, 48}, + .rcTarget = {0, 0, 64, 48}, + .bmiHeader = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 64, + .biHeight = 48, + .biPlanes = 1, + .biBitCount = 12, + .biCompression = MAKEFOURCC('N','V','1','2'), + .biSizeImage = 64 * 48 * 3 / 2, + }, + }; + static const MSAUDIO1WAVEFORMAT msaudio1_format = + { + .wfx.wFormatTag = WAVE_FORMAT_MSAUDIO1, + .wfx.nChannels = 1, + .wfx.nSamplesPerSec = 44100, + .wfx.nBlockAlign = 743, + .wfx.nAvgBytesPerSec = 16000, + .wfx.wBitsPerSample = 16, + .wfx.cbSize = sizeof(MSAUDIO1WAVEFORMAT) - sizeof(WAVEFORMATEX), + .wEncodeOptions = 1, + }; + static const VIDEOINFOHEADER2 wmv1_info2 = + { + .rcSource = {0, 0, 64, 48}, + .rcTarget = {0, 0, 64, 48}, + .dwBitRate = 189464, + .dwPictAspectRatioX = 64, + .dwPictAspectRatioY = 48, + .bmiHeader = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 64, + .biHeight = 48, + .biPlanes = 1, + .biBitCount = 24, + .biCompression = MAKEFOURCC('W','M','V','1'), + .biSizeImage = 64 * 48 * 3, + }, + }; + AM_MEDIA_TYPE audio_mt = + { + .majortype = MEDIATYPE_Audio, + .subtype = MEDIASUBTYPE_MSAUDIO1, + .bFixedSizeSamples = TRUE, + .lSampleSize = 743, + .formattype = FORMAT_WaveFormatEx, + .cbFormat = sizeof(MSAUDIO1WAVEFORMAT), + .pbFormat = (BYTE *)&msaudio1_format, + }; + AM_MEDIA_TYPE video_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = WMMEDIASUBTYPE_WMV1, + .formattype = FORMAT_VideoInfo2, + .bTemporalCompression = TRUE, + .cbFormat = sizeof(VIDEOINFOHEADER2), + .pbFormat = (BYTE *)&wmv1_info2, + }; + AM_MEDIA_TYPE wine_audio_mt = + { + .majortype = MEDIATYPE_Audio, + .subtype = MEDIASUBTYPE_PCM, + .bFixedSizeSamples = TRUE, + .formattype = FORMAT_WaveFormatEx, + .cbFormat = sizeof(WAVEFORMATEX), + .pbFormat = (BYTE *)&pcm_format, + }; + AM_MEDIA_TYPE wine_video_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_NV12, + .formattype = FORMAT_VideoInfo, + .bTemporalCompression = TRUE, + .cbFormat = sizeof(VIDEOINFOHEADER), + .pbFormat = (BYTE *)&nv12_info, + }; + + struct test_pin audio_pin = default_test_pin, video_pin = default_test_pin; + const WCHAR *filename = load_resource(L"test.wmv"); + IBaseFilter *filter = create_asf_reader(); + IFileSourceFilter *file_source; + IEnumPins *enum_pins; + IFilterGraph *graph; + FILTER_STATE state; + IPin *pins[4]; + HRESULT hr; + DWORD ret; + ULONG ref; + + winetest_push_context("%u", !!receive_can_block); + + video_pin.receive_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!video_pin.receive_event, "CreateEventW failed, error %lu\n", GetLastError()); + audio_pin.receive_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!audio_pin.receive_event, "CreateEventW failed, error %lu\n", GetLastError()); + + video_pin.receive_can_block = receive_can_block; + audio_pin.receive_can_block = receive_can_block; + + hr = IBaseFilter_QueryInterface(filter, &IID_IFileSourceFilter, (void **)&file_source); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFileSourceFilter_Load(file_source, filename, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IFileSourceFilter_Release(file_source); + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterGraph, (void **)&graph); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFilterGraph_AddFilter(graph, filter, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IFilterGraph_Release(graph); + + hr = IBaseFilter_EnumPins(filter, &enum_pins); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IEnumPins_Next(enum_pins, 1, pins, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IPin_Connect(pins[0], &video_pin.IPin_iface, &video_mt); + todo_wine + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr != S_OK) + { + hr = IPin_Connect(pins[0], &video_pin.IPin_iface, &wine_video_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + IPin_Release(pins[0]); + hr = IEnumPins_Next(enum_pins, 1, pins, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IPin_Connect(pins[0], &audio_pin.IPin_iface, &audio_mt); + todo_wine + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr != S_OK) + { + hr = IPin_Connect(pins[0], &audio_pin.IPin_iface, &wine_audio_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + IPin_Release(pins[0]); + hr = IEnumPins_Next(enum_pins, 1, pins, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + IEnumPins_Release(enum_pins); + + hr = IBaseFilter_Run(filter, GetTickCount() * 10000); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IBaseFilter_GetState(filter, INFINITE, &state); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(state == State_Running, "Got state %#x.\n", state); + + ret = WaitForSingleObject(video_pin.receive_event, 500); + ok(!ret, "Wait timed out.\n"); + ret = WaitForSingleObject(audio_pin.receive_event, 500); + ok(!ret, "Wait timed out.\n"); + + ok(video_pin.receive_tid != GetCurrentThreadId(), "got wrong thread\n"); + ok(audio_pin.receive_tid != GetCurrentThreadId(), "got wrong thread\n"); + if (receive_can_block) + { + todo_wine + ok(audio_pin.receive_tid != video_pin.receive_tid, "got wrong thread\n"); + } + else + ok(audio_pin.receive_tid == video_pin.receive_tid, "got wrong thread\n"); + + hr = IBaseFilter_Stop(filter); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IBaseFilter_GetState(filter, INFINITE, &state); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(state == State_Stopped, "Got state %#x.\n", state); + + ref = IBaseFilter_Release(filter); + ok(!ref, "Got ref %ld.\n", ref); + + if (video_pin.allocator) + IMemAllocator_Release(video_pin.allocator); + if (audio_pin.allocator) + IMemAllocator_Release(audio_pin.allocator); + + CloseHandle(video_pin.receive_event); + CloseHandle(audio_pin.receive_event); + + winetest_pop_context(); +} + START_TEST(asfreader) { CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -614,6 +1070,8 @@ START_TEST(asfreader) test_aggregation(); test_filesourcefilter(); test_filter_state(); + test_threading(FALSE); + test_threading(TRUE);
CoUninitialize(); }