[PATCH v2 1/8] qedit/tests: Add initial tests for bitmap grab mode with a custom filter.

Gabriel Ivăncescu gabrielopcode at gmail.com
Fri Oct 23 10:18:51 CDT 2020


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

v2: I did most changes, except the following "big" ones due to reasons given
(I can still do/remove them if still requested). I figured looking at the
big picture again might be different with the other changes in place:

I kept the loop in the test filter since it helps track down race
conditions/regressions, but now I fill it with black pixels until the
check_bitmap tests. I only fill it with the pattern in the same test patch
that I verify it.

I still used the actual stretch algorithm that Windows uses. While I can
certainly take this off, I'd have to remove all the stretch tests (they
won't pass even on Windows, and having the stretching algorithm only in the
tests seems pointless, as it's almost a copy-paste). Having considered this,
let me know if I should still remove it, though.

Also, the graph state is checked in this patch now, and is indeed "paused"
on Windows.

 dlls/qedit/tests/mediadet.c | 424 ++++++++++++++++++++++++++++++++++--
 1 file changed, 411 insertions(+), 13 deletions(-)

diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c
index dc83bb9..0a05a65 100644
--- a/dlls/qedit/tests/mediadet.c
+++ b/dlls/qedit/tests/mediadet.c
@@ -136,6 +136,12 @@ struct testfilter
     struct strmbase_filter filter;
     struct strmbase_source source;
     IMediaSeeking IMediaSeeking_iface;
+
+    BOOL bitmap_grab_mode;
+    const GUID *majortype;
+    const GUID *time_format;
+    LONGLONG cur_pos;
+    HANDLE thread;
 };
 
 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
@@ -158,10 +164,95 @@ static void testfilter_destroy(struct strmbase_filter *iface)
     strmbase_filter_cleanup(&filter->filter);
 }
 
+static DWORD WINAPI testfilter_frame_thread(void *arg)
+{
+    REFERENCE_TIME start_time, end_time;
+    struct testfilter *filter = arg;
+    IMemAllocator *allocator;
+    IMediaSample *sample;
+    HRESULT hr;
+    BYTE *data;
+
+    hr = IMemInputPin_GetAllocator(filter->source.pMemInputPin, &allocator);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    start_time = (filter->cur_pos == 0xdeadbeef) ? 0 : filter->cur_pos;
+    while (hr == S_OK)
+    {
+        hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+        if (hr == VFW_E_NOT_COMMITTED)
+        {
+            IMemAllocator_Commit(allocator);
+            hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+        }
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        hr = IMediaSample_GetPointer(sample, &data);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        memset(data, 0, 640 * 480 * 3);
+
+        hr = IMediaSample_SetActualDataLength(sample, 640 * 480 * 3);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        end_time = start_time + 400000;
+        hr = IMediaSample_SetTime(sample, &start_time, &end_time);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+        start_time = end_time;
+
+        if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
+        hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
+        if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
+
+        IMediaSample_Release(sample);
+    }
+
+    IMemAllocator_Release(allocator);
+    return hr;
+}
+
+static HRESULT testfilter_init_stream(struct strmbase_filter *iface)
+{
+    struct testfilter *filter = impl_from_strmbase_filter(iface);
+    HRESULT hr;
+
+    if (!filter->bitmap_grab_mode) return S_OK;
+
+    hr = BaseOutputPinImpl_Active(&filter->source);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    filter->thread = CreateThread(NULL, 0, testfilter_frame_thread, filter, 0, NULL);
+    ok(filter->thread != NULL, "Failed to create thread: %#x.\n", GetLastError());
+
+    return S_OK;
+}
+
+static HRESULT testfilter_cleanup_stream(struct strmbase_filter *iface)
+{
+    struct testfilter *filter = impl_from_strmbase_filter(iface);
+    HRESULT hr;
+
+    if (filter->thread)
+    {
+        WaitForSingleObject(filter->thread, INFINITE);
+        CloseHandle(filter->thread);
+        filter->thread = NULL;
+    }
+    if (!filter->bitmap_grab_mode)
+        return S_OK;
+
+    hr = BaseOutputPinImpl_Inactive(&filter->source);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    return S_OK;
+}
+
 static const struct strmbase_filter_ops testfilter_ops =
 {
     .filter_get_pin = testfilter_get_pin,
     .filter_destroy = testfilter_destroy,
+    .filter_init_stream = testfilter_init_stream,
+    .filter_cleanup_stream = testfilter_cleanup_stream
 };
 
 static inline struct testfilter *impl_from_strmbase_pin(struct strmbase_pin *iface)
