[PATCH 1/4] qasf: Implement WM ASF reader stub.

Zebediah Figura zfigura at codeweavers.com
Wed Apr 1 10:17:25 CDT 2020


On 3/31/20 11:01 AM, Jactry Zeng wrote:
> Signed-off-by: Jactry Zeng <jzeng at codeweavers.com>
> ---
>  dlls/qasf/Makefile.in       |   3 +-
>  dlls/qasf/qasf_classes.idl  |   7 ++
>  dlls/qasf/qasf_main.c       |   3 +
>  dlls/qasf/qasf_private.h    |   1 +
>  dlls/qasf/tests/Makefile.in |   3 +-
>  dlls/qasf/tests/wmasf.c     | 182 ++++++++++++++++++++++++++++++++++++
>  dlls/qasf/wmasf.c           |  67 +++++++++++++
>  7 files changed, 264 insertions(+), 2 deletions(-)
>  create mode 100644 dlls/qasf/tests/wmasf.c
>  create mode 100644 dlls/qasf/wmasf.c
> 
> diff --git a/dlls/qasf/Makefile.in b/dlls/qasf/Makefile.in
> index dd02f5a344..d7e0168fab 100644
> --- a/dlls/qasf/Makefile.in
> +++ b/dlls/qasf/Makefile.in
> @@ -5,7 +5,8 @@ EXTRADLLFLAGS = -mno-cygwin
>  
>  C_SRCS = \
>  	dmowrapper.c \
> -	qasf_main.c
> +	qasf_main.c \
> +	wmasf.c
>  

Would you mind renaming this to asfreader.c? "wm" is kind of redundant,
and I think we want to distinguish the ASF reader from the ASF writer
(if we ever do implement the latter).

Similarly "wmasf" can be shortened to "asf" in most places below.

Otherwise I think this patch looks good.

