[PATCH 3/5] amstream: Implement MediaStreamFilter::SupportSeeking.
Anton Baskanov
baskanov at gmail.com
Wed Jun 3 11:36:57 CDT 2020
On Tuesday, 2 June 2020 23:04:00 +07 you wrote:
> On 6/2/20 10:54 AM, Zebediah Figura wrote:
> > On 6/1/20 11:13 PM, Anton Baskanov wrote:
> >> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> >> ---
> >>
> >> dlls/amstream/filter.c | 249 ++++++++++++++++++++++++-
> >> dlls/amstream/tests/amstream.c | 323 +++++++++++++++++++++++++++++++++
> >> 2 files changed, 568 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/dlls/amstream/filter.c b/dlls/amstream/filter.c
> >> index 4b5e184f04..643cfcdbe4 100644
> >> --- a/dlls/amstream/filter.c
> >> +++ b/dlls/amstream/filter.c
> >> @@ -163,6 +163,7 @@ static const IEnumPinsVtbl enum_pins_vtbl =
> >>
> >> struct filter
> >> {
> >>
> >> IMediaStreamFilter IMediaStreamFilter_iface;
> >>
> >> + IMediaSeeking IMediaSeeking_iface;
> >>
> >> LONG refcount;
> >> CRITICAL_SECTION cs;
> >>
> >> @@ -171,6 +172,7 @@ struct filter
> >>
> >> IFilterGraph *graph;
> >> ULONG nb_streams;
> >> IAMMediaStream **streams;
> >>
> >> + IAMMediaStream *seekable_stream;
> >>
> >> FILTER_STATE state;
> >>
> >> };
> >>
> >> @@ -181,6 +183,8 @@ static inline struct filter
> >> *impl_from_IMediaStreamFilter(IMediaStreamFilter *if>>
> >> static HRESULT WINAPI filter_QueryInterface(IMediaStreamFilter *iface,
> >> REFIID riid, void **ret_iface) {
> >>
> >> + struct filter *filter = impl_from_IMediaStreamFilter(iface);
> >> +
> >>
> >> TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ret_iface);
> >>
> >> *ret_iface = NULL;
> >>
> >> @@ -191,10 +195,12 @@ static HRESULT WINAPI
> >> filter_QueryInterface(IMediaStreamFilter *iface, REFIID ri>>
> >> IsEqualIID(riid, &IID_IBaseFilter) ||
> >> IsEqualIID(riid, &IID_IMediaStreamFilter))
> >> *ret_iface = iface;
> >>
> >> + else if (IsEqualIID(riid, &IID_IMediaSeeking) &&
> >> filter->seekable_stream) + *ret_iface =
> >> &filter->IMediaSeeking_iface;
> >>
> >> if (*ret_iface)
> >> {
> >>
> >> - IMediaStreamFilter_AddRef(*ret_iface);
> >> + IUnknown_AddRef((IUnknown *)*ret_iface);
> >>
> >> return S_OK;
> >>
> >> }
> >>
> >> @@ -544,11 +550,74 @@ static HRESULT WINAPI
> >> filter_EnumMediaStreams(IMediaStreamFilter *iface, LONG in>>
> >> return S_OK;
> >>
> >> }
> >>
> >> -static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface,
> >> BOOL bRenderer) +static IMediaSeeking *get_seeking(IAMMediaStream
> >> *stream)
> >>
> >> {
> >>
> >> - FIXME("(%p)->(%d): Stub!\n", iface, bRenderer);
> >> + IPin *pin;
> >> + IPin *peer;
> >> + IMediaSeeking *seeking;
> >>
> >> - return E_NOTIMPL;
> >> + if (FAILED(IAMMediaStream_QueryInterface(stream, &IID_IPin, (void
> >> **)&pin))) + {
> >> + WARN("Stream %p does not support IPin.\n", stream);
> >> + return NULL;
> >> + }
> >> +
> >> + if (FAILED(IPin_ConnectedTo(pin, &peer)))
> >> + {
> >> + IPin_Release(pin);
> >> + return NULL;
> >> + }
> >> +
> >> + if (FAILED(IPin_QueryInterface(peer, &IID_IMediaSeeking, (void
> >> **)&seeking))) + {
> >> + IPin_Release(peer);
> >> + IPin_Release(pin);
> >> + return NULL;
> >> + }
> >> +
> >> + IPin_Release(peer);
> >> + IPin_Release(pin);
> >> +
> >> + return seeking;
> >> +}
> >> +
> >> +static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface,
> >> BOOL renderer) +{
> >> + struct filter *filter = impl_from_IMediaStreamFilter(iface);
> >> + unsigned int i;
> >> + HRESULT hr = E_NOINTERFACE;
> >> +
> >> + TRACE("filter %p, renderer %d\n", iface, renderer);
> >
> > Without tests to show whether/how the "renderer" value makes a
> > difference, I think we should print a FIXME if it's FALSE.
> >
> >> +
> >> + EnterCriticalSection(&filter->cs);
> >> +
> >> + if (filter->seekable_stream)
> >> + return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
> >
> > Missing LeaveCriticalSection().
> >
> >> +
> >> + for (i = 0; i < filter->nb_streams; ++i)
> >> + {
> >> + IMediaSeeking *seeking = get_seeking(filter->streams[i]);
> >> + LONGLONG duration;
> >> +
> >> + if (!seeking)
> >> + continue;
> >> +
> >> + if (FAILED(IMediaSeeking_GetDuration(seeking, &duration)))
> >> + {
> >> + IMediaSeeking_Release(seeking);
> >> + continue;
> >> + }
> >> +
> >> + filter->seekable_stream = filter->streams[i];
> >> + hr = S_OK;
> >> + IMediaSeeking_Release(seeking);
> >
> > Is it correct that only one stream is chosen for seeking, even if there
> > are multiple available? Consider e.g. the quartz filter graph, which
> > seeks all available streams.
> >
> > For that matter, should we be delegating to the filter graph instead of
> > seeking the pins directly?
> >
> > One thing in particular to test is whether filters are paused when
> > seeked. Even if we don't delegate to the filter graph, we likely want to
> > do this anyway.
> >
> > Another thing to test is whether GetCurrentPosition() returns something
> > reflecting the reference clock time, or the last sample time, or whether
> > it fails if no exposed streams support GetCurrentPosition().
>
> Sorry, on reflection, I realize this doesn't make sense, because we
> *are* the sink filter. multimedia stream â stream filter...
>
> I think the question about seeking multiple streams still stands, though.
::SetPosition tests show that only one stream is used for seeking and that
::SupportSeeking determines which one will be used. Probably it's assumed that
all the streams come from the same splitter filter.
More information about the wine-devel
mailing list