@@ -171,11 +262,13 @@ static inline struct testfilter *impl_from_strmbase_pin(struct strmbase_pin *ifa
 
 static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
 {
+    struct testfilter *filter = impl_from_strmbase_pin(iface);
+
     static const VIDEOINFOHEADER source_format =
     {
         .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
         .bmiHeader.biWidth = 640,
-        .bmiHeader.biHeight = 480,
+        .bmiHeader.biHeight = -480,
         .bmiHeader.biPlanes = 1,
         .bmiHeader.biBitCount = 24,
         .bmiHeader.biCompression = BI_RGB,
@@ -185,7 +278,7 @@ static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned in
     if (index)
         return S_FALSE;
 
-    mt->majortype = MEDIATYPE_Video;
+    mt->majortype = *filter->majortype;
     mt->subtype = MEDIASUBTYPE_RGB24;
     mt->bFixedSizeSamples = TRUE;
     mt->bTemporalCompression = FALSE;
@@ -211,10 +304,37 @@ static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid
     return S_OK;
 }
 
+static HRESULT WINAPI testsource_DecideBufferSize(struct strmbase_source *iface,
+        IMemAllocator *allocator, ALLOCATOR_PROPERTIES *requested)
+{
+    ALLOCATOR_PROPERTIES actual;
+
+    if (!requested->cbAlign)
+        requested->cbAlign = 1;
+
+    if (requested->cbBuffer < 640 * 480 * 3)
+        requested->cbBuffer = 640 * 480 * 3;
+
+    if (!requested->cBuffers)
+        requested->cBuffers = 1;
+
+    return IMemAllocator_SetProperties(allocator, requested, &actual);
+}
+
 static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
         IMemInputPin *peer, IMemAllocator **allocator)
 {
-    return S_OK;
+    ALLOCATOR_PROPERTIES props = {0};
+    HRESULT hr;
+
+    hr = BaseOutputPinImpl_InitAllocator(iface, allocator);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    IMemInputPin_GetAllocatorRequirements(peer, &props);
+    hr = testsource_DecideBufferSize(iface, *allocator, &props);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    return IMemInputPin_NotifyAllocator(peer, *allocator, FALSE);
 }
 
 static const struct strmbase_source_ops testsource_ops =
@@ -222,6 +342,7 @@ static const struct strmbase_source_ops testsource_ops =
     .base.pin_get_media_type = testsource_get_media_type,
     .base.pin_query_interface = testsource_query_interface,
     .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
+    .pfnDecideBufferSize = testsource_DecideBufferSize,
     .pfnDecideAllocator = testsource_DecideAllocator,
 };
 
@@ -250,8 +371,12 @@ static ULONG WINAPI testseek_Release(IMediaSeeking *iface)
 
 static HRESULT WINAPI testseek_GetCapabilities(IMediaSeeking *iface, DWORD *caps)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    if (winetest_debug > 1) trace("IMediaSeeking_GetCapabilities()\n");
+
+    ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+    *caps = 0;
+    return S_OK;
 }
 
 static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *caps)
@@ -262,8 +387,12 @@ static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *ca
 
 static HRESULT WINAPI testseek_IsFormatSupported(IMediaSeeking *iface, const GUID *format)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    if (winetest_debug > 1) trace("IMediaSeeking_IsFormatSupported(%s)\n", wine_dbgstr_guid(format));
+
+    ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+    ok(IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME), "Unexpected format %s.\n", wine_dbgstr_guid(format));
+    return S_OK;
 }
 
 static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *format)
@@ -274,14 +403,21 @@ static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *
 
 static HRESULT WINAPI testseek_GetTimeFormat(IMediaSeeking *iface, GUID *format)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    if (winetest_debug > 1) trace("IMediaSeeking_GetTimeFormat()\n");
+
+    ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+    *format = *filter->time_format;
+    return S_OK;
 }
 
 static HRESULT WINAPI testseek_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    if (winetest_debug > 1) trace("IMediaSeeking_IsUsingTimeFormat(%s)\n", wine_dbgstr_guid(format));
+
+    ok(filter->bitmap_grab_mode, "Unexpected call.\n");
+    return IsEqualGUID(format, filter->time_format) ? S_OK : S_FALSE;
 }
 
 static HRESULT WINAPI testseek_SetTimeFormat(IMediaSeeking *iface, const GUID *format)
@@ -320,8 +456,41 @@ static HRESULT WINAPI testseek_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG
 static HRESULT WINAPI testseek_SetPositions(IMediaSeeking *iface, LONGLONG *current,
     DWORD current_flags, LONGLONG *stop, DWORD stop_flags)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+    if (winetest_debug > 1)
