From: "Gabriel Ivăncescu" Subject: [PATCH 1/2] qedit/tests: Check the Sample Grabber's buffer during and after flushing. Message-Id: <5def2d7ec5f6cc93efb5266853c21cc81501ba4b.1603818649.git.gabrielopcode@gmail.com> Date: Tue, 27 Oct 2020 19:13:32 +0200 Signed-off-by: Gabriel Ivăncescu --- dlls/qedit/tests/samplegrabber.c | 234 +++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/dlls/qedit/tests/samplegrabber.c b/dlls/qedit/tests/samplegrabber.c index 8e68e3e..e66180f 100644 --- a/dlls/qedit/tests/samplegrabber.c +++ b/dlls/qedit/tests/samplegrabber.c @@ -1036,6 +1036,239 @@ static void test_connect_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); } +struct frame_thread_params +{ + IMemInputPin *sink; + IMediaSample *sample; + DWORD delay; +}; + +static DWORD WINAPI frame_thread(void *arg) +{ + struct frame_thread_params *params = arg; + HRESULT hr; + + if (params->delay) + { + if (winetest_debug > 1) trace("%04x: Sleeping %u ms.\n", GetCurrentThreadId(), params->delay); + Sleep(params->delay); + } + if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId()); + hr = IMemInputPin_Receive(params->sink, params->sample); + if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr); + IMediaSample_Release(params->sample); + free(params); + return hr; +} + +static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, unsigned char color, DWORD delay) +{ + struct frame_thread_params *params = malloc(sizeof(*params)); + IMemAllocator *allocator; + REFERENCE_TIME end_time; + IMediaSample *sample; + HANDLE thread; + HRESULT hr; + BYTE *data; + + hr = IMemInputPin_GetAllocator(sink, &allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + if (hr == VFW_E_NOT_COMMITTED) + { + IMemAllocator_Commit(allocator); + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + } + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + memset(data, 0x55, 32 * 16 * 2); + + hr = IMediaSample_SetActualDataLength(sample, 32 * 16 * 2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + start_time *= 10000000; + end_time = start_time + 10000000; + hr = IMediaSample_SetTime(sample, &start_time, &end_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + params->sink = sink; + params->sample = sample; + params->delay = delay; + thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL); + + IMemAllocator_Release(allocator); + return thread; +} + +static HANDLE send_frame(IMemInputPin *sink, DWORD delay) +{ + return send_frame_time(sink, 0, 0x55, delay); /* purple */ +} + +static HRESULT join_thread_(int line, HANDLE thread) +{ + DWORD ret; + ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n"); + GetExitCodeThread(thread, &ret); + CloseHandle(thread); + return ret; +} +#define join_thread(a) join_thread_(__LINE__, a) + +static void test_buffer_flush(void) +{ + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_RGB565, + .formattype = FORMAT_VideoInfo, + .bTemporalCompression = TRUE, + }; + LONG buf[(32 * 16 * 2) / sizeof(LONG)], size = sizeof(buf); + IPin *sink, *source, *renderer_pin; + struct testfilter testsource; + ISampleGrabber *grabber; + IMediaControl *control; + IFilterGraph2 *graph; + IMemInputPin *input; + IBaseFilter *filter; + OAFilterState state; + IMediaFilter *mf; + HANDLE thread; + DWORD ticks; + unsigned i; + HRESULT hr; + ULONG ref; + + testfilter_init(&testsource); + CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterGraph2, (void **)&graph); + CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (void **)&filter); + IFilterGraph2_AddFilter(graph, filter, L"sink"); + IBaseFilter_FindPin(filter, L"In", &renderer_pin); + IBaseFilter_Release(filter); + + filter = create_sample_grabber(); + IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); + IFilterGraph2_AddFilter(graph, filter, L"sample grabber"); + IBaseFilter_FindPin(filter, L"In", &sink); + IBaseFilter_FindPin(filter, L"Out", &source); + IBaseFilter_QueryInterface(filter, &IID_ISampleGrabber, (void **)&grabber); + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input); + + ISampleGrabber_SetMediaType(grabber, &req_mt); + ISampleGrabber_SetBufferSamples(grabber, TRUE); + + testsource.sink_mt = &req_mt; + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_ConnectDirect(graph, source, renderer_pin, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IPin_Release(renderer_pin); + + IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&mf); + IMediaFilter_SetSyncSource(mf, NULL); + IMediaFilter_Release(mf); + + hr = IMemInputPin_ReceiveCanBlock(input); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf); + ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IMediaControl_GetState(control, 0, &state); + ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr); + + thread = send_frame(input, 0); + hr = IMediaControl_GetState(control, 1000, &state); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n"); + + for (i = 0; i < 3; i++) + { + ticks = GetTickCount(); + hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf); + ticks = GetTickCount() - ticks; + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(ticks < 100, "Got %u ticks.\n", ticks); + ok(size == sizeof(buf), "Got size %d.\n", size); + } + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = join_thread(thread); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaControl_GetState(control, 1000, &state); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(state == State_Stopped, "Got state %d.\n", state); + hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IMediaControl_GetState(control, 0, &state); + ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr); + + thread = send_frame(input, 0); + hr = IMediaControl_GetState(control, 1000, &state); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n"); + + for (i = 0; i < 3; i++) + { + ticks = GetTickCount(); + hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf); + ticks = GetTickCount() - ticks; + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(ticks < 100, "Got %u ticks.\n", ticks); + ok(size == sizeof(buf), "Got size %d.\n", size); + } + + IPin_BeginFlush(sink); + hr = join_thread(thread); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IPin_EndFlush(sink); + + hr = IMediaControl_GetState(control, 0, &state); + todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr); + + ticks = GetTickCount(); + thread = send_frame(input, 150); + hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf); + ticks = GetTickCount() - ticks; + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(ticks < 100, "Got %u ticks.\n", ticks); + ok(size == sizeof(buf), "Got size %d.\n", size); + + hr = IMediaControl_GetState(control, 1000, &state); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = join_thread(thread); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + IPin_Release(sink); + IPin_Release(source); + IMemInputPin_Release(input); + IMediaControl_Release(control); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ISampleGrabber_Release(grabber); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(samplegrabber) { IBaseFilter *filter; @@ -1059,6 +1292,7 @@ START_TEST(samplegrabber) test_aggregation(); test_media_types(); test_connect_pin(); + test_buffer_flush(); CoUninitialize(); } -- 2.21.0