This isn't all of what Rewrite needs, but it's the large and risky part that would be inappropriate for code freeze.
-- v3: quartz/tests: Add some tests for VMR7 renderless mode. quartz: Return S_OK from IVMRSurfaceAllocator_PrepareSurface(). quartz: Implement IVMRSurfaceAllocatorNotify::AdviseSurfaceAllocator(). quartz: Reimplement the VMR7 using the VMR7 presenter.
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/quartz/vmr7_presenter.c | 59 +++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 78d97bd5e10..0c6cb6dedbd 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -33,6 +33,8 @@ struct vmr7_presenter
IDirectDraw7 *ddraw; IDirectDrawSurface7 *frontbuffer; + IDirectDrawSurface7 *primary; + HWND window; };
static struct vmr7_presenter *impl_from_IVMRImagePresenter(IVMRImagePresenter *iface) @@ -82,6 +84,7 @@ static ULONG WINAPI image_presenter_Release(IVMRImagePresenter *iface) { if (presenter->frontbuffer) IDirectDrawSurface7_Release(presenter->frontbuffer); + IDirectDrawSurface7_Release(presenter->primary); IDirectDraw7_Release(presenter->ddraw); free(presenter); } @@ -103,8 +106,31 @@ static HRESULT WINAPI image_presenter_StopPresenting(IVMRImagePresenter *iface, static HRESULT WINAPI image_presenter_PresentImage(IVMRImagePresenter *iface, DWORD_PTR cookie, VMRPRESENTATIONINFO *info) { - FIXME("iface %p, cookie %#Ix, info %p, stub!\n", iface, cookie, info); - return E_NOTIMPL; + struct vmr7_presenter *presenter = impl_from_IVMRImagePresenter(iface); + POINT point; + HRESULT hr; + RECT rect; + + TRACE("iface %p, cookie %#Ix, info %p.\n", iface, cookie, info); + + TRACE("flags %#lx, surface %p, start %s, end %s, aspect ratio %ldx%ld,\n", + info->dwFlags, info->lpSurf, debugstr_time(info->rtStart), + debugstr_time(info->rtEnd), info->szAspectRatio.cx, info->szAspectRatio.cy); + TRACE("src %s, dst %s, type-specific flags %#lx, interlace flags %#lx.\n", + wine_dbgstr_rect(&info->rcSrc), wine_dbgstr_rect(&info->rcDst), + info->dwTypeSpecificFlags, info->dwInterlaceFlags); + + if (info->dwFlags & VMRSample_SrcDstRectsValid) + FIXME("Ignoring src/dst rects.\n"); + + GetClientRect(presenter->window, &rect); + point.x = point.y = 0; + ClientToScreen(presenter->window, &point); + OffsetRect(&rect, point.x, point.y); + if (FAILED(hr = IDirectDrawSurface7_Blt(presenter->primary, &rect, info->lpSurf, NULL, DDBLT_WAIT, NULL))) + ERR("Failed to blit, hr %#lx.\n", hr); + + return S_OK; }
static const IVMRImagePresenterVtbl image_presenter_vtbl = @@ -310,8 +336,23 @@ static HRESULT WINAPI windowless_control_SetAspectRatioMode( static HRESULT WINAPI windowless_control_SetVideoClippingWindow( IVMRWindowlessControl *iface, HWND window) { - FIXME("iface %p, window %p, stub!.\n", iface, window); - return E_NOTIMPL; + struct vmr7_presenter *presenter = impl_from_IVMRWindowlessControl(iface); + IDirectDrawClipper *clipper; + HRESULT hr; + + TRACE("iface %p, window %p.\n", iface, window); + + if (FAILED(hr = IDirectDraw7_CreateClipper(presenter->ddraw, 0, &clipper, NULL))) + ERR("Failed to create clipper, hr %#lx.\n", hr); + if (FAILED(hr = IDirectDrawClipper_SetHWnd(clipper, 0, window))) + ERR("Failed to set clip window, hr %#lx.\n", hr); + if (FAILED(hr = IDirectDrawSurface7_SetClipper(presenter->primary, clipper))) + ERR("Failed to set clipper, hr %#lx.\n", hr); + IDirectDrawClipper_Release(clipper); + + presenter->window = window; + + return S_OK; }
static HRESULT WINAPI windowless_control_RepaintVideo( @@ -384,6 +425,13 @@ HRESULT vmr7_presenter_create(IUnknown *outer, IUnknown **out) struct vmr7_presenter *object; HRESULT hr;
+ DDSURFACEDESC2 primary_desc = + { + .dwSize = sizeof(DDSURFACEDESC2), + .dwFlags = DDSD_CAPS, + .ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE, + }; + TRACE("outer %p, out %p.\n", outer, out);
if (outer) @@ -406,6 +454,9 @@ HRESULT vmr7_presenter_create(IUnknown *outer, IUnknown **out) if (FAILED(hr = IDirectDraw7_SetCooperativeLevel(object->ddraw, NULL, DDSCL_NORMAL))) ERR("Failed to set cooperative level, hr %#lx.\n", hr);
+ if (FAILED(hr = IDirectDraw7_CreateSurface(object->ddraw, &primary_desc, &object->primary, NULL))) + ERR("Failed to create primary surface, hr %#lx.\n", hr); + TRACE("Created VMR7 default presenter %p.\n", object); *out = (IUnknown *)&object->IVMRSurfaceAllocator_iface; return S_OK;
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/quartz/tests/vmr7.c | 7 +- dlls/quartz/vmr7.c | 753 ++++----------------------------------- 2 files changed, 77 insertions(+), 683 deletions(-)
diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index fda4c6d46d8..7cb94338126 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -1288,7 +1288,9 @@ static void test_current_image(IBaseFilter *filter, IMemInputPin *input,
size = sizeof(buffer); hr = IBasicVideo_GetCurrentImage(video, &size, buffer); - ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr != S_OK) + goto out; ok(size == sizeof(buffer), "Got size %ld.\n", size); ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n"); /* The contents seem to reflect the last frame rendered. */ @@ -1339,6 +1341,7 @@ static void test_current_image(IBaseFilter *filter, IMemInputPin *input, hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#lx.\n", hr);
+out: IBasicVideo_Release(video); }
@@ -1495,7 +1498,7 @@ static void test_connect_pin(void)
vih.bmiHeader.biBitCount = 16; hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); - ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); + todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr);
vih.bmiHeader.biBitCount = 32; hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); diff --git a/dlls/quartz/vmr7.c b/dlls/quartz/vmr7.c index 4770543b614..5b1b13b7436 100644 --- a/dlls/quartz/vmr7.c +++ b/dlls/quartz/vmr7.c @@ -63,18 +63,14 @@ struct vmr7 IAMVideoAccelerator IAMVideoAccelerator_iface; IOverlay IOverlay_iface;
- IVMRSurfaceAllocator9 *allocator; - IVMRImagePresenter9 *presenter; - DWORD stream_count; DWORD mixing_prefs;
VMRMode mode;
- HMODULE d3d9_module; - - IDirect3DDevice9 *device; - IDirect3DSurface9 **surfaces; + IVMRSurfaceAllocator *allocator; + IVMRImagePresenter *presenter; + IDirectDrawSurface7 **surfaces; DWORD surface_count; DWORD surface_index; DWORD_PTR cookie; @@ -124,36 +120,6 @@ static struct vmr7 *impl_from_IVMRWindowlessControl(IVMRWindowlessControl *iface return CONTAINING_RECORD(iface, struct vmr7, IVMRWindowlessControl_iface); }
-struct default_presenter -{ - IVMRImagePresenter9 IVMRImagePresenter9_iface; - IVMRSurfaceAllocator9 IVMRSurfaceAllocator9_iface; - - LONG refcount; - - IDirect3DDevice9 *device; - IDirect3D9 *d3d9; - IDirect3DSurface9 **surfaces; - HMONITOR monitor; - DWORD surface_count; - - VMR9AllocationInfo info; - - struct vmr7 *vmr; -}; - -static struct default_presenter *impl_from_IVMRImagePresenter9(IVMRImagePresenter9 *iface) -{ - return CONTAINING_RECORD(iface, struct default_presenter, IVMRImagePresenter9_iface); -} - -static struct default_presenter *impl_from_IVMRSurfaceAllocator9(IVMRSurfaceAllocator9 *iface) -{ - return CONTAINING_RECORD(iface, struct default_presenter, IVMRSurfaceAllocator9_iface); -} - -static HRESULT default_presenter_create(struct vmr7 *parent, struct default_presenter **presenter); - static struct vmr7 *impl_from_IBaseFilter(IBaseFilter *iface) { return CONTAINING_RECORD(iface, struct vmr7, renderer.filter.IBaseFilter_iface); @@ -165,8 +131,8 @@ static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample) unsigned int data_size, width, depth, src_pitch; const BITMAPINFOHEADER *bitmap_header; REFERENCE_TIME start_time, end_time; - VMR9PresentationInfo info = {0}; - D3DLOCKED_RECT locked_rect; + VMRPRESENTATIONINFO info = {0}; + DDSURFACEDESC2 surface_desc; BYTE *data = NULL; HRESULT hr; int height; @@ -199,6 +165,7 @@ static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample) return hr; } data_size = IMediaSample_GetActualDataLength(sample); + TRACE("Sample size %u.\n", data_size);
bitmap_header = get_filter_bitmap_header(filter); width = bitmap_header->biWidth; @@ -210,13 +177,20 @@ static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample) else /* packed YUV (UYVY or YUY2) or RGB */ src_pitch = ((width * depth / 8) + 3) & ~3;
+ info.dwFlags = VMRSample_TimeValid; info.rtStart = start_time; info.rtEnd = end_time; info.szAspectRatio.cx = width; info.szAspectRatio.cy = height; - info.lpSurf = filter->surfaces[(++filter->surface_index) % filter->surface_count]; + info.lpSurf = filter->surfaces[(--filter->surface_index) % filter->surface_count];
- if (FAILED(hr = IDirect3DSurface9_LockRect(info.lpSurf, &locked_rect, NULL, D3DLOCK_DISCARD))) + hr = IVMRSurfaceAllocator_PrepareSurface(filter->allocator, filter->cookie, info.lpSurf, 0); + if (hr != S_OK) + ERR("PrepareSurface() returned %#lx.\n", hr); + + surface_desc.dwSize = sizeof(surface_desc); + if (FAILED(hr = IDirectDrawSurface7_Lock(info.lpSurf, NULL, + &surface_desc, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, NULL))) { ERR("Failed to lock surface, hr %#lx.\n", hr); return hr; @@ -224,43 +198,43 @@ static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample)
if (height > 0 && bitmap_header->biCompression == BI_RGB) { - BYTE *dst = (BYTE *)locked_rect.pBits + (height * locked_rect.Pitch); + BYTE *dst = (BYTE *)surface_desc.lpSurface + (height * surface_desc.lPitch); const BYTE *src = data;
TRACE("Inverting image.\n");
while (height--) { - dst -= locked_rect.Pitch; + dst -= surface_desc.lPitch; memcpy(dst, src, width * depth / 8); src += src_pitch; } } - else if (locked_rect.Pitch != src_pitch) + else if (surface_desc.lPitch != src_pitch) { - BYTE *dst = locked_rect.pBits; + BYTE *dst = surface_desc.lpSurface; const BYTE *src = data;
height = abs(height);
- TRACE("Source pitch %u does not match dest pitch %u; copying manually.\n", - src_pitch, locked_rect.Pitch); + TRACE("Source pitch %u does not match dest pitch %lu; copying manually.\n", + src_pitch, surface_desc.lPitch);
while (height--) { memcpy(dst, src, width * depth / 8); src += src_pitch; - dst += locked_rect.Pitch; + dst += surface_desc.lPitch; } } else { - memcpy(locked_rect.pBits, data, data_size); + memcpy(surface_desc.lpSurface, data, data_size); }
- IDirect3DSurface9_UnlockRect(info.lpSurf); + IDirectDrawSurface7_Unlock(info.lpSurf, NULL);
- return IVMRImagePresenter9_PresentImage(filter->presenter, filter->cookie, &info); + return IVMRImagePresenter_PresentImage(filter->presenter, filter->cookie, &info); }
static HRESULT vmr_query_accept(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt) @@ -275,26 +249,43 @@ static HRESULT vmr_query_accept(struct strmbase_renderer *iface, const AM_MEDIA_ return S_OK; }
-static HRESULT initialize_device(struct vmr7 *filter, VMR9AllocationInfo *info, DWORD count) +static HRESULT initialize_device(struct vmr7 *filter, VMRALLOCATIONINFO *info, DWORD count) { + IDirectDrawSurface7 *frontbuffer, *prev; + IVMRWindowlessControl *control; HRESULT hr;
- if (FAILED(hr = IVMRSurfaceAllocator9_InitializeDevice(filter->allocator, - filter->cookie, info, &count))) + if (FAILED(hr = IVMRSurfaceAllocator_AllocateSurface(filter->allocator, + filter->cookie, info, &count, &frontbuffer))) { - WARN("Failed to initialize device (flags %#lx), hr %#lx.\n", info->dwFlags, hr); + WARN("Failed to allocate surface, hr %#lx.\n", hr); return hr; }
+ if (filter->mode != VMRMode_Renderless) + { + IVMRSurfaceAllocator_QueryInterface(filter->allocator, &IID_IVMRWindowlessControl, (void **)&control); + IVMRWindowlessControl_SetVideoClippingWindow(control, + filter->mode == VMRMode_Windowed ? filter->window.hwnd : filter->clipping_window); + IVMRWindowlessControl_Release(control); + } + + if (!(filter->surfaces = calloc(count, sizeof(IDirectDrawSurface7 *)))) + return E_OUTOFMEMORY; + filter->surface_count = count; + filter->surface_index = 0; + + prev = frontbuffer; for (DWORD i = 0; i < count; ++i) { - if (FAILED(hr = IVMRSurfaceAllocator9_GetSurface(filter->allocator, - filter->cookie, i, 0, &filter->surfaces[i]))) + DDSCAPS2 caps = {.dwCaps = DDSCAPS_FLIP}; + + if (FAILED(hr = IDirectDrawSurface7_GetAttachedSurface(prev, &caps, &filter->surfaces[i]))) { ERR("Failed to get surface %lu, hr %#lx.\n", i, hr); while (i--) - IDirect3DSurface9_Release(filter->surfaces[i]); - IVMRSurfaceAllocator9_TerminateDevice(filter->allocator, filter->cookie); + IDirectDrawSurface7_Release(filter->surfaces[i]); + IVMRSurfaceAllocator_FreeSurface(filter->allocator, filter->cookie); return hr; } } @@ -304,8 +295,8 @@ static HRESULT initialize_device(struct vmr7 *filter, VMR9AllocationInfo *info,
static HRESULT allocate_surfaces(struct vmr7 *filter, const AM_MEDIA_TYPE *mt) { - const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(mt); - VMR9AllocationInfo info = {0}; + BITMAPINFOHEADER bitmap_header = *get_bitmap_header(mt); + VMRALLOCATIONINFO info = {0}; HRESULT hr = E_FAIL; DWORD count = 1;
@@ -315,45 +306,12 @@ static HRESULT allocate_surfaces(struct vmr7 *filter, const AM_MEDIA_TYPE *mt) if (filter->mode == VMRMode_Windowless && !filter->clipping_window) return S_OK;
- info.Pool = D3DPOOL_DEFAULT; - info.MinBuffers = count; - info.dwWidth = info.szAspectRatio.cx = info.szNativeSize.cx = bitmap_header->biWidth; - info.dwHeight = info.szAspectRatio.cy = info.szNativeSize.cy = bitmap_header->biHeight; + info.dwFlags = AMAP_DIRECTED_FLIP | AMAP_ALLOW_SYSMEM; + info.lpHdr = &bitmap_header; + info.dwMinBuffers = info.dwMaxBuffers = count; + info.szAspectRatio.cx = info.szNativeSize.cx = bitmap_header.biWidth; + info.szAspectRatio.cy = info.szNativeSize.cy = bitmap_header.biHeight;
- if (!(filter->surfaces = calloc(count, sizeof(IDirect3DSurface9 *)))) - return E_OUTOFMEMORY; - filter->surface_count = count; - filter->surface_index = 0; - - switch (bitmap_header->biCompression) - { - case BI_RGB: - switch (bitmap_header->biBitCount) - { - case 24: info.Format = D3DFMT_R8G8B8; break; - case 32: info.Format = D3DFMT_X8R8G8B8; break; - default: - FIXME("Unhandled bit depth %u.\n", bitmap_header->biBitCount); - free(filter->surfaces); - return VFW_E_TYPE_NOT_ACCEPTED; - } - - info.dwFlags = VMR9AllocFlag_TextureSurface; - break; - - case mmioFOURCC('N','V','1','2'): - case mmioFOURCC('U','Y','V','Y'): - case mmioFOURCC('Y','U','Y','2'): - case mmioFOURCC('Y','V','1','2'): - info.Format = bitmap_header->biCompression; - info.dwFlags = VMR9AllocFlag_OffscreenSurface; - break; - - default: - WARN("Unhandled video compression %#lx.\n", bitmap_header->biCompression); - free(filter->surfaces); - return VFW_E_TYPE_NOT_ACCEPTED; - } if (FAILED(hr = initialize_device(filter, &info, count))) free(filter->surfaces); return hr; @@ -371,7 +329,7 @@ static void vmr_start_stream(struct strmbase_renderer *iface) { struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
- IVMRImagePresenter9_StartPresenting(filter->presenter, filter->cookie); + IVMRImagePresenter_StartPresenting(filter->presenter, filter->cookie); }
static void vmr_stop_stream(struct strmbase_renderer *iface) @@ -379,7 +337,7 @@ static void vmr_stop_stream(struct strmbase_renderer *iface) struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
if (filter->renderer.filter.state == State_Running) - IVMRImagePresenter9_StopPresenting(filter->presenter, filter->cookie); + IVMRImagePresenter_StopPresenting(filter->presenter, filter->cookie); }
static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt) @@ -411,10 +369,10 @@ static void deallocate_surfaces(struct vmr7 *filter) if (filter->mode && filter->allocator && filter->presenter) { for (DWORD i = 0; i < filter->surface_count; ++i) - IDirect3DSurface9_Release(filter->surfaces[i]); + IDirectDrawSurface7_Release(filter->surfaces[i]); free(filter->surfaces);
- IVMRSurfaceAllocator9_TerminateDevice(filter->allocator, filter->cookie); + IVMRSurfaceAllocator_FreeSurface(filter->allocator, filter->cookie); filter->surface_count = 0; } } @@ -434,20 +392,15 @@ static void vmr_destroy(struct strmbase_renderer *iface)
if (filter->allocator) { - IVMRSurfaceAllocator9_TerminateDevice(filter->allocator, filter->cookie); - IVMRSurfaceAllocator9_Release(filter->allocator); + if (filter->surface_count) + IVMRSurfaceAllocator_FreeSurface(filter->allocator, filter->cookie); + IVMRSurfaceAllocator_Release(filter->allocator); } if (filter->presenter) - IVMRImagePresenter9_Release(filter->presenter); + IVMRImagePresenter_Release(filter->presenter);
filter->surface_count = 0; - if (filter->device) - { - IDirect3DDevice9_Release(filter->device); - filter->device = NULL; - }
- FreeLibrary(filter->d3d9_module); strmbase_renderer_cleanup(&filter->renderer); free(filter); } @@ -518,65 +471,8 @@ static void vmr_get_default_rect(struct video_window *iface, RECT *rect)
static HRESULT vmr_get_current_image(struct video_window *iface, LONG *size, LONG *image) { - struct vmr7 *filter = impl_from_video_window(iface); - IDirect3DSurface9 *rt = NULL, *surface = NULL; - D3DLOCKED_RECT locked_rect; - IDirect3DDevice9 *device; - unsigned int row_size; - BITMAPINFOHEADER bih; - LONG size_left; - HRESULT hr; - char *dst; - - EnterCriticalSection(&filter->renderer.filter.stream_cs); - device = filter->device; - - bih = *get_filter_bitmap_header(filter); - bih.biSizeImage = bih.biWidth * bih.biHeight * bih.biBitCount / 8; - - if (!image) - { - *size = sizeof(BITMAPINFOHEADER) + bih.biSizeImage; - LeaveCriticalSection(&filter->renderer.filter.stream_cs); - return S_OK; - } - - if (FAILED(hr = IDirect3DDevice9_GetRenderTarget(device, 0, &rt))) - goto out; - - if (FAILED(hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, bih.biWidth, - bih.biHeight, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL))) - goto out; - - if (FAILED(hr = IDirect3DDevice9_GetRenderTargetData(device, rt, surface))) - goto out; - - if (FAILED(hr = IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, D3DLOCK_READONLY))) - goto out; - - size_left = *size; - memcpy(image, &bih, min(size_left, sizeof(BITMAPINFOHEADER))); - size_left -= sizeof(BITMAPINFOHEADER); - - dst = (char *)image + sizeof(BITMAPINFOHEADER); - row_size = bih.biWidth * bih.biBitCount / 8; - - for (LONG i = 0; i < bih.biHeight && size_left > 0; ++i) - { - memcpy(dst, (char *)locked_rect.pBits + (i * locked_rect.Pitch), min(row_size, size_left)); - dst += row_size; - size_left -= row_size; - } - - IDirect3DSurface9_UnlockRect(surface); - -out: - if (surface) - IDirect3DSurface9_Release(surface); - if (rt) - IDirect3DSurface9_Release(rt); - LeaveCriticalSection(&filter->renderer.filter.stream_cs); - return hr; + FIXME("stub!\n"); + return E_NOTIMPL; }
static const struct video_window_ops window_ops = @@ -806,7 +702,7 @@ static HRESULT WINAPI filter_config_GetRenderingPrefs(IVMRFilterConfig *iface, D static HRESULT WINAPI filter_config_SetRenderingMode(IVMRFilterConfig *iface, DWORD mode) { struct vmr7 *filter = impl_from_IVMRFilterConfig(iface); - struct default_presenter *default_presenter; + IUnknown *default_presenter; HRESULT hr = S_OK;
TRACE("filter %p, mode %lu.\n", filter, mode); @@ -823,15 +719,15 @@ static HRESULT WINAPI filter_config_SetRenderingMode(IVMRFilterConfig *iface, DW { case VMRMode_Windowed: case VMRMode_Windowless: - if (FAILED(hr = default_presenter_create(filter, &default_presenter))) + if (FAILED(hr = vmr7_presenter_create(NULL, &default_presenter))) { ERR("Failed to create default presenter, hr %#lx.\n", hr); LeaveCriticalSection(&filter->renderer.filter.filter_cs); return hr; } - filter->allocator = &default_presenter->IVMRSurfaceAllocator9_iface; - filter->presenter = &default_presenter->IVMRImagePresenter9_iface; - IVMRImagePresenter9_AddRef(filter->presenter); + IUnknown_QueryInterface(default_presenter, &IID_IVMRSurfaceAllocator, (void **)&filter->allocator); + IUnknown_QueryInterface(default_presenter, &IID_IVMRImagePresenter, (void **)&filter->presenter); + IUnknown_Release(default_presenter); break;
case VMRMode_Renderless: @@ -1331,116 +1227,6 @@ static const IVMRSurfaceAllocatorNotifyVtbl surface_allocator_notify_vtbl = surface_allocator_notify_SetBorderColor, };
-static void vmr_set_d3d_device(struct vmr7 *filter, IDirect3DDevice9 *device, HMONITOR monitor) -{ - if (filter->device) - IDirect3DDevice9_Release(filter->device); - filter->device = device; - IDirect3DDevice9_AddRef(device); -} - -static HRESULT vmr_allocate_d3d9_surfaces(struct vmr7 *filter, - VMR9AllocationInfo *info, DWORD *count, IDirect3DSurface9 **surfaces) -{ - HRESULT hr = S_OK; - DWORD i; - - TRACE("filter %p, info %p, count %p, surfaces %p.\n", filter, count, info, surfaces); - - if (!info || !count || !surfaces) - return E_POINTER; - - TRACE("Flags %#lx, size %lux%lu, format %u (%#x), pool %u, minimum buffers %lu.\n", - info->dwFlags, info->dwWidth, info->dwHeight, - info->Format, info->Format, info->Pool, info->MinBuffers); - - if ((info->dwFlags & VMR9AllocFlag_TextureSurface) - && (info->dwFlags & VMR9AllocFlag_OffscreenSurface)) - { - WARN("Invalid flags specified; returning E_INVALIDARG.\n"); - return E_INVALIDARG; - } - - if (!info->Format) - { - IDirect3DSurface9 *backbuffer; - D3DSURFACE_DESC desc; - - IDirect3DDevice9_GetBackBuffer(filter->device, 0, 0, - D3DBACKBUFFER_TYPE_MONO, &backbuffer); - IDirect3DSurface9_GetDesc(backbuffer, &desc); - IDirect3DSurface9_Release(backbuffer); - info->Format = desc.Format; - } - - if (!*count || *count < info->MinBuffers) - { - WARN("%lu surfaces requested (minimum %lu); returning E_INVALIDARG.\n", - *count, info->MinBuffers); - return E_INVALIDARG; - } - - if (!filter->device) - { - WARN("No Direct3D device; returning VFW_E_WRONG_STATE.\n"); - return VFW_E_WRONG_STATE; - } - - if (info->dwFlags == VMR9AllocFlag_OffscreenSurface) - { - for (i = 0; i < *count; ++i) - { - if (FAILED(hr = IDirect3DDevice9_CreateOffscreenPlainSurface(filter->device, - info->dwWidth, info->dwHeight, info->Format, info->Pool, &surfaces[i], NULL))) - break; - } - } - else if (info->dwFlags == VMR9AllocFlag_TextureSurface) - { - for (i = 0; i < *count; ++i) - { - IDirect3DTexture9 *texture; - - if (FAILED(hr = IDirect3DDevice9_CreateTexture(filter->device, info->dwWidth, - info->dwHeight, 1, D3DUSAGE_DYNAMIC, info->Format, info->Pool, &texture, NULL))) - break; - IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surfaces[i]); - IDirect3DTexture9_Release(texture); - } - } - else if (info->dwFlags == VMR9AllocFlag_3DRenderTarget) - { - for (i = 0; i < *count; ++i) - { - if (FAILED(hr = IDirect3DDevice9_CreateRenderTarget(filter->device, - info->dwWidth, info->dwHeight, info->Format, - D3DMULTISAMPLE_NONE, 0, FALSE, &surfaces[i], NULL))) - break; - } - } - else - { - FIXME("Unhandled flags %#lx.\n", info->dwFlags); - return E_NOTIMPL; - } - - if (FAILED(hr)) - WARN("%lu/%lu surfaces allocated, hr %#lx.\n", i, *count, hr); - - if (i >= info->MinBuffers) - { - hr = S_OK; - *count = i; - } - else - { - for (; i > 0; --i) - IDirect3DSurface9_Release(surfaces[i - 1]); - *count = 0; - } - return hr; -} - static struct vmr7 *impl_from_IAMVideoAccelerator(IAMVideoAccelerator *iface) { return CONTAINING_RECORD(iface, struct vmr7, IAMVideoAccelerator_iface); @@ -1695,14 +1481,6 @@ HRESULT vmr7_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- object->d3d9_module = LoadLibraryA("d3d9.dll"); - if (!object->d3d9_module) - { - WARN("Could not load d3d9.dll\n"); - free(object); - return VFW_E_DDRAW_CAPS_NOT_SUITABLE; - } - strmbase_renderer_init(&object->renderer, outer, &CLSID_VideoMixingRenderer, L"VMR Input0", &renderer_ops); object->IAMCertifiedOutputProtection_iface.lpVtbl = &certified_output_protection_vtbl; object->IAMFilterMiscFlags_iface.lpVtbl = &misc_flags_vtbl; @@ -1721,7 +1499,6 @@ HRESULT vmr7_create(IUnknown *outer, IUnknown **out) { video_window_cleanup(&object->window); strmbase_renderer_cleanup(&object->renderer); - FreeLibrary(object->d3d9_module); free(object); return hr; } @@ -1733,389 +1510,3 @@ HRESULT vmr7_create(IUnknown *outer, IUnknown **out) *out = &object->renderer.filter.IUnknown_inner; return S_OK; } - -static HRESULT WINAPI VMR9_ImagePresenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out) -{ - struct default_presenter *presenter = impl_from_IVMRImagePresenter9(iface); - - TRACE("presenter %p, iid %s, out %p.\n", presenter, debugstr_guid(iid), out); - - if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IVMRImagePresenter9)) - *out = &presenter->IVMRImagePresenter9_iface; - else if (IsEqualIID(iid, &IID_IVMRSurfaceAllocator9)) - *out = &presenter->IVMRSurfaceAllocator9_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI VMR9_ImagePresenter_AddRef(IVMRImagePresenter9 *iface) -{ - struct default_presenter *presenter = impl_from_IVMRImagePresenter9(iface); - ULONG refcount = InterlockedIncrement(&presenter->refcount); - - TRACE("%p increasing refcount to %lu.\n", presenter, refcount); - - return refcount; -} - -static ULONG WINAPI VMR9_ImagePresenter_Release(IVMRImagePresenter9 *iface) -{ - struct default_presenter *presenter = impl_from_IVMRImagePresenter9(iface); - ULONG refcount = InterlockedDecrement(&presenter->refcount); - - TRACE("%p decreasing refcount to %lu.\n", presenter, refcount); - - if (!refcount) - { - IDirect3D9_Release(presenter->d3d9); - - for (DWORD i = 0; i < presenter->surface_count; ++i) - { - IDirect3DSurface9 *surface = presenter->surfaces[i]; - - if (surface) - IDirect3DSurface9_Release(surface); - } - - if (presenter->device) - IDirect3DDevice9_Release(presenter->device); - free(presenter->surfaces); - presenter->surfaces = NULL; - presenter->surface_count = 0; - free(presenter); - return 0; - } - return refcount; -} - -static HRESULT WINAPI VMR9_ImagePresenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie) -{ - struct default_presenter *presenter = impl_from_IVMRImagePresenter9(iface); - - TRACE("presenter %p, cookie %#Ix.\n", presenter, cookie); - - return S_OK; -} - -static HRESULT WINAPI VMR9_ImagePresenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie) -{ - struct default_presenter *presenter = impl_from_IVMRImagePresenter9(iface); - - TRACE("presenter %p, cookie %#Ix.\n", presenter, cookie); - - return S_OK; -} - -static HRESULT WINAPI VMR9_ImagePresenter_PresentImage(IVMRImagePresenter9 *iface, - DWORD_PTR cookie, VMR9PresentationInfo *info) -{ - struct default_presenter *presenter = impl_from_IVMRImagePresenter9(iface); - IDirect3DDevice9 *device = presenter->device; - const struct vmr7 *filter = presenter->vmr; - const RECT src = filter->window.src; - IDirect3DSurface9 *backbuffer; - RECT dst = filter->window.dst; - HRESULT hr; - - TRACE("presenter %p, cookie %#Ix, info %p.\n", presenter, cookie, info); - - /* presenter might happen if we don't have active focus (eg on a different virtual desktop) */ - if (!device) - return S_OK; - - if (FAILED(hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, - D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0))) - ERR("Failed to clear, hr %#lx.\n", hr); - - if (FAILED(hr = IDirect3DDevice9_BeginScene(device))) - ERR("Failed to begin scene, hr %#lx.\n", hr); - - if (FAILED(hr = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer))) - { - ERR("Failed to get backbuffer, hr %#lx.\n", hr); - return hr; - } - - if (FAILED(hr = IDirect3DDevice9_StretchRect(device, info->lpSurf, NULL, backbuffer, NULL, D3DTEXF_POINT))) - ERR("Failed to blit image, hr %#lx.\n", hr); - IDirect3DSurface9_Release(backbuffer); - - if (FAILED(hr = IDirect3DDevice9_EndScene(device))) - ERR("Failed to end scene, hr %#lx.\n", hr); - - if (filter->aspect_mode == VMR9ARMode_LetterBox) - { - unsigned int src_width = src.right - src.left, src_height = src.bottom - src.top; - unsigned int dst_width = dst.right - dst.left, dst_height = dst.bottom - dst.top; - - if (src_width * dst_height > dst_width * src_height) - { - /* src is "wider" than dst. */ - unsigned int dst_center = (dst.top + dst.bottom) / 2; - unsigned int scaled_height = src_height * dst_width / src_width; - - dst.top = dst_center - scaled_height / 2; - dst.bottom = dst.top + scaled_height; - } - else if (src_width * dst_height < dst_width * src_height) - { - /* src is "taller" than dst. */ - unsigned int dst_center = (dst.left + dst.right) / 2; - unsigned int scaled_width = src_width * dst_height / src_height; - - dst.left = dst_center - scaled_width / 2; - dst.right = dst.left + scaled_width; - } - } - - if (FAILED(hr = IDirect3DDevice9_Present(device, &src, &dst, NULL, NULL))) - ERR("Failed to present, hr %#lx.\n", hr); - - return S_OK; -} - -static const IVMRImagePresenter9Vtbl VMR9_ImagePresenter = -{ - VMR9_ImagePresenter_QueryInterface, - VMR9_ImagePresenter_AddRef, - VMR9_ImagePresenter_Release, - VMR9_ImagePresenter_StartPresenting, - VMR9_ImagePresenter_StopPresenting, - VMR9_ImagePresenter_PresentImage -}; - -static HRESULT WINAPI VMR9_SurfaceAllocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REFIID iid, void **out) -{ - struct default_presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface); - - return IVMRImagePresenter9_QueryInterface(&presenter->IVMRImagePresenter9_iface, iid, out); -} - -static ULONG WINAPI VMR9_SurfaceAllocator_AddRef(IVMRSurfaceAllocator9 *iface) -{ - struct default_presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface); - - return IVMRImagePresenter9_AddRef(&presenter->IVMRImagePresenter9_iface); -} - -static ULONG WINAPI VMR9_SurfaceAllocator_Release(IVMRSurfaceAllocator9 *iface) -{ - struct default_presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface); - - return IVMRImagePresenter9_Release(&presenter->IVMRImagePresenter9_iface); -} - -static void adjust_surface_size(const D3DCAPS9 *caps, VMR9AllocationInfo *info) -{ - unsigned int width, height; - - /* There are no restrictions on the size of offscreen surfaces. */ - if (!(info->dwFlags & VMR9AllocFlag_TextureSurface)) - return; - - if (!(caps->TextureCaps & D3DPTEXTURECAPS_POW2) || (caps->TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)) - { - width = info->dwWidth; - height = info->dwHeight; - } - else - { - width = height = 1; - while (width < info->dwWidth) - width *= 2; - - while (height < info->dwHeight) - height *= 2; - FIXME("Non-power-of-two textures are not supported.\n"); - } - - if (caps->TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) - { - if (height > width) - width = height; - else - height = width; - FIXME("Rectangular textures are not supported.\n"); - } - - info->dwHeight = height; - info->dwWidth = width; -} - -static UINT adapter_index_from_hwnd(IDirect3D9 *d3d9, HWND hwnd, HMONITOR *ret_monitor) -{ - UINT adapter_index; - HMONITOR monitor; - - monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); - if (!monitor) - adapter_index = 0; - else - { - for (adapter_index = 0; adapter_index < IDirect3D9_GetAdapterCount(d3d9); ++adapter_index) - { - if (monitor == IDirect3D9_GetAdapterMonitor(d3d9, adapter_index)) - break; - } - if (adapter_index >= IDirect3D9_GetAdapterCount(d3d9)) - adapter_index = 0; - } - if (ret_monitor) - *ret_monitor = monitor; - return adapter_index; -} - -static HRESULT WINAPI VMR9_SurfaceAllocator_InitializeDevice(IVMRSurfaceAllocator9 *iface, - DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *count) -{ - struct default_presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface); - D3DPRESENT_PARAMETERS present_parameters = {0}; - IDirect3DDevice9 *device; - DWORD adapter_index; - D3DCAPS9 caps; - HWND window; - HRESULT hr; - - TRACE("presenter %p, cookie %#Ix, info %p, count %p.\n", presenter, cookie, info, count); - - presenter->info = *info; - - if (presenter->vmr->mode == VMRMode_Windowed) - window = presenter->vmr->window.hwnd; - else - window = presenter->vmr->clipping_window; - - adapter_index = adapter_index_from_hwnd(presenter->d3d9, window, &presenter->monitor); - - present_parameters.Windowed = TRUE; - present_parameters.hDeviceWindow = window; - present_parameters.SwapEffect = D3DSWAPEFFECT_COPY; - present_parameters.BackBufferWidth = info->dwWidth; - present_parameters.BackBufferHeight = info->dwHeight; - - hr = IDirect3D9_CreateDevice(presenter->d3d9, adapter_index, D3DDEVTYPE_HAL, - NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &present_parameters, &device); - if (FAILED(hr)) - { - ERR("Failed to create device, hr %#lx.\n", hr); - return hr; - } - - IDirect3DDevice9_GetDeviceCaps(device, &caps); - if (!(caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES)) - { - WARN("Device does not support blitting from textures.\n"); - IDirect3DDevice9_Release(device); - return VFW_E_DDRAW_CAPS_NOT_SUITABLE; - } - - presenter->device = device; - vmr_set_d3d_device(presenter->vmr, presenter->device, presenter->monitor); - - if (!(presenter->surfaces = calloc(*count, sizeof(IDirect3DSurface9 *)))) - return E_OUTOFMEMORY; - - adjust_surface_size(&caps, info); - - if (FAILED(hr = vmr_allocate_d3d9_surfaces(presenter->vmr, info, count, presenter->surfaces))) - { - ERR("Failed to allocate surfaces, hr %#lx.\n", hr); - IVMRSurfaceAllocator9_TerminateDevice(presenter->vmr->allocator, presenter->vmr->cookie); - return hr; - } - - presenter->surface_count = *count; - - return S_OK; -} - -static HRESULT WINAPI VMR9_SurfaceAllocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie) -{ - TRACE("iface %p, cookie %#Ix.\n", iface, cookie); - - return S_OK; -} - -static HRESULT WINAPI VMR9_SurfaceAllocator_GetSurface(IVMRSurfaceAllocator9 *iface, - DWORD_PTR cookie, DWORD index, DWORD flags, IDirect3DSurface9 **surface) -{ - struct default_presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface); - - if (!presenter->device) - { - ERR("No device.\n"); - return E_FAIL; - } - - if (index >= presenter->surface_count) - { - ERR("Index %lu exceeds surface count %lu.\n", index, presenter->surface_count); - return E_FAIL; - } - *surface = presenter->surfaces[index]; - IDirect3DSurface9_AddRef(*surface); - - return S_OK; -} - -static HRESULT WINAPI VMR9_SurfaceAllocator_AdviseNotify(IVMRSurfaceAllocator9 *iface, - IVMRSurfaceAllocatorNotify9 *notify) -{ - ERR("Unexpected call.\n"); - return S_OK; -} - -static const IVMRSurfaceAllocator9Vtbl VMR9_SurfaceAllocator = -{ - VMR9_SurfaceAllocator_QueryInterface, - VMR9_SurfaceAllocator_AddRef, - VMR9_SurfaceAllocator_Release, - VMR9_SurfaceAllocator_InitializeDevice, - VMR9_SurfaceAllocator_TerminateDevice, - VMR9_SurfaceAllocator_GetSurface, - VMR9_SurfaceAllocator_AdviseNotify, -}; - -static IDirect3D9 *init_d3d9(HMODULE d3d9_handle) -{ - IDirect3D9 * (__stdcall *d3d9_create)(UINT version); - - d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9"); - if (!d3d9_create) - return NULL; - - return d3d9_create(D3D_SDK_VERSION); -} - -static HRESULT default_presenter_create(struct vmr7 *parent, struct default_presenter **presenter) -{ - struct default_presenter *object; - - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; - - object->d3d9 = init_d3d9(parent->d3d9_module); - if (!object->d3d9) - { - WARN("Could not initialize d3d9.dll\n"); - free(object); - return VFW_E_DDRAW_CAPS_NOT_SUITABLE; - } - - object->IVMRImagePresenter9_iface.lpVtbl = &VMR9_ImagePresenter; - object->IVMRSurfaceAllocator9_iface.lpVtbl = &VMR9_SurfaceAllocator; - - object->refcount = 1; - object->vmr = parent; - - TRACE("Created default presenter %p.\n", object); - *presenter = object; - return S_OK; -}
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/quartz/vmr7.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/dlls/quartz/vmr7.c b/dlls/quartz/vmr7.c index 5b1b13b7436..2a077f266ab 100644 --- a/dlls/quartz/vmr7.c +++ b/dlls/quartz/vmr7.c @@ -1176,8 +1176,39 @@ static ULONG WINAPI surface_allocator_notify_Release(IVMRSurfaceAllocatorNotify static HRESULT WINAPI surface_allocator_notify_AdviseSurfaceAllocator( IVMRSurfaceAllocatorNotify *iface, DWORD_PTR cookie, IVMRSurfaceAllocator *allocator) { - FIXME("iface %p, cookie %#Ix, allocator %p, stub!\n", iface, cookie, allocator); - return E_NOTIMPL; + struct vmr7 *filter = impl_from_IVMRSurfaceAllocatorNotify(iface); + IVMRImagePresenter *presenter; + + TRACE("filter %p, cookie %#Ix, allocator %p.\n", filter, cookie, allocator); + + EnterCriticalSection(&filter->renderer.filter.filter_cs); + + filter->cookie = cookie; + + if (filter->renderer.sink.pin.peer) + { + LeaveCriticalSection(&filter->renderer.filter.filter_cs); + WARN("Attempt to set allocator while connected; returning VFW_E_WRONG_STATE.\n"); + return VFW_E_WRONG_STATE; + } + + if (FAILED(IVMRSurfaceAllocator_QueryInterface(allocator, &IID_IVMRImagePresenter, (void **)&presenter))) + { + LeaveCriticalSection(&filter->renderer.filter.filter_cs); + return E_NOINTERFACE; + } + + if (filter->allocator) + { + IVMRImagePresenter_Release(filter->presenter); + IVMRSurfaceAllocator_Release(filter->allocator); + } + filter->allocator = allocator; + filter->presenter = presenter; + IVMRSurfaceAllocator_AddRef(allocator); + + LeaveCriticalSection(&filter->renderer.filter.filter_cs); + return S_OK; }
static HRESULT WINAPI surface_allocator_notify_SetDDrawDevice(
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/quartz/vmr7_presenter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 0c6cb6dedbd..406c9ead52a 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -235,8 +235,8 @@ static HRESULT WINAPI surface_allocator_FreeSurface(IVMRSurfaceAllocator *iface, static HRESULT WINAPI surface_allocator_PrepareSurface(IVMRSurfaceAllocator *iface, DWORD_PTR id, IDirectDrawSurface7 *surface, DWORD flags) { - FIXME("iface %p, id %#Ix, surface %p, flags %#lx, stub!\n", iface, id, surface, flags); - return E_NOTIMPL; + TRACE("iface %p, id %#Ix, surface %p, flags %#lx.\n", iface, id, surface, flags); + return S_OK; }
static HRESULT WINAPI surface_allocator_AdviseNotify(IVMRSurfaceAllocator *iface,
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/quartz/tests/vmr7.c | 467 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 467 insertions(+)
diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index 7cb94338126..37834517425 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -3156,6 +3156,472 @@ static void test_unconnected_eos(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static IDirectDraw7 *create_ddraw(HWND window) +{ + DDSURFACEDESC2 desc = {.dwSize = sizeof(desc)}; + IDirectDraw7 *ddraw; + HRESULT hr; + + if (FAILED(DirectDrawCreateEx(NULL, (void **)&ddraw, &IID_IDirectDraw7, NULL))) + return NULL; + + hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + return ddraw; +} + +struct presenter +{ + IVMRSurfaceAllocator IVMRSurfaceAllocator_iface; + IVMRImagePresenter IVMRImagePresenter_iface; + LONG refcount; + + IDirectDraw7 *ddraw; + IDirectDrawSurface7 *surfaces[6]; + DWORD surface_count; + + BITMAPINFOHEADER format; + IVMRSurfaceAllocatorNotify *notify; + unsigned int got_PresentImage, got_PrepareSurface; +}; + +static struct presenter *impl_from_IVMRImagePresenter(IVMRImagePresenter *iface) +{ + return CONTAINING_RECORD(iface, struct presenter, IVMRImagePresenter_iface); +} + +static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter *iface, REFIID iid, void **out) +{ + struct presenter *presenter = impl_from_IVMRImagePresenter(iface); + return IVMRSurfaceAllocator_QueryInterface(&presenter->IVMRSurfaceAllocator_iface, iid, out); +} + +static ULONG WINAPI presenter_AddRef(IVMRImagePresenter *iface) +{ + struct presenter *presenter = impl_from_IVMRImagePresenter(iface); + return IVMRSurfaceAllocator_AddRef(&presenter->IVMRSurfaceAllocator_iface); +} + +static ULONG WINAPI presenter_Release(IVMRImagePresenter *iface) +{ + struct presenter *presenter = impl_from_IVMRImagePresenter(iface); + return IVMRSurfaceAllocator_Release(&presenter->IVMRSurfaceAllocator_iface); +} + +static HRESULT WINAPI presenter_StartPresenting(IVMRImagePresenter *iface, DWORD_PTR cookie) +{ + if (winetest_debug > 1) trace("StartPresenting()\n"); + ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI presenter_StopPresenting(IVMRImagePresenter *iface, DWORD_PTR cookie) +{ + if (winetest_debug > 1) trace("StopPresenting()\n"); + ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter *iface, DWORD_PTR cookie, VMRPRESENTATIONINFO *info) +{ + struct presenter *presenter = impl_from_IVMRImagePresenter(iface); + static const RECT rect; + + if (winetest_debug > 1) trace("PresentImage(surface %p)\n", info->lpSurf); + + ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); + ok(info->dwFlags == VMRSample_TimeValid, "Got flags %#lx.\n", info->dwFlags); + todo_wine ok(info->lpSurf == presenter->surfaces[5 - presenter->got_PresentImage], "Got unexpected surface.\n"); + ok(!info->rtStart, "Got start time %s.\n", wine_dbgstr_longlong(info->rtStart)); + ok(info->rtEnd == 10000000, "Got end time %s.\n", wine_dbgstr_longlong(info->rtEnd)); + todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %ld.\n", info->szAspectRatio.cx); + todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %ld.\n", info->szAspectRatio.cy); + ok(EqualRect(&info->rcSrc, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&info->rcSrc)); + ok(EqualRect(&info->rcDst, &rect), "Got dest rect %s.\n", wine_dbgstr_rect(&info->rcDst)); + ok(!info->dwTypeSpecificFlags, "Got type-specific flags %#lx.\n", info->dwTypeSpecificFlags); + ok(!info->dwInterlaceFlags, "Got interlace flags %#lx.\n", info->dwInterlaceFlags); + + ++presenter->got_PresentImage; + ok(presenter->got_PresentImage == presenter->got_PrepareSurface, + "Got %u calls to PrepareSurface(); %u calls to PresentImage().\n", + presenter->got_PrepareSurface, presenter->got_PresentImage); + + return S_OK; +} + +static const IVMRImagePresenterVtbl presenter_vtbl = +{ + presenter_QueryInterface, + presenter_AddRef, + presenter_Release, + presenter_StartPresenting, + presenter_StopPresenting, + presenter_PresentImage, +}; + +static struct presenter *impl_from_IVMRSurfaceAllocator(IVMRSurfaceAllocator *iface) +{ + return CONTAINING_RECORD(iface, struct presenter, IVMRSurfaceAllocator_iface); +} + +static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator *iface, REFIID iid, void **out) +{ + struct presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + + if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid)); + + if (IsEqualGUID(iid, &IID_IVMRImagePresenter)) + { + *out = &presenter->IVMRImagePresenter_iface; + IVMRImagePresenter_AddRef(&presenter->IVMRImagePresenter_iface); + return S_OK; + } + ok(!IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorEx9), "Unexpected query for IVMRSurfaceAllocatorEx9.\n"); + *out = NULL; + return E_NOTIMPL; +} + +static ULONG WINAPI allocator_AddRef(IVMRSurfaceAllocator *iface) +{ + struct presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + return InterlockedIncrement(&presenter->refcount); +} + +static ULONG WINAPI allocator_Release(IVMRSurfaceAllocator *iface) +{ + struct presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + return InterlockedDecrement(&presenter->refcount); +} + +static HRESULT WINAPI allocator_AllocateSurface(IVMRSurfaceAllocator *iface, + DWORD_PTR cookie, VMRALLOCATIONINFO *info, DWORD *buffer_count, IDirectDrawSurface7 **surface) +{ + struct presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + DDSURFACEDESC2 surface_desc = {.dwSize = sizeof(surface_desc)}; + HRESULT hr; + + if (winetest_debug > 1) trace("AllocateSurface()\n"); + + ok(!presenter->surfaces[0], "Surface should not already exist.\n"); + + ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); + ok(info->dwFlags == (AMAP_DIRECTED_FLIP | AMAP_ALLOW_SYSMEM), "Got flags %#lx.\n", info->dwFlags); + todo_wine ok(info->dwMinBuffers == 5, "Got minimum buffer count %lu.\n", info->dwMinBuffers); + todo_wine ok(info->dwMaxBuffers == 5, "Got maximum buffer count %lu.\n", info->dwMaxBuffers); + ok(!info->dwInterlaceFlags, "Got interlace flags %#lx.\n", info->dwInterlaceFlags); + todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %ld.\n", info->szAspectRatio.cx); + todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %ld.\n", info->szAspectRatio.cy); + ok(info->szNativeSize.cx == 32, "Got native width %ld.\n", info->szNativeSize.cx); + ok(info->szNativeSize.cy == 16, "Got native height %ld.\n", info->szNativeSize.cy); + todo_wine ok(*buffer_count == 5, "Got buffer count %lu.\n", *buffer_count); + ok(!info->lpPixFmt, "Got pixel format %p.\n", info->lpPixFmt); + + presenter->format = *info->lpHdr; + + surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + surface_desc.dwWidth = presenter->format.biWidth; + surface_desc.dwHeight = presenter->format.biHeight; + surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat); + surface_desc.ddsCaps.dwCaps = DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwBackBufferCount = *buffer_count; + + if (presenter->format.biCompression == BI_RGB) + { + surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; + surface_desc.ddpfPixelFormat.dwRGBBitCount = 32; + surface_desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000; + surface_desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00; + surface_desc.ddpfPixelFormat.dwBBitMask = 0x000000ff; + } + else + { + surface_desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC; + surface_desc.ddpfPixelFormat.dwFourCC = presenter->format.biCompression; + } + + hr = IDirectDraw7_CreateSurface(presenter->ddraw, &surface_desc, surface, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + presenter->surfaces[0] = *surface; + presenter->surface_count = *buffer_count; + for (unsigned int i = 0; i < *buffer_count; ++i) + { + DDSCAPS2 caps = {.dwCaps = DDSCAPS_FLIP}; + + hr = IDirectDrawSurface7_GetAttachedSurface(presenter->surfaces[i], &caps, &presenter->surfaces[i + 1]); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + + ++*buffer_count; + return S_OK; +} + +static HRESULT WINAPI allocator_FreeSurface(IVMRSurfaceAllocator *iface, DWORD_PTR cookie) +{ + struct presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + LONG ref; + + if (winetest_debug > 1) trace("FreeSurface()\n"); + + ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); + ok(!!presenter->surfaces[0], "Surface should exist.\n"); + + for (unsigned int i = 0; i < presenter->surface_count; ++i) + IDirectDrawSurface7_Release(presenter->surfaces[i + 1]); + ref = IDirectDrawSurface7_Release(presenter->surfaces[0]); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + memset(presenter->surfaces, 0, sizeof(presenter->surfaces)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI allocator_PrepareSurface(IVMRSurfaceAllocator *iface, + DWORD_PTR cookie, IDirectDrawSurface7 *surface, DWORD flags) +{ + struct presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + + if (winetest_debug > 1) trace("PrepareSurface(surface %p)\n", surface); + ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); + ok(!flags, "Got flags %#lx.\n", flags); + todo_wine ok(surface == presenter->surfaces[5 - presenter->got_PrepareSurface], "Got unexpected surface.\n"); + ++presenter->got_PrepareSurface; + + return S_OK; +} + +static HRESULT WINAPI allocator_AdviseNotify(IVMRSurfaceAllocator *iface, IVMRSurfaceAllocatorNotify *notify) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IVMRSurfaceAllocatorVtbl allocator_vtbl = +{ + allocator_QueryInterface, + allocator_AddRef, + allocator_Release, + allocator_AllocateSurface, + allocator_FreeSurface, + allocator_PrepareSurface, + allocator_AdviseNotify, +}; + +static void test_renderless_present(struct presenter *presenter, + IFilterGraph2 *graph, IMemInputPin *input) +{ + IMediaControl *control; + OAFilterState state; + HANDLE thread; + HRESULT hr; + + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + + presenter->got_PrepareSurface = 0; + presenter->got_PresentImage = 0; + + hr = IMediaControl_Pause(control); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + thread = send_frame(input); + hr = IMediaControl_GetState(control, 1000, &state); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(presenter->got_PrepareSurface == 1, "Got %u calls to PrepareSurface().\n", presenter->got_PrepareSurface); + ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage); + + hr = IMediaControl_Run(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = join_thread(thread); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(presenter->got_PrepareSurface == 1, "Got %u calls to PrepareSurface().\n", presenter->got_PrepareSurface); + ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage); + + thread = send_frame(input); + hr = join_thread(thread); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(presenter->got_PrepareSurface == 2, "Got %u calls to PrepareSurface().\n", presenter->got_PrepareSurface); + ok(presenter->got_PresentImage == 2, "Got %u calls to PresentImage().\n", presenter->got_PresentImage); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IMediaControl_Release(control); +} + +static void test_renderless_formats(void) +{ + VIDEOINFOHEADER vih = + { + .rcSource = {4, 6, 16, 12}, + .rcTarget = {40, 60, 160, 120}, + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = 16, + .bmiHeader.biPlanes = 1, + }; + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_WAVE, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(vih), + .pbFormat = (BYTE *)&vih, + }; + ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props; + struct presenter presenter = + { + .IVMRSurfaceAllocator_iface.lpVtbl = &allocator_vtbl, + .IVMRImagePresenter_iface.lpVtbl = &presenter_vtbl, + .refcount = 1, + }; + struct presenter presenter2 = presenter; + IVMRSurfaceAllocatorNotify *notify; + RECT rect = {0, 0, 640, 480}; + struct testfilter source; + IMemAllocator *allocator; + IFilterGraph2 *graph; + IDirectDraw7 *ddraw; + IMemInputPin *input; + IBaseFilter *filter; + unsigned int i; + HWND window; + HRESULT hr; + ULONG ref; + IPin *pin; + + static const struct + { + const GUID *subtype; + WORD depth; + DWORD compression; + } + tests[] = + { + {&MEDIASUBTYPE_RGB32, 32, BI_RGB}, + {&MEDIASUBTYPE_NV12, 12, mmioFOURCC('N','V','1','2')}, + {&MEDIASUBTYPE_YV12, 12, mmioFOURCC('Y','V','1','2')}, + {&MEDIASUBTYPE_UYVY, 16, mmioFOURCC('U','Y','V','Y')}, + {&MEDIASUBTYPE_YUY2, 16, mmioFOURCC('Y','U','Y','2')}, + }; + + 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 (!(ddraw = create_ddraw(window))) + { + DestroyWindow(window); + return; + } + + filter = create_vmr7(VMRMode_Renderless); + IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify, (void **)¬ify); + + ref = get_refcount(ddraw); + ok(ref == 1, "Got unexpected refcount %ld.\n", ref); + + hr = IVMRSurfaceAllocatorNotify_SetDDrawDevice(notify, ddraw, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + presenter.ddraw = ddraw; + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ref = get_refcount(ddraw); + todo_wine ok(ref == 2, "Got unexpected refcount %ld.\n", ref); + + hr = IVMRSurfaceAllocatorNotify_AdviseSurfaceAllocator(notify, 0xabacab, + &presenter.IVMRSurfaceAllocator_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + presenter.notify = notify; + + testfilter_init(&source); + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, filter, NULL); + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Compression %#lx, depth %u", tests[i].compression, tests[i].depth); + + req_mt.subtype = *tests[i].subtype; + vih.bmiHeader.biBitCount = tests[i].depth; + vih.bmiHeader.biCompression = tests[i].compression; + + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + /* Connection never fails on native, but Wine currently creates + * surfaces during IPin::ReceiveConnection() instead of + * IMemAllocator::SetProperties(), so let that fail here for now. */ + if (hr != S_OK) + { + skip("Format is not supported, hr %#lx.\n", hr); + winetest_pop_context(); + continue; + } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemInputPin_GetAllocator(input, &allocator); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr != S_OK) + { + test_allocator(input); + hr = IMemInputPin_GetAllocator(input, &allocator); + } + + req_props.cbBuffer = vih.bmiHeader.biWidth * vih.bmiHeader.biHeight * vih.bmiHeader.biBitCount / 8; + hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props); + if (hr != S_OK) + { + skip("Format is not supported, hr %#lx.\n", hr); + IMemAllocator_Release(allocator); + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + winetest_pop_context(); + continue; + } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n"); + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IVMRSurfaceAllocatorNotify_AdviseSurfaceAllocator(notify, 0xabacab, + &presenter2.IVMRSurfaceAllocator_iface); + ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr); + + ok(!memcmp(&presenter.format, &vih.bmiHeader, sizeof(BITMAPINFOHEADER)), + "Bitmap header didn't match.\n"); + + test_renderless_present(&presenter, graph, input); + + hr = IMemAllocator_Decommit(allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IMemAllocator_Release(allocator); + + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + winetest_pop_context(); + } + + hr = IVMRSurfaceAllocatorNotify_AdviseSurfaceAllocator(notify, 0xabacab, + &presenter2.IVMRSurfaceAllocator_iface); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + IMemInputPin_Release(input); + IPin_Release(pin); + + IVMRSurfaceAllocatorNotify_Release(notify); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ok(presenter.refcount == 1, "Got outstanding refcount %ld.\n", presenter.refcount); + ok(presenter2.refcount == 1, "Got outstanding refcount %ld.\n", presenter2.refcount); + ref = IDirectDraw7_Release(ddraw); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + DestroyWindow(window); +} + static void test_default_presenter_allocate(void) { IDirectDrawSurface7 *frontbuffer, *backbuffer, *backbuffer2, *backbuffer3; @@ -3346,6 +3812,7 @@ START_TEST(vmr7) test_windowless_size(); test_unconnected_eos(); test_default_presenter_allocate(); + test_renderless_formats();
CoUninitialize(); }
v2: Fix a couple of issues I noticed immediately after submitting.
This should be ready for merging now that code freeze is over, unless of course there are problems with it.