[PATCH 1/4] quartz/filtergraph: Always try to query IMediaSeeking if it's not cached yet.

Zebediah Figura z.figura12 at gmail.com
Mon Jun 8 14:28:51 CDT 2020


On 6/8/20 1:00 PM, Anton Baskanov wrote:
> Some filters (e.g. MediaStreamFilter) can become seekable when they are already in the graph.
> 

I think this should be a comment, in update_seeking along with the
comment regarding The Legend of Heroes.

> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> ---
>  dlls/quartz/filtergraph.c       | 30 +++++++++---
>  dlls/quartz/tests/filtergraph.c | 86 +++++++++++++++++++++++++++++++--
>  2 files changed, 105 insertions(+), 11 deletions(-)
> 
> diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c
> index 6217516db1..fa0a15a3fc 100644
> --- a/dlls/quartz/filtergraph.c
> +++ b/dlls/quartz/filtergraph.c
> @@ -585,6 +585,18 @@ 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. */
> +        if (FAILED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaSeeking, (void **)&filter->seeking)))
> +            filter->seeking = NULL;
> +    }
> +}
> +
>  static BOOL is_renderer(struct filter *filter)
>  {
>      IAMFilterMiscFlags *flags;
> @@ -596,8 +608,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;
>  }
>  
> @@ -663,15 +679,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))
> @@ -2249,6 +2260,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);
> @@ -2454,6 +2466,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;
>  
> @@ -2562,6 +2575,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 f0aa084192..10f76d36ce 100644
> --- a/dlls/quartz/tests/filtergraph.c
> +++ b/dlls/quartz/tests/filtergraph.c
> @@ -3658,9 +3658,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);
> @@ -3823,6 +3820,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;
> @@ -3832,6 +3831,15 @@ 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);
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +

You could probably factor this out into a helper function, along the
lines of:

/* 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. */
void flush_cached_seeking(IFilterGraph *, struct testfilter *);

>      caps = AM_SEEKING_CanDoSegments | AM_SEEKING_CanGetCurrentPos;
>      hr = IMediaSeeking_CheckCapabilities(seeking, &caps);
>      ok(hr == S_FALSE, "Got hr %#x.\n", hr);
> @@ -3847,6 +3855,15 @@ static void test_graph_seeking(void)
>      ok(hr == E_FAIL, "Got hr %#x.\n", hr);
>      ok(!caps, "Got caps %#x.\n", caps);
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +
>      hr = IMediaSeeking_IsFormatSupported(seeking, &testguid);
>      ok(hr == S_FALSE, "Got hr %#x.\n", hr);
>  
> @@ -3904,6 +3921,15 @@ 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);
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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_duration = 0x12345;
>      filter2.seek_duration = 0x23456;
>      hr = IMediaSeeking_GetDuration(seeking, &time);
> @@ -3916,6 +3942,15 @@ 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));
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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_stop = 0x54321;
>      filter2.seek_stop = 0x65432;
>      hr = IMediaSeeking_GetStopPosition(seeking, &time);
> @@ -3947,16 +3982,43 @@ static void test_graph_seeking(void)
>      ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
>      filter1.seek_hr = filter2.seek_hr = S_OK;
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +
>      hr = IMediaSeeking_GetCurrentPosition(seeking, &time);
>      ok(hr == S_OK, "Got hr %#x.\n", hr);
>      ok(!time, "Got time %s.\n", wine_dbgstr_longlong(time));
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +
>      current = stop = 0xdeadbeef;
>      hr = IMediaSeeking_GetPositions(seeking, &current, &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));
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +
>      current = 0x123;
>      stop = 0x321;
>      hr = IMediaSeeking_SetPositions(seeking, &current, AM_SEEKING_AbsolutePositioning,
> @@ -4024,6 +4086,15 @@ 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));
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +
>      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);
> @@ -4039,6 +4110,15 @@ 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);
>  
> +    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
> +    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
> +    filter1.IMediaSeeking_iface.lpVtbl = NULL;
> +    filter2.IMediaSeeking_iface.lpVtbl = NULL;
> +    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;
> +
>      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);
> 



More information about the wine-devel mailing list