This resolves 2 of 8 missing features needed by the Kirikiri visual novel engine.
-- v2: quartz: Delete some redundant members from struct quartz_vmr quartz: Add test for VMR9SurfaceAllocatorNotify_ChangeD3DDevice Add test for VMR9SurfaceAllocatorNotify_NotifyEvent Recreate surfaces in VMR9SurfaceAllocatorNotify_ChangeD3DDevice quartz: Fill in VMR9SurfaceAllocatorNotify_NotifyEvent stub
From: Alfred Agrell floating@muncher.se
--- dlls/quartz/vmr9.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 8eee6587182..d26b6cd8fea 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -2118,9 +2118,17 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfa static HRESULT WINAPI VMR9SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify9 *iface, LONG code, LONG_PTR param1, LONG_PTR param2) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); + IMediaEventSink *sink; + HRESULT hr;
- FIXME("(%p/%p)->(...) stub\n", iface, This); - return E_NOTIMPL; + TRACE("filter %p, code %#lx, param1 %#Ix, param2 %#Ix.\n", This, code, param1, param2); + + hr = IFilterGraph_QueryInterface(This->renderer.filter.graph, &IID_IMediaEventSink, (void **)&sink); + if (FAILED(hr)) + return hr; + hr = IMediaEventSink_Notify(sink, code, param1, param2); + IMediaEventSink_Release(sink); + return hr; }
static const IVMRSurfaceAllocatorNotify9Vtbl VMR9_SurfaceAllocatorNotify_Vtbl =
From: Alfred Agrell floating@muncher.se
--- dlls/quartz/vmr9.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index d26b6cd8fea..6efc626f6f6 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -514,9 +514,8 @@ static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE return hr; }
-static void vmr_disconnect(struct strmbase_renderer *This) +static void deallocate_surfaces(struct quartz_vmr *filter) { - struct quartz_vmr *filter = impl_from_IBaseFilter(&This->filter.IBaseFilter_iface); DWORD i;
if (filter->mode && filter->allocator && filter->presenter) @@ -530,6 +529,12 @@ static void vmr_disconnect(struct strmbase_renderer *This) } }
+static void vmr_disconnect(struct strmbase_renderer *This) +{ + struct quartz_vmr *filter = impl_from_IBaseFilter(&This->filter.IBaseFilter_iface); + deallocate_surfaces(filter); +} + static void vmr_destroy(struct strmbase_renderer *iface) { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); @@ -1999,16 +2004,24 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocat return S_OK; }
-static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor) +static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, + IDirect3DDevice9 *device, HMONITOR monitor) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
- FIXME("(%p/%p)->(...) semi-stub\n", iface, This); + TRACE("(%p/%p)->(...).\n", iface, This); + if (This->allocator_d3d9_dev) IDirect3DDevice9_Release(This->allocator_d3d9_dev); This->allocator_d3d9_dev = device; IDirect3DDevice9_AddRef(This->allocator_d3d9_dev);
+ if (This->mode && This->allocator && This->presenter) + { + deallocate_surfaces(This); + allocate_surfaces(This, &This->renderer.sink.pin.mt); + } + return S_OK; }
From: Alfred Agrell floating@muncher.se
--- dlls/quartz/tests/vmr9.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 9d88afb295d..a859673ceb6 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -4267,6 +4267,42 @@ static void test_unconnected_eos(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_notifyevent(void) +{ + IFilterGraph2 *graph = create_graph(); + IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless); + IVMRSurfaceAllocatorNotify9 *notify; + IMediaEvent *eventsrc; + unsigned int ret; + HRESULT hr; + ULONG ref; + + hr = IFilterGraph2_AddFilter(graph, filter, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&eventsrc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = check_event_code(eventsrc, 0, 0x12345678, 0x9ABC, 0xDEF0); + ok(ret == 0, "Got %u custom events.\n", ret); + + hr = IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)¬ify); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IVMRSurfaceAllocatorNotify9_NotifyEvent(notify, 0x12345678, 0x9ABC, 0xDEF0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = check_event_code(eventsrc, 0, 0x12345678, 0x9ABC, 0xDEF0); + ok(ret == 1, "Got %u custom events.\n", ret); + + IMediaEvent_Release(eventsrc); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IVMRSurfaceAllocatorNotify9_Release(notify); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + START_TEST(vmr9) { IBaseFilter *filter; @@ -4303,6 +4339,7 @@ START_TEST(vmr9) test_windowless_size(); test_mixing_prefs(); test_unconnected_eos(); + test_notifyevent();
CoUninitialize(); }
From: Alfred Agrell floating@muncher.se
--- dlls/quartz/tests/vmr9.c | 95 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index a859673ceb6..321be35d985 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -4303,6 +4303,100 @@ static void test_notifyevent(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_changed3ddevice(void) +{ + VIDEOINFOHEADER vih = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biBitCount = 32, + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = 16, + .bmiHeader.biPlanes = 1, + .bmiHeader.biCompression = BI_RGB, + }; + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_RGB32, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(vih), + .pbFormat = (BYTE *)&vih, + }; + struct presenter presenter = + { + .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl, + .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl, + .refcount = 1, + .accept_flags = VMR9AllocFlag_TextureSurface, + }; + IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless); + IFilterGraph2 *graph = create_graph(); + IVMRSurfaceAllocatorNotify9 *notify; + IDirect3DDevice9 *device, *device2; + RECT rect = {0, 0, 640, 480}; + struct testfilter source; + HWND window; + HRESULT hr; + ULONG ref; + IPin *pin; + + testfilter_init(&source); + + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); + window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, + rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL); + if (!(device = create_device(window))) + { + IBaseFilter_Release(filter); + DestroyWindow(window); + return; + } + + IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)¬ify); + presenter.notify = notify; + + hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, + &presenter.IVMRSurfaceAllocator9_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + if (hr == E_NOINTERFACE) + { + win_skip("Direct3D does not support video rendering.\n"); + goto out; + } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, filter, NULL); + + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + device2 = create_device(window); + ok(device2 != NULL, "Out of memory\n"); + + ok(presenter.got_TerminateDevice == 0, "got %d\n", presenter.got_TerminateDevice); + + hr = IVMRSurfaceAllocatorNotify9_ChangeD3DDevice(notify, device2, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(presenter.got_TerminateDevice == 1, "got %d\n", presenter.got_TerminateDevice); + + IDirect3DDevice9_Release(device2); + +out: + IPin_Release(pin); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + IVMRSurfaceAllocatorNotify9_Release(notify); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IDirect3DDevice9_Release(device); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + DestroyWindow(window); +} + START_TEST(vmr9) { IBaseFilter *filter; @@ -4340,6 +4434,7 @@ START_TEST(vmr9) test_mixing_prefs(); test_unconnected_eos(); test_notifyevent(); + test_changed3ddevice();
CoUninitialize(); }
From: Alfred Agrell floating@muncher.se
--- dlls/quartz/vmr9.c | 53 ++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 25 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 6efc626f6f6..27ebe68e69a 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -94,7 +94,6 @@ struct quartz_vmr * windowed also as a special case of windowless. This is probably the easiest way. */ VMR9Mode mode; - BITMAPINFOHEADER bmiheader;
HMODULE hD3d9;
@@ -107,11 +106,14 @@ struct quartz_vmr
HWND clipping_window;
- LONG VideoWidth; - LONG VideoHeight; VMR9AspectRatioMode aspect_mode; };
+static const BITMAPINFOHEADER *get_filter_bitmap_header(const struct quartz_vmr *filter) +{ + return get_bitmap_header(&filter->renderer.sink.pin.mt); +} + static inline BOOL is_vmr9(const struct quartz_vmr *filter) { return IsEqualGUID(&filter->renderer.filter.clsid, &CLSID_VideoMixingRenderer9); @@ -251,7 +253,7 @@ static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample) } data_size = IMediaSample_GetActualDataLength(sample);
- bitmap_header = get_bitmap_header(&filter->renderer.sink.pin.mt); + bitmap_header = get_filter_bitmap_header(filter); width = bitmap_header->biWidth; height = bitmap_header->biHeight; depth = bitmap_header->biBitCount; @@ -360,6 +362,7 @@ static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE HRESULT hr = E_FAIL; DWORD count = 1; unsigned int i; + const BITMAPINFOHEADER *bmiheader = get_bitmap_header(mt);
static const struct { @@ -392,8 +395,8 @@ static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE
info.Pool = D3DPOOL_DEFAULT; info.MinBuffers = count; - info.dwWidth = info.szAspectRatio.cx = info.szNativeSize.cx = filter->bmiheader.biWidth; - info.dwHeight = info.szAspectRatio.cy = info.szNativeSize.cy = filter->bmiheader.biHeight; + info.dwWidth = info.szAspectRatio.cx = info.szNativeSize.cx = bmiheader->biWidth; + info.dwHeight = info.szAspectRatio.cy = info.szNativeSize.cy = bmiheader->biHeight;
if (!(filter->surfaces = calloc(count, sizeof(IDirect3DSurface9 *)))) return E_OUTOFMEMORY; @@ -402,15 +405,15 @@ static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE
if (!is_vmr9(filter)) { - switch (filter->bmiheader.biCompression) + switch (bmiheader->biCompression) { case BI_RGB: - switch (filter->bmiheader.biBitCount) + switch (bmiheader->biBitCount) { case 24: info.Format = D3DFMT_R8G8B8; break; case 32: info.Format = D3DFMT_X8R8G8B8; break; default: - FIXME("Unhandled bit depth %u.\n", filter->bmiheader.biBitCount); + FIXME("Unhandled bit depth %u.\n", bmiheader->biBitCount); free(filter->surfaces); return VFW_E_TYPE_NOT_ACCEPTED; } @@ -422,12 +425,12 @@ static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE case mmioFOURCC('U','Y','V','Y'): case mmioFOURCC('Y','U','Y','2'): case mmioFOURCC('Y','V','1','2'): - info.Format = filter->bmiheader.biCompression; + info.Format = bmiheader->biCompression; info.dwFlags = VMR9AllocFlag_OffscreenSurface; break;
default: - WARN("Unhandled video compression %#lx.\n", filter->bmiheader.biCompression); + WARN("Unhandled video compression %#lx.\n", bmiheader->biCompression); free(filter->surfaces); return VFW_E_TYPE_NOT_ACCEPTED; } @@ -495,10 +498,7 @@ static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE HRESULT hr; RECT rect;
- filter->bmiheader = *bitmap_header; - filter->VideoWidth = bitmap_header->biWidth; - filter->VideoHeight = bitmap_header->biHeight; - SetRect(&rect, 0, 0, filter->VideoWidth, filter->VideoHeight); + SetRect(&rect, 0, 0, bitmap_header->biWidth, bitmap_header->biHeight); filter->window.src = rect;
AdjustWindowRectEx(&rect, GetWindowLongW(window, GWL_STYLE), FALSE, @@ -645,9 +645,10 @@ static const struct strmbase_renderer_ops renderer_ops = static RECT vmr_get_default_rect(struct video_window *This) { struct quartz_vmr *pVMR9 = impl_from_video_window(This); + const BITMAPINFOHEADER *bmiheader = get_filter_bitmap_header(pVMR9); static RECT defRect;
- SetRect(&defRect, 0, 0, pVMR9->VideoWidth, pVMR9->VideoHeight); + SetRect(&defRect, 0, 0, bmiheader->biWidth, bmiheader->biHeight);
return defRect; } @@ -667,7 +668,7 @@ static HRESULT vmr_get_current_image(struct video_window *iface, LONG *size, LON EnterCriticalSection(&filter->renderer.filter.stream_cs); device = filter->allocator_d3d9_dev;
- bih = *get_bitmap_header(&filter->renderer.sink.pin.mt); + bih = *get_filter_bitmap_header(filter); bih.biSizeImage = bih.biWidth * bih.biHeight * bih.biBitCount / 8;
if (!image) @@ -1434,6 +1435,7 @@ static HRESULT WINAPI VMR7WindowlessControl_GetNativeVideoSize(IVMRWindowlessCon LONG *width, LONG *height, LONG *aspect_width, LONG *aspect_height) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl(iface); + const BITMAPINFOHEADER *bmiheader = get_filter_bitmap_header(filter);
TRACE("filter %p, width %p, height %p, aspect_width %p, aspect_height %p.\n", filter, width, height, aspect_width, aspect_height); @@ -1441,12 +1443,12 @@ static HRESULT WINAPI VMR7WindowlessControl_GetNativeVideoSize(IVMRWindowlessCon if (!width || !height) return E_POINTER;
- *width = filter->bmiheader.biWidth; - *height = filter->bmiheader.biHeight; + *width = bmiheader->biWidth; + *height = bmiheader->biHeight; if (aspect_width) - *aspect_width = filter->bmiheader.biWidth; + *aspect_width = bmiheader->biWidth; if (aspect_height) - *aspect_height = filter->bmiheader.biHeight; + *aspect_height = bmiheader->biHeight;
return S_OK; } @@ -1634,6 +1636,7 @@ static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessCon LONG *width, LONG *height, LONG *aspect_width, LONG *aspect_height) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(iface); + const BITMAPINFOHEADER *bmiheader = get_filter_bitmap_header(filter);
TRACE("filter %p, width %p, height %p, aspect_width %p, aspect_height %p.\n", filter, width, height, aspect_width, aspect_height); @@ -1641,12 +1644,12 @@ static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessCon if (!width || !height) return E_POINTER;
- *width = filter->bmiheader.biWidth; - *height = filter->bmiheader.biHeight; + *width = bmiheader->biWidth; + *height = bmiheader->biHeight; if (aspect_width) - *aspect_width = filter->bmiheader.biWidth; + *aspect_width = bmiheader->biWidth; if (aspect_height) - *aspect_height = filter->bmiheader.biHeight; + *aspect_height = bmiheader->biHeight;
return S_OK; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=137244
Your paranoid android.
=== w8 (32 bit report) ===
quartz: 0c08:vmr9: unhandled exception c0000005 at 0049F33E
=== w8adm (32 bit report) ===
quartz: 0aec:vmr9: unhandled exception c0000005 at 0049F33E
=== w864 (32 bit report) ===
quartz: 0780:vmr9: unhandled exception c0000005 at 0049F33E
=== w1064v1507 (32 bit report) ===
quartz: 05e4:vmr9: unhandled exception c0000005 at 0049F343
=== w1064v1809 (32 bit report) ===
quartz: 1d38:vmr9: unhandled exception c0000005 at 0049F343
=== w1064_tsign (32 bit report) ===
quartz: 1f9c:vmr9: unhandled exception c0000005 at 0049F33E
=== w10pro64 (32 bit report) ===
quartz: 1fc4:vmr9: unhandled exception c0000005 at 0049F33E
=== w864 (64 bit report) ===
quartz: 0768:vmr9: unhandled exception c0000005 at 000000000048911D
=== w1064v1507 (64 bit report) ===
quartz: 0c8c:vmr9: unhandled exception c0000005 at 0000000000489120
=== w1064v1809 (64 bit report) ===
quartz: 1c2c:vmr9: unhandled exception c0000005 at 000000000048911D
=== w1064_2qxl (64 bit report) ===
quartz: 1d68:vmr9: unhandled exception c0000005 at 0000000000489120
=== w1064_adm (64 bit report) ===
quartz: 0ebc:vmr9: unhandled exception c0000005 at 0000000000489120
=== w1064_tsign (64 bit report) ===
quartz: 1138:vmr9: unhandled exception c0000005 at 0000000000489120
=== w10pro64 (64 bit report) ===
quartz: vmr9.c:1444: Test failed: Wait failed. vmr9.c:1445: Test failed: Got hr 0x103. 20c0:vmr9: unhandled exception c0000005 at 0000000000489120
=== w10pro64_en_AE_u8 (64 bit report) ===
quartz: 2100:vmr9: unhandled exception c0000005 at 000000000048911D
=== w10pro64_ar (64 bit report) ===
quartz: 0c5c:vmr9: unhandled exception c0000005 at 000000000048911D
=== w10pro64_ja (64 bit report) ===
quartz: 1478:vmr9: unhandled exception c0000005 at 000000000048911D
=== w10pro64_zh_CN (64 bit report) ===
quartz: 22fc:vmr9: unhandled exception c0000005 at 0000000000489120
=== w11pro64_amd (64 bit report) ===
quartz: vmr9.c:4384: Test failed: got 0
Sure, done. I also found VideoWidth and VideoHeight members that look as redundant as the bmiheader, so I deleted them too.