+        trace("IMediaSeeking_SetPositions(0x%s, %#x, 0x%s, %#x)\n",
+              wine_dbgstr_longlong(*current), current_flags, wine_dbgstr_longlong(*stop), stop_flags);
+
+    if (filter->bitmap_grab_mode)
+    {
+        ok(current_flags == (AM_SEEKING_AbsolutePositioning | AM_SEEKING_ReturnTime),
+            "Unexpected current_flags %#x.\n", current_flags);
+        if (*stop != *current)
+        {
+            ok(!*stop, "Unexpected stop position: 0x%s.\n", wine_dbgstr_longlong(*stop));
+            ok(!stop_flags, "Unexpected stop_flags %#x.\n", stop_flags);
+        }
+        else
+            ok(stop_flags == AM_SEEKING_AbsolutePositioning || (!*current && !stop_flags),
+                "Unexpected stop_flags %#x.\n", stop_flags);
+
+        if (filter->thread)
+        {
+            IPin_BeginFlush(filter->source.pin.peer);
+            WaitForSingleObject(filter->thread, INFINITE);
+            CloseHandle(filter->thread);
+            filter->cur_pos = *current;
+            IPin_EndFlush(filter->source.pin.peer);
+
+            filter->thread = CreateThread(NULL, 0, testfilter_frame_thread, filter, 0, NULL);
+            ok(filter->thread != NULL, "Failed to create thread: %#x.\n", GetLastError());
+        }
+        else
+            filter->cur_pos = *current;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI testseek_GetPositions(IMediaSeeking *iface, LONGLONG *current, LONGLONG *stop)
@@ -386,6 +555,9 @@ static void testfilter_init(struct testfilter *filter)
     strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
     strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
     filter->IMediaSeeking_iface.lpVtbl = &testseek_vtbl;
+    filter->cur_pos = 0xdeadbeef;
+    filter->majortype = &MEDIATYPE_Video;
+    filter->time_format = &TIME_FORMAT_MEDIA_TIME;
 }
 
 static WCHAR test_avi_filename[MAX_PATH];
@@ -1117,6 +1289,231 @@ static void test_COM_sg_enumpins(void)
     IBaseFilter_Release(bf);
 }
 
