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

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Oct 19 11:48:53 CDT 2020


We fill the video pattern with something that varies between lines and
columns, to test it properly later (including the scaling algorithm).

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/qedit/tests/mediadet.c | 337 +++++++++++++++++++++++++++++++++++-
 1 file changed, 333 insertions(+), 4 deletions(-)

diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c
index dc83bb9..010b746 100644
--- a/dlls/qedit/tests/mediadet.c
+++ b/dlls/qedit/tests/mediadet.c
@@ -136,6 +136,11 @@ struct testfilter
     struct strmbase_filter filter;
     struct strmbase_source source;
     IMediaSeeking IMediaSeeking_iface;
+
+    BOOL bitmap_grab_mode;
+    const GUID *time_format;
+    LONGLONG cur_pos;
+    HANDLE thread;
 };
 
 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
@@ -158,10 +163,103 @@ 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;
+    unsigned i;
+    HRESULT hr;
+    DWORD fill;
+    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);
+
+        fill = (start_time / 10000 & 0xffffff) ^ 0xccaabb;
+        for (i = 0; i < 640 * 480 * 3; i += 3)
+        {
+            data[i] = fill ^ i;
+            data[i + 1] = fill >> 8 ^ i;
+            data[i + 2] = fill >> 16 ^ i;
+        }
+
+        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)
@@ -175,7 +273,7 @@ static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned in
     {
         .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
         .bmiHeader.biWidth = 640,
-        .bmiHeader.biHeight = 480,
+        .bmiHeader.biHeight = -480,
         .bmiHeader.biPlanes = 1,
         .bmiHeader.biBitCount = 24,
         .bmiHeader.biCompression = BI_RGB,
@@ -211,10 +309,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 +347,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,6 +376,15 @@ static ULONG WINAPI testseek_Release(IMediaSeeking *iface)
 
 static HRESULT WINAPI testseek_GetCapabilities(IMediaSeeking *iface, DWORD *caps)
 {
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+    if (filter->bitmap_grab_mode)
+    {
+        if (winetest_debug > 1) trace("IMediaSeeking_GetCapabilities()\n");
+        *caps = 0;  /* Doesn't seem to have any effect, despite being called */
+        return S_OK;
+    }
+
     ok(0, "Unexpected call.\n");
     return E_NOTIMPL;
 }
@@ -262,6 +397,15 @@ static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *ca
 
 static HRESULT WINAPI testseek_IsFormatSupported(IMediaSeeking *iface, const GUID *format)
 {
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+    if (filter->bitmap_grab_mode)
+    {
+        if (winetest_debug > 1) trace("IMediaSeeking_IsFormatSupported(%s)\n", wine_dbgstr_guid(format));
+        ok(IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME), "Unexpected format %s.\n", wine_dbgstr_guid(format));
+        return S_OK;
+    }
+
     ok(0, "Unexpected call.\n");
     return E_NOTIMPL;
 }
@@ -274,12 +418,29 @@ static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *
 
 static HRESULT WINAPI testseek_GetTimeFormat(IMediaSeeking *iface, GUID *format)
 {
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+    if (filter->bitmap_grab_mode)
+    {
+        if (winetest_debug > 1) trace("IMediaSeeking_GetTimeFormat()\n");
+        *format = *filter->time_format;
+        return S_OK;
+    }
+
     ok(0, "Unexpected call.\n");
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI testseek_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format)
 {
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+    if (filter->bitmap_grab_mode)
+    {
+        if (winetest_debug > 1) trace("IMediaSeeking_IsUsingTimeFormat(%s)\n", wine_dbgstr_guid(format));
+        return IsEqualGUID(format, filter->time_format) ? S_OK : S_FALSE;
+    }
+
     ok(0, "Unexpected call.\n");
     return E_NOTIMPL;
 }
@@ -320,8 +481,35 @@ 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, 0x%08x, 0x%s, 0x%08x)\n",
+              wine_dbgstr_longlong(*current), current_flags, wine_dbgstr_longlong(*stop), stop_flags);
+
+    if (filter->bitmap_grab_mode)
+    {
+        ok(*stop == *current || !*stop, "Unexpected stop position: 0x%s.\n", wine_dbgstr_longlong(*stop));
+        ok(current_flags == (AM_SEEKING_AbsolutePositioning | AM_SEEKING_ReturnTime),
+            "Unexpected current_flags 0x%08x.\n", current_flags);
+        ok(stop_flags == AM_SEEKING_AbsolutePositioning || !stop_flags, "Unexpected stop_flags 0x%08x.\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 +574,8 @@ 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->time_format = &TIME_FORMAT_MEDIA_TIME;
 }
 
 static WCHAR test_avi_filename[MAX_PATH];
@@ -1117,6 +1307,144 @@ static void test_COM_sg_enumpins(void)
     IBaseFilter_Release(bf);
 }
 
+static void test_bitmap_grab_mode(void)
+{
+    static const GUID *time_formats[] =
+    {
+        &TIME_FORMAT_NONE,
+        &TIME_FORMAT_FRAME,
+        &TIME_FORMAT_SAMPLE,
+        &TIME_FORMAT_FIELD,
+        &TIME_FORMAT_BYTE,
+        &TIME_FORMAT_MEDIA_TIME
+    };
+    struct testfilter testfilter;
+    IMediaDet *detector;
+    AM_MEDIA_TYPE mt;
+    double duration;
+    IUnknown *unk;
+    unsigned i;
+    HRESULT hr;
+    LONG count;
+    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);
+
+    /* EnterBitmapGrabMode only seeks once, and if SeekTime is non-negative */
+    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);
+
+    /* 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_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);
+}
+
 START_TEST(mediadet)
 {
     IMediaDet *detector;
@@ -1145,6 +1473,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