>  IDL_SRCS = \
>  	qasf_classes.idl
> diff --git a/dlls/qasf/qasf_classes.idl b/dlls/qasf/qasf_classes.idl
> index 0acf380691..b6f6c58fed 100644
> --- a/dlls/qasf/qasf_classes.idl
> +++ b/dlls/qasf/qasf_classes.idl
> @@ -25,3 +25,10 @@
>      uuid(94297043-bd82-4dfd-b0de-8177739c6d20),
>  ]
>  coclass DMOWrapperFilter {}
> +
> +[
> +    helpstring("WM ASF Reader"),
> +    threading(both),
> +    uuid(187463a0-5bb7-11d3-acbe-0080c75e246e),
> +]
> +coclass WMAsfReader {}
> diff --git a/dlls/qasf/qasf_main.c b/dlls/qasf/qasf_main.c
> index 5df23649f0..17301b2494 100644
> --- a/dlls/qasf/qasf_main.c
> +++ b/dlls/qasf/qasf_main.c
> @@ -99,6 +99,7 @@ static const IClassFactoryVtbl class_factory_vtbl =
>  };
>  
>  static struct class_factory dmo_wrapper_cf = {{&class_factory_vtbl}, dmo_wrapper_create};
> +static struct class_factory wmasf_reader_cf = {{&class_factory_vtbl}, wmasf_reader_create};
>  
>  BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
>  {
> @@ -116,6 +117,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
>  
>      if (IsEqualGUID(clsid, &CLSID_DMOWrapperFilter))
>          return IClassFactory_QueryInterface(&dmo_wrapper_cf.IClassFactory_iface, iid, out);
> +    if (IsEqualIID(clsid, &CLSID_WMAsfReader))
> +        return IClassFactory_QueryInterface(&wmasf_reader_cf.IClassFactory_iface, iid, out);
>  
>      FIXME("%s not available, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid));
>      return CLASS_E_CLASSNOTAVAILABLE;
> diff --git a/dlls/qasf/qasf_private.h b/dlls/qasf/qasf_private.h
> index bdb2e433b2..6564194c9e 100644
> --- a/dlls/qasf/qasf_private.h
> +++ b/dlls/qasf/qasf_private.h
> @@ -30,5 +30,6 @@
>  #include "wine/strmbase.h"
>  
>  HRESULT dmo_wrapper_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
> +HRESULT wmasf_reader_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
>  
>  #endif /* QASF_PRIVATE_H */
> diff --git a/dlls/qasf/tests/Makefile.in b/dlls/qasf/tests/Makefile.in
> index 793f0d2c4b..b622ccf599 100644
> --- a/dlls/qasf/tests/Makefile.in
> +++ b/dlls/qasf/tests/Makefile.in
> @@ -2,4 +2,5 @@ TESTDLL   = qasf.dll
>  IMPORTS   = strmbase dmoguids strmiids uuid msdmo ole32
>  
>  C_SRCS = \
> -	dmowrapper.c
> +	dmowrapper.c \
> +	wmasf.c
> diff --git a/dlls/qasf/tests/wmasf.c b/dlls/qasf/tests/wmasf.c
> new file mode 100644
> index 0000000000..b82aa3a053
> --- /dev/null
> +++ b/dlls/qasf/tests/wmasf.c
> @@ -0,0 +1,182 @@
> +/*
> + * WM ASF reader unit tests
> + *
> + * Copyright 2019 Zebediah Figura
> + * Copyright 2020 Jactry Zeng for CodeWeavers
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + */
> +
> +#define COBJMACROS
> +
> +#include "dshow.h"
> +#include "wine/strmbase.h"
> +#include "wine/test.h"
> +
> +static IBaseFilter *create_wmasf_reader(void)
> +{
> +    IBaseFilter *filter = NULL;
> +    HRESULT hr;
> +
> +    hr = CoCreateInstance(&CLSID_WMAsfReader, NULL, CLSCTX_INPROC_SERVER,
> +                          &IID_IBaseFilter, (void **)&filter);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    return filter;
> +}
> +
> +#define expected_ref(obj,ref) expect_ref_((IUnknown*)obj, ref, __LINE__)
> +static void expect_ref_(IUnknown* obj, ULONG expected_refcount, int line)
> +{
> +    ULONG refcount;
> +    IUnknown_AddRef(obj);
> +    refcount = IUnknown_Release(obj);
> +    ok_(__FILE__, line)(refcount == expected_refcount, "Unexpected refcount %d, expected %d.\n",
> +                        refcount, expected_refcount);
> +}

Style nitpick: I'd prefer "check_refcount" here, or alternatively to use
the same get_refcount() helper as in other tests. If not, you might also
want to change "IUnknown *" to "void *".

> +
> +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
> +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
> +{
> +    IUnknown *iface = iface_ptr;
> +    HRESULT hr, expected_hr;
> +    IUnknown *unk;
> +
> +    expected_hr = supported ? S_OK : E_NOINTERFACE;
> +
> +    hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
> +    ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
> +    if (SUCCEEDED(hr))
> +        IUnknown_Release(unk);
> +}
> +
> +static void test_interfaces(void)
> +{
> +    IBaseFilter *filter = create_wmasf_reader();
> +
> +    check_interface(filter, &IID_IBaseFilter, TRUE);
> +    check_interface(filter, &IID_IMediaFilter, TRUE);
> +    todo_wine check_interface(filter, &IID_IFileSourceFilter, TRUE);
> +    check_interface(filter, &IID_IPersist, TRUE);
> +    check_interface(filter, &IID_IUnknown, TRUE);
> +
> +    check_interface(filter, &IID_IAMFilterMiscFlags, FALSE);
> +    check_interface(filter, &IID_IMediaSeeking, FALSE);

In general I try to check for all of the interfaces that the filter
graph or capture graph automatically queries, plus any that the filter
is documented to expose. Not that I expect the ASF reader to expose
IBasicAudio, but I do think it's worth checking for IReferenceClock and
IQualityControl at least. The DirectX 9 documentation lists also that
this filter supports IAMExtendedSeeking (though we have no header for
it, so I don't object to leaving that one out for now),
IServiceProvider, IWMHeaderInfo, IWMReaderAdvanced, IWMReaderAdvanced2.

> +
> +    IBaseFilter_Release(filter);
> +}
> +
> +static const GUID test_iid = {0x33333333};
> +static LONG outer_ref = 1;
> +
> +static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
> +{
> +    if (IsEqualGUID(iid, &IID_IUnknown) ||
> +        IsEqualGUID(iid, &IID_IBaseFilter) ||
> +        IsEqualGUID(iid, &test_iid))
> +    {
> +        *out = (IUnknown *)0xdeadbeef;
> +        return S_OK;
> +    }
> +    ok(0, "Unexpected call %s.\n", wine_dbgstr_guid(iid));
> +    return E_NOINTERFACE;
> +}
> +
> +static ULONG WINAPI outer_AddRef(IUnknown *iface)
> +{
> +    return InterlockedIncrement(&outer_ref);
> +}
> +
> +static ULONG WINAPI outer_Release(IUnknown *iface)
> +{
> +    return InterlockedDecrement(&outer_ref);
> +}
> +
> +static const IUnknownVtbl outer_vtbl =
> +{
> +    outer_QueryInterface,
> +    outer_AddRef,
> +    outer_Release,
> +};
> +
> +static IUnknown test_outer = {&outer_vtbl};
> +
> +static void test_aggregation(void)
> +{
> +    IBaseFilter *filter, *filter2;
> +    IUnknown *unk, *unk2;
> +    HRESULT hr;
> +    ULONG ref;
> +
> +    filter = (IBaseFilter *)0xdeadbeef;
> +    hr = CoCreateInstance(&CLSID_WMAsfReader, &test_outer, CLSCTX_INPROC_SERVER,
> +                          &IID_IBaseFilter, (void **)&filter);
> +    ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
> +    ok(!filter, "Got interface %p.\n", filter);
> +
> +    hr = CoCreateInstance(&CLSID_WMAsfReader, &test_outer, CLSCTX_INPROC_SERVER,
> +                          &IID_IUnknown, (void **)&unk);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
> +    ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
> +    expected_ref(unk, 1);
> +
> +    ref = IUnknown_AddRef(unk);
> +    ok(ref == 2, "Got unexpected refcount %d.\n", ref);
> +    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
> +
> +    ref = IUnknown_Release(unk);
> +    ok(ref == 1, "Got unexpected refcount %d.\n", ref);
> +    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
> +
> +    hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
> +    IUnknown_Release(unk2);
> +
> +    hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
> +
> +    hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
> +
> +    hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
> +    ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
> +    ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
> +
> +    hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
> +
> +    IBaseFilter_Release(filter);
> +    ref = IUnknown_Release(unk);
> +    ok(!ref, "Got unexpected refcount %d.\n", ref);
> +    ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
> +}
> +
> +START_TEST(wmasf)
> +{
> +    CoInitializeEx(NULL, COINIT_MULTITHREADED);
> +
> +    test_interfaces();
> +    test_aggregation();
> +
> +    CoUninitialize();
> +}
> diff --git a/dlls/qasf/wmasf.c b/dlls/qasf/wmasf.c
> new file mode 100644
> index 0000000000..04aaf21367
> --- /dev/null
> +++ b/dlls/qasf/wmasf.c
> @@ -0,0 +1,67 @@
> +/*
> + * WM ASF reader
> + *
> + * Copyright 2020 Jactry Zeng for CodeWeavers
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + */
> +
> +#include "qasf_private.h"
> +
> +WINE_DEFAULT_DEBUG_CHANNEL(qasf);
> +
> +struct wmasf_reader
> +{
> +    struct strmbase_filter filter;
> +};
> +
> +static inline struct wmasf_reader *impl_reader_from_strmbase_filter(struct strmbase_filter *iface)
> +{
> +    return CONTAINING_RECORD(iface, struct wmasf_reader, filter);
> +}
> +
> +static struct strmbase_pin *wmasf_reader_get_pin(struct strmbase_filter *iface, unsigned int index)
> +{
> +    return NULL;
> +}
> +
> +static void wmasf_reader_destroy(struct strmbase_filter *iface)
> +{
> +    struct wmasf_reader *filter = impl_reader_from_strmbase_filter(iface);
> +
> +    strmbase_filter_cleanup(&filter->filter);
> +    free(filter);
> +}
> +
> +static struct strmbase_filter_ops filter_ops =
> +{
> +    .filter_get_pin = wmasf_reader_get_pin,
> +    .filter_destroy = wmasf_reader_destroy,
> +};
> +
> +HRESULT wmasf_reader_create(IUnknown *outer, IUnknown **out)
> +{
> +    struct wmasf_reader *object;
> +
> +    if (!(object = calloc(sizeof(*object), 1)))
> +        return E_OUTOFMEMORY;
> +
> +    strmbase_filter_init(&object->filter, outer, &CLSID_WMAsfReader, &filter_ops);
> +
> +    TRACE("Created WM ASF reader %p.\n", object);
> +    *out = &object->filter.IUnknown_inner;
> +
> +    return S_OK;
> +}
> 



More information about the wine-devel mailing list