+static void test_bitmap_grab_mode(void)
+{
+    static const GUID *const time_formats[] =
+    {
+        &TIME_FORMAT_NONE,
+        &TIME_FORMAT_FRAME,
+        &TIME_FORMAT_SAMPLE,
+        &TIME_FORMAT_FIELD,
+        &TIME_FORMAT_BYTE,
+        &TIME_FORMAT_MEDIA_TIME
+    };
+    char *buf = malloc(640 * 480 * 3);
+    struct testfilter testfilter;
+    FILTER_INFO filter_info;
+    IReferenceClock *clock;
+    IBaseFilter *filter;
+    IMediaDet *detector;
+    ISampleGrabber *sg;
+    FILTER_STATE state;
+    PIN_INFO pin_info;
+    AM_MEDIA_TYPE mt;
+    IMediaFilter *mf;
+    LONG count, size;
+    IPin *pin, *pin2;
+    double duration;
+    IUnknown *unk;
+    unsigned i;
+    HRESULT hr;
+    ULONG ref;
+    GUID guid;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IMediaDet, (void **)&detector);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IMediaDet_GetSampleGrabber(detector, &sg);
+    todo_wine ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+
+    /* EnterBitmapGrabMode only works with Video major type */
+    testfilter_init(&testfilter);
+    testfilter.majortype = &MEDIATYPE_Audio;
+    hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+    todo_wine ok(hr == VFW_E_INVALIDMEDIATYPE, "Got hr %#x.\n", hr);
+
+    ref = IMediaDet_Release(detector);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+    ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+    /* EnterBitmapGrabMode only seeks once, and if SeekTime is non-negative */
+    hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IMediaDet, (void **)&detector);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    testfilter_init(&testfilter);
+    testfilter.bitmap_grab_mode = TRUE;
+    hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaDet_EnterBitmapGrabMode(detector, -1.0);
+    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+    hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+
+    ref = IMediaDet_Release(detector);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+    ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+    /* Time formats other than TIME_FORMAT_MEDIA_TIME return E_NOTIMPL */
+    for (i = 0; i < ARRAY_SIZE(time_formats); i++)
+    {
+        hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+                              &IID_IMediaDet, (void **)&detector);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        testfilter_init(&testfilter);
+        testfilter.bitmap_grab_mode = TRUE;
+        testfilter.time_format = time_formats[i];
+        hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        hr = IMediaDet_EnterBitmapGrabMode(detector, 1337.0);
+        if (time_formats[i] == &TIME_FORMAT_MEDIA_TIME)
+        {
+            todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+            todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+            hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+            todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+            todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+        }
+        else
+            ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
+
+        ref = IMediaDet_Release(detector);
+        ok(!ref, "Got outstanding refcount %d.\n", ref);
+        ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+        ok(!ref, "Got outstanding refcount %d.\n", ref);
+    }
+
+    hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IMediaDet, (void **)&detector);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    testfilter_init(&testfilter);
+    testfilter.bitmap_grab_mode = TRUE;
+    hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+    todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+    hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+    todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+
+    /* These still work */
+    hr = IMediaDet_get_Filter(detector, &unk);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    IUnknown_Release(unk);
+    hr = IMediaDet_get_Filename(detector, &str);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    SysFreeString(str);
+    hr = IMediaDet_get_CurrentStream(detector, &count);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(count == 0, "Got stream %d.\n", count);
+
+    /* These don't work anymore */
+    hr = IMediaDet_get_OutputStreams(detector, &count);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IMediaDet_get_FrameRate(detector, &duration);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IMediaDet_get_StreamLength(detector, &duration);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IMediaDet_get_StreamMediaType(detector, &mt);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    if (SUCCEEDED(hr)) FreeMediaType(&mt);
+    hr = IMediaDet_get_StreamType(detector, &guid);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    hr = IMediaDet_get_StreamTypeB(detector, &str);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+    if (SUCCEEDED(hr)) SysFreeString(str);
+    hr = IMediaDet_put_CurrentStream(detector, 0);
+    todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+    /* Check the SampleGrabber */
+    hr = IMediaDet_GetSampleGrabber(detector, &sg);
+    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+    if (hr != S_OK) goto no_grabber;
+    hr = ISampleGrabber_GetConnectedMediaType(sg, &mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(IsEqualGUID(&mt.majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&mt.majortype));
+    ok(IsEqualGUID(&mt.subtype, &MEDIASUBTYPE_RGB24), "Got sub type %s.\n", debugstr_guid(&mt.subtype));
+    ok(IsEqualGUID(&mt.formattype, &FORMAT_VideoInfo), "Got format type %s.\n", debugstr_guid(&mt.formattype));
+    FreeMediaType(&mt);
+
+    hr = ISampleGrabber_GetCurrentBuffer(sg, &size, NULL);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(size == 640 * 480 * 3, "Got size %d.\n", size);
+    hr = ISampleGrabber_GetCurrentBuffer(sg, &size, (LONG*)buf);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(size == 640 * 480 * 3, "Got size %d.\n", size);
+    hr = ISampleGrabber_QueryInterface(sg, &IID_IBaseFilter, (void**)&filter);
+    ok(hr == S_OK, "QueryInterface for IID_IBaseFilter failed: %#x\n", hr);
+    ISampleGrabber_Release(sg);
+
+    hr = IBaseFilter_QueryFilterInfo(filter, &filter_info);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(!wcscmp(filter_info.achName, L"BitBucket"), "Got name %s.\n", debugstr_w(filter_info.achName));
+    IFilterGraph_Release(filter_info.pGraph);
+    hr = IBaseFilter_FindPin(filter, L"Out", &pin);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    IBaseFilter_Release(filter);
+
+    hr = IPin_ConnectedTo(pin, &pin2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    hr = IPin_QueryPinInfo(pin2, &pin_info);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(pin_info.pFilter != NULL, "Got NULL filter.\n");
+    IPin_Release(pin2);
+    IPin_Release(pin);
+
+    hr = IBaseFilter_QueryFilterInfo(pin_info.pFilter, &filter_info);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(!wcscmp(filter_info.achName, L"NullRenderer"), "Got name %s.\n", debugstr_w(filter_info.achName));
+    hr = IFilterGraph_QueryInterface(filter_info.pGraph, &IID_IMediaFilter, (void**)&mf);
+    ok(hr == S_OK, "QueryInterface for IID_IMediaFilter failed: %#x\n", hr);
+    IFilterGraph_Release(filter_info.pGraph);
+    IBaseFilter_Release(pin_info.pFilter);
+
+    /* The graph should be paused */
+    hr = IMediaFilter_GetState(mf, INFINITE, &state);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(state == State_Paused, "Got state %d.\n", state);
+    hr = IMediaFilter_GetSyncSource(mf, &clock);
+    ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
+    ok(clock == NULL, "Got non-NULL clock.\n");
+    IMediaFilter_Release(mf);
+
+no_grabber:
+    /* Changing filter resets bitmap grab mode */
+    testfilter.bitmap_grab_mode = FALSE;
+    hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    hr = IMediaDet_GetSampleGrabber(detector, &sg);
+    todo_wine ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
+    hr = IMediaDet_get_OutputStreams(detector, &count);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(count == 1, "Got %d streams.\n", count);
+
+    ref = IMediaDet_Release(detector);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+    ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+    free(buf);
+}
+
 START_TEST(mediadet)
 {
     IMediaDet *detector;
@@ -1145,6 +1542,7 @@ START_TEST(mediadet)
     test_put_filter();
     test_samplegrabber();
     test_COM_sg_enumpins();
+    test_bitmap_grab_mode();
 
     ret = DeleteFileW(test_avi_filename);
     ok(ret, "Failed to delete file, error %u.\n", GetLastError());
-- 
2.21.0




More information about the wine-devel mailing list