quartz/tests: Add some tests for filter states.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2018-09-25 23:30:20 -05:00 committed by Alexandre Julliard
parent 12d72c891d
commit 0c0606cd1b
1 changed files with 268 additions and 8 deletions

View File

@ -1133,6 +1133,8 @@ struct testfilter
IFilterGraph *graph;
WCHAR *name;
IReferenceClock *clock;
FILTER_STATE state;
REFERENCE_TIME start_time;
IEnumPins IEnumPins_iface;
struct testpin *pins;
@ -1255,28 +1257,73 @@ static HRESULT WINAPI testfilter_GetClassID(IBaseFilter *iface, CLSID *clsid)
return S_OK;
}
/* Downstream filters are always stopped before any filters they are connected
* to upstream. Native actually implements this by topologically sorting filters
* as they are connected. */
static void check_state_transition(struct testfilter *filter, FILTER_STATE expect)
{
FILTER_STATE state;
unsigned int i;
PIN_INFO info;
for (i = 0; i < filter->pin_count; ++i)
{
if (filter->pins[i].peer)
{
IPin_QueryPinInfo(filter->pins[i].peer, &info);
IBaseFilter_GetState(info.pFilter, 0, &state);
if (filter->pins[i].dir == PINDIR_OUTPUT)
ok(state == expect, "Expected state %d for downstream filter %p, got %d.\n",
expect, info.pFilter, state);
else
ok(state == filter->state, "Expected state %d for upstream filter %p, got %d.\n",
filter->state, info.pFilter, state);
IBaseFilter_Release(info.pFilter);
}
}
}
static HRESULT WINAPI testfilter_Stop(IBaseFilter *iface)
{
if (winetest_debug > 1) trace("%p->Stop()\n", iface);
return E_NOTIMPL;
struct testfilter *filter = impl_from_IBaseFilter(iface);
if (winetest_debug > 1) trace("%p->Stop()\n", filter);
check_state_transition(filter, State_Stopped);
filter->state = State_Stopped;
return S_OK;
}
static HRESULT WINAPI testfilter_Pause(IBaseFilter *iface)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
struct testfilter *filter = impl_from_IBaseFilter(iface);
if (winetest_debug > 1) trace("%p->Pause()\n", filter);
check_state_transition(filter, State_Paused);
filter->state = State_Paused;
return S_OK;
}
static HRESULT WINAPI testfilter_Run(IBaseFilter *iface, REFERENCE_TIME start)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
struct testfilter *filter = impl_from_IBaseFilter(iface);
if (winetest_debug > 1) trace("%p->Run(%s)\n", filter, wine_dbgstr_longlong(start));
check_state_transition(filter, State_Running);
filter->state = State_Running;
filter->start_time = start;
return S_OK;
}
static HRESULT WINAPI testfilter_GetState(IBaseFilter *iface, DWORD timeout, FILTER_STATE *state)
{
if (winetest_debug > 1) trace("%p->GetState()\n", iface);
return E_NOTIMPL;
struct testfilter *filter = impl_from_IBaseFilter(iface);
if (winetest_debug > 1) trace("%p->GetState(%u)\n", filter, timeout);
*state = filter->state;
return S_OK;
}
static HRESULT WINAPI testfilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
@ -1389,6 +1436,7 @@ static void testfilter_init(struct testfilter *filter, struct testpin *pins, int
filter->pin_count = pin_count;
for (i = 0; i < pin_count; i++)
pins[i].filter = &filter->IBaseFilter_iface;
filter->state = State_Stopped;
}
static HRESULT WINAPI testfilter_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out)
@ -2512,6 +2560,217 @@ todo_wine
ok(filter2.ref == 1, "Got outstanding refcount %d.\n", filter2.ref);
}
#define check_filter_state(a, b) check_filter_state_(__LINE__, a, b)
static void check_filter_state_(unsigned int line, IFilterGraph2 *graph, FILTER_STATE expect)
{
IMediaFilter *mediafilter;
IEnumFilters *filterenum;
IMediaControl *control;
OAFilterState oastate;
IBaseFilter *filter;
FILTER_STATE state;
HRESULT hr;
IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&mediafilter);
hr = IMediaFilter_GetState(mediafilter, 1000, &state);
ok_(__FILE__, line)(hr == S_OK, "IMediaFilter_GetState() returned %#x.\n", hr);
ok_(__FILE__, line)(state == expect, "Expected state %u, got %u.\n", expect, state);
IMediaFilter_Release(mediafilter);
IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
hr = IMediaControl_GetState(control, 1000, &oastate);
ok_(__FILE__, line)(hr == S_OK, "IMediaControl_GetState() returned %#x.\n", hr);
ok_(__FILE__, line)(state == expect, "Expected state %u, got %u.\n", expect, state);
IMediaControl_Release(control);
IFilterGraph2_EnumFilters(graph, &filterenum);
while (IEnumFilters_Next(filterenum, 1, &filter, NULL) == S_OK)
{
hr = IBaseFilter_GetState(filter, 1000, &state);
ok_(__FILE__, line)(hr == S_OK, "IBaseFilter_GetState() returned %#x.\n", hr);
ok_(__FILE__, line)(state == expect, "Expected state %u, got %u.\n", expect, state);
IBaseFilter_Release(filter);
}
IEnumFilters_Release(filterenum);
}
static void test_filter_state(void)
{
struct testpin source_pin, sink_pin;
struct testfilter source, sink;
IFilterGraph2 *graph = create_graph();
REFERENCE_TIME start_time;
IReferenceClock *clock;
IMediaControl *control;
IMediaFilter *filter;
HRESULT hr;
ULONG ref;
testsource_init(&source_pin, NULL, 0);
testsink_init(&sink_pin);
testfilter_init(&source, &source_pin, 1);
testfilter_init(&sink, &sink_pin, 1);
IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter);
IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
source_pin.filter = &source.IBaseFilter_iface;
sink_pin.filter = &sink.IBaseFilter_iface;
IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
check_filter_state(graph, State_Stopped);
hr = IMediaControl_Pause(control);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Paused);
/* Pausing sets the default sync source, if it's not already set. */
hr = IMediaFilter_GetSyncSource(filter, &clock);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!!clock, "Reference clock not set.\n");
ok(source.clock == clock, "Expected %p, got %p.\n", clock, source.clock);
ok(sink.clock == clock, "Expected %p, got %p.\n", clock, sink.clock);
hr = IReferenceClock_GetTime(clock, &start_time);
ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
hr = IMediaControl_Run(control);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Running);
ok(source.start_time >= start_time && source.start_time < start_time + 500 * 10000,
"Expected time near %s, got %s.\n",
wine_dbgstr_longlong(start_time), wine_dbgstr_longlong(source.start_time));
ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
hr = IMediaControl_Pause(control);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Paused);
hr = IMediaControl_Stop(control);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Stopped);
hr = IMediaControl_Run(control);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Running);
hr = IMediaControl_Stop(control);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Stopped);
IReferenceClock_Release(clock);
IMediaFilter_Release(filter);
IMediaControl_Release(control);
IFilterGraph2_Release(graph);
/* Test same methods using IMediaFilter. */
graph = create_graph();
IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter);
IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
hr = IMediaFilter_Pause(filter);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Paused);
hr = IMediaFilter_GetSyncSource(filter, &clock);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!!clock, "Reference clock not set.\n");
ok(source.clock == clock, "Expected %p, got %p.\n", clock, source.clock);
ok(sink.clock == clock, "Expected %p, got %p.\n", clock, sink.clock);
hr = IMediaFilter_Run(filter, 0xdeadbeef);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Running);
todo_wine {
ok(source.start_time == 0xdeadbeef, "Got time %s.\n", wine_dbgstr_longlong(source.start_time));
ok(sink.start_time == 0xdeadbeef, "Got time %s.\n", wine_dbgstr_longlong(sink.start_time));
}
hr = IMediaFilter_Pause(filter);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Paused);
hr = IMediaFilter_Stop(filter);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Stopped);
hr = IReferenceClock_GetTime(clock, &start_time);
ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
hr = IMediaFilter_Run(filter, 0);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Running);
ok(source.start_time >= start_time && source.start_time < start_time + 500 * 10000,
"Expected time near %s, got %s.\n",
wine_dbgstr_longlong(start_time), wine_dbgstr_longlong(source.start_time));
ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
hr = IMediaFilter_Stop(filter);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Stopped);
/* Test removing the sync source. */
IReferenceClock_Release(clock);
IMediaFilter_SetSyncSource(filter, NULL);
hr = IMediaControl_Run(control);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Running);
todo_wine
ok(source.start_time > 0 && source.start_time < 500 * 10000,
"Got time %s.\n", wine_dbgstr_longlong(source.start_time));
ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
hr = IMediaControl_Stop(control);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Stopped);
/* Destroying the graph while it's running stops all filters. */
hr = IMediaFilter_Run(filter, 0);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_filter_state(graph, State_Running);
todo_wine
ok(source.start_time > 0 && source.start_time < 500 * 10000,
"Got time %s.\n", wine_dbgstr_longlong(source.start_time));
ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
IMediaFilter_Release(filter);
IMediaControl_Release(control);
ref = IFilterGraph2_Release(graph);
ok(!ref, "Got outstanding refcount %d.\n", ref);
ok(source.ref == 1, "Got outstanding refcount %d.\n", source.ref);
ok(sink.ref == 1, "Got outstanding refcount %d.\n", sink.ref);
ok(source_pin.ref == 1, "Got outstanding refcount %d.\n", source_pin.ref);
ok(sink_pin.ref == 1, "Got outstanding refcount %d.\n", sink_pin.ref);
ok(source.state == State_Stopped, "Got state %u.\n", source.state);
ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
}
START_TEST(filtergraph)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
@ -2527,6 +2786,7 @@ START_TEST(filtergraph)
test_add_remove_filter();
test_connect_direct();
test_sync_source();
test_filter_state();
CoUninitialize();
test_render_with_multithread();