From 609a832a56b0e313013b05eb5e9e609887b03544 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Wed, 10 Jun 2020 23:09:06 +0700 Subject: [PATCH] quartz/filtergraph: Always try to query IMediaSeeking if it's not cached yet. Signed-off-by: Anton Baskanov Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/quartz/filtergraph.c | 33 +++++++++++++++++++++++-------- dlls/quartz/tests/filtergraph.c | 43 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 918c41a3d67..b1968069b86 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -588,6 +588,21 @@ static BOOL has_output_pins(IBaseFilter *filter) return FALSE; } +static void update_seeking(struct filter *filter) +{ + if (!filter->seeking) + { + /* The Legend of Heroes: Trails of Cold Steel II destroys its filter when + * its IMediaSeeking interface is released, so cache the interface instead + * of querying for it every time. + * Some filters (e.g. MediaStreamFilter) can become seekable when they are + * already in the graph, so always try to query IMediaSeeking if it's not + * cached yet. */ + if (FAILED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaSeeking, (void **)&filter->seeking))) + filter->seeking = NULL; + } +} + static BOOL is_renderer(struct filter *filter) { IAMFilterMiscFlags *flags; @@ -599,8 +614,12 @@ static BOOL is_renderer(struct filter *filter) ret = TRUE; IAMFilterMiscFlags_Release(flags); } - else if (filter->seeking && !has_output_pins(filter->filter)) - ret = TRUE; + else + { + update_seeking(filter); + if (filter->seeking && !has_output_pins(filter->filter)) + ret = TRUE; + } return ret; } @@ -666,15 +685,10 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, IBaseFilter_AddRef(entry->filter = filter); - /* The Legend of Heroes: Trails of Cold Steel II destroys its filter when - * its IMediaSeeking interface is released, so cache the interface instead - * of querying for it every time. */ - if (FAILED(IBaseFilter_QueryInterface(filter, &IID_IMediaSeeking, (void **)&entry->seeking))) - entry->seeking = NULL; - list_add_head(&graph->filters, &entry->entry); list_add_head(&graph->sorted_filters, &entry->sorted_entry); entry->sorting = FALSE; + entry->seeking = NULL; ++graph->version; if (is_renderer(entry)) @@ -2252,6 +2266,7 @@ static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry) { + update_seeking(filter); if (!filter->seeking) continue; hr = FoundSeek(This, filter->seeking, arg); @@ -2457,6 +2472,7 @@ static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLON LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry) { + update_seeking(filter); if (!filter->seeking) continue; @@ -2565,6 +2581,7 @@ static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG * { LONGLONG current = current_ptr ? *current_ptr : 0, stop = stop_ptr ? *stop_ptr : 0; + update_seeking(filter); if (!filter->seeking) continue; diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index a3378efe0be..d1c081681a3 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -3619,6 +3619,17 @@ static void test_ec_complete(void) ok(filter3.ref == 1, "Got outstanding refcount %d.\n", filter3.ref); } +/* Remove and re-add the filter, to flush the graph's internal + * IMediaSeeking cache. Don't expose IMediaSeeking when adding, to show + * that it's only queried when needed. */ +static void flush_cached_seeking(IFilterGraph2 *graph, struct testfilter *filter) +{ + IFilterGraph2_RemoveFilter(graph, &filter->IBaseFilter_iface); + filter->IMediaSeeking_iface.lpVtbl = NULL; + IFilterGraph2_AddFilter(graph, &filter->IBaseFilter_iface, NULL); + filter->IMediaSeeking_iface.lpVtbl = &testseek_vtbl; +} + static void test_graph_seeking(void) { struct testfilter filter1, filter2; @@ -3659,9 +3670,6 @@ static void test_graph_seeking(void) testfilter_init(&filter1, NULL, 0); testfilter_init(&filter2, NULL, 0); - filter1.IMediaSeeking_iface.lpVtbl = &testseek_vtbl; - filter2.IMediaSeeking_iface.lpVtbl = &testseek_vtbl; - IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); IFilterGraph2_QueryInterface(graph, &IID_IMediaSeeking, (void **)&seeking); IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter); @@ -3824,6 +3832,8 @@ static void test_graph_seeking(void) IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL); IFilterGraph2_AddFilter(graph, &filter2.IBaseFilter_iface, NULL); + filter1.IMediaSeeking_iface.lpVtbl = &testseek_vtbl; + filter2.IMediaSeeking_iface.lpVtbl = &testseek_vtbl; filter1.seek_caps = AM_SEEKING_CanDoSegments | AM_SEEKING_CanGetCurrentPos; filter2.seek_caps = AM_SEEKING_CanDoSegments | AM_SEEKING_CanGetDuration; @@ -3833,6 +3843,9 @@ static void test_graph_seeking(void) ok(filter1.seeking_ref > 0, "Unexpected seeking refcount %d.\n", filter1.seeking_ref); ok(filter2.seeking_ref > 0, "Unexpected seeking refcount %d.\n", filter2.seeking_ref); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + caps = AM_SEEKING_CanDoSegments | AM_SEEKING_CanGetCurrentPos; hr = IMediaSeeking_CheckCapabilities(seeking, &caps); ok(hr == S_FALSE, "Got hr %#x.\n", hr); @@ -3848,6 +3861,9 @@ static void test_graph_seeking(void) ok(hr == E_FAIL, "Got hr %#x.\n", hr); ok(!caps, "Got caps %#x.\n", caps); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + hr = IMediaSeeking_IsFormatSupported(seeking, &testguid); ok(hr == S_FALSE, "Got hr %#x.\n", hr); @@ -3905,6 +3921,9 @@ static void test_graph_seeking(void) hr = IMediaSeeking_ConvertTimeFormat(seeking, &time, &testguid, 0x123456789a, &TIME_FORMAT_NONE); todo_wine ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + filter1.seek_duration = 0x12345; filter2.seek_duration = 0x23456; hr = IMediaSeeking_GetDuration(seeking, &time); @@ -3917,6 +3936,9 @@ static void test_graph_seeking(void) ok(hr == S_OK, "Got hr %#x.\n", hr); ok(time == 0x23456, "Got time %s.\n", wine_dbgstr_longlong(time)); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + filter1.seek_stop = 0x54321; filter2.seek_stop = 0x65432; hr = IMediaSeeking_GetStopPosition(seeking, &time); @@ -3948,16 +3970,25 @@ static void test_graph_seeking(void) ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr); filter1.seek_hr = filter2.seek_hr = S_OK; + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + hr = IMediaSeeking_GetCurrentPosition(seeking, &time); ok(hr == S_OK, "Got hr %#x.\n", hr); ok(!time, "Got time %s.\n", wine_dbgstr_longlong(time)); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + current = stop = 0xdeadbeef; hr = IMediaSeeking_GetPositions(seeking, ¤t, &stop); ok(hr == S_OK, "Got hr %#x.\n", hr); ok(!current, "Got time %s.\n", wine_dbgstr_longlong(current)); ok(stop == 0x65432, "Got time %s.\n", wine_dbgstr_longlong(stop)); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + current = 0x123; stop = 0x321; hr = IMediaSeeking_SetPositions(seeking, ¤t, AM_SEEKING_AbsolutePositioning, @@ -4025,6 +4056,9 @@ static void test_graph_seeking(void) ok(filter2.seek_current == 0x123, "Got time %s.\n", wine_dbgstr_longlong(filter2.seek_current)); ok(filter2.seek_stop == 0x321, "Got time %s.\n", wine_dbgstr_longlong(filter2.seek_stop)); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + hr = IMediaSeeking_SetRate(seeking, 2.0); ok(hr == S_OK, "Got hr %#x.\n", hr); todo_wine ok(filter1.seek_rate == 2.0, "Got rate %.16e.\n", filter1.seek_rate); @@ -4040,6 +4074,9 @@ static void test_graph_seeking(void) todo_wine ok(filter1.seek_rate == -1.0, "Got rate %.16e.\n", filter1.seek_rate); todo_wine ok(filter2.seek_rate == -1.0, "Got rate %.16e.\n", filter2.seek_rate); + flush_cached_seeking(graph, &filter1); + flush_cached_seeking(graph, &filter2); + hr = IMediaSeeking_GetRate(seeking, &rate); ok(hr == S_OK, "Got hr %#x.\n", hr); todo_wine ok(rate == -1.0, "Got rate %.16e.\n", rate); -- 2.11.4.GIT