1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-08 20:06:18 +00:00
wine/dlls/quartz/vmr7_presenter.c

464 lines
16 KiB
C

/*
* Default allocator-presenter for the VMR7
*
* Copyright 2023 Zebediah Figura for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "quartz_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
struct vmr7_presenter
{
IVMRImagePresenter IVMRImagePresenter_iface;
IVMRSurfaceAllocator IVMRSurfaceAllocator_iface;
IVMRWindowlessControl IVMRWindowlessControl_iface;
LONG refcount;
IDirectDraw7 *ddraw;
IDirectDrawSurface7 *frontbuffer;
IDirectDrawSurface7 *primary;
HWND window;
};
static struct vmr7_presenter *impl_from_IVMRImagePresenter(IVMRImagePresenter *iface)
{
return CONTAINING_RECORD(iface, struct vmr7_presenter, IVMRImagePresenter_iface);
}
static HRESULT WINAPI image_presenter_QueryInterface(IVMRImagePresenter *iface, REFIID iid, void **out)
{
struct vmr7_presenter *presenter = impl_from_IVMRImagePresenter(iface);
TRACE("presenter %p, iid %s, out %p.\n", presenter, debugstr_guid(iid), out);
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IVMRImagePresenter))
*out = iface;
else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocator))
*out = &presenter->IVMRSurfaceAllocator_iface;
else if (IsEqualGUID(iid, &IID_IVMRWindowlessControl))
*out = &presenter->IVMRWindowlessControl_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 image_presenter_AddRef(IVMRImagePresenter *iface)
{
struct vmr7_presenter *presenter = impl_from_IVMRImagePresenter(iface);
ULONG refcount = InterlockedIncrement(&presenter->refcount);
TRACE("%p increasing refcount to %lu.\n", presenter, refcount);
return refcount;
}
static ULONG WINAPI image_presenter_Release(IVMRImagePresenter *iface)
{
struct vmr7_presenter *presenter = impl_from_IVMRImagePresenter(iface);
ULONG refcount = InterlockedDecrement(&presenter->refcount);
TRACE("%p decreasing refcount to %lu.\n", presenter, refcount);
if (!refcount)
{
if (presenter->frontbuffer)
IDirectDrawSurface7_Release(presenter->frontbuffer);
IDirectDrawSurface7_Release(presenter->primary);
IDirectDraw7_Release(presenter->ddraw);
free(presenter);
}
return refcount;
}
static HRESULT WINAPI image_presenter_StartPresenting(IVMRImagePresenter *iface, DWORD_PTR cookie)
{
FIXME("iface %p, cookie %#Ix, stub!\n", iface, cookie);
return E_NOTIMPL;
}
static HRESULT WINAPI image_presenter_StopPresenting(IVMRImagePresenter *iface, DWORD_PTR cookie)
{
FIXME("iface %p, cookie %#Ix, stub!\n", iface, cookie);
return E_NOTIMPL;
}
static HRESULT WINAPI image_presenter_PresentImage(IVMRImagePresenter *iface,
DWORD_PTR cookie, VMRPRESENTATIONINFO *info)
{
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 =
{
image_presenter_QueryInterface,
image_presenter_AddRef,
image_presenter_Release,
image_presenter_StartPresenting,
image_presenter_StopPresenting,
image_presenter_PresentImage,
};
static struct vmr7_presenter *impl_from_IVMRSurfaceAllocator(IVMRSurfaceAllocator *iface)
{
return CONTAINING_RECORD(iface, struct vmr7_presenter, IVMRSurfaceAllocator_iface);
}
static HRESULT WINAPI surface_allocator_QueryInterface(IVMRSurfaceAllocator *iface, REFIID iid, void **out)
{
struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface);
return IVMRImagePresenter_QueryInterface(&presenter->IVMRImagePresenter_iface, iid, out);
}
static ULONG WINAPI surface_allocator_AddRef(IVMRSurfaceAllocator *iface)
{
struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface);
return IVMRImagePresenter_AddRef(&presenter->IVMRImagePresenter_iface);
}
static ULONG WINAPI surface_allocator_Release(IVMRSurfaceAllocator *iface)
{
struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface);
return IVMRImagePresenter_Release(&presenter->IVMRImagePresenter_iface);
}
static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *iface,
DWORD_PTR id, VMRALLOCATIONINFO *info, DWORD *count, IDirectDrawSurface7 **surface)
{
struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface);
DDSURFACEDESC2 surface_desc = {.dwSize = sizeof(surface_desc)};
HRESULT hr;
TRACE("presenter %p, id %#Ix, info %p, count %p, surface %p.\n", presenter, id, info, count, surface);
surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
surface_desc.dwWidth = info->lpHdr->biWidth;
surface_desc.dwHeight = info->lpHdr->biHeight;
surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
surface_desc.ddsCaps.dwCaps = DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_OFFSCREENPLAIN;
surface_desc.dwBackBufferCount = *count;
if (info->lpHdr->biCompression == BI_RGB)
{
if (info->lpHdr->biBitCount != 32)
{
FIXME("Unhandled bit depth %u.\n", info->lpHdr->biBitCount);
return E_NOTIMPL;
}
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 = info->lpHdr->biCompression;
}
if (FAILED(hr = IDirectDraw7_CreateSurface(presenter->ddraw,
&surface_desc, &presenter->frontbuffer, NULL)))
{
WARN("Failed to create surface, hr %#lx.\n", hr);
return hr;
}
*surface = presenter->frontbuffer;
++*count;
return S_OK;
}
static HRESULT WINAPI surface_allocator_FreeSurface(IVMRSurfaceAllocator *iface, DWORD_PTR id)
{
struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface);
DDSURFACEDESC2 surface_desc = {.dwSize = sizeof(surface_desc)};
TRACE("presenter %p, id %#Ix.\n", presenter, id);
if (presenter->frontbuffer)
{
IDirectDrawSurface7_Release(presenter->frontbuffer);
presenter->frontbuffer = NULL;
}
return S_OK;
}
static HRESULT WINAPI surface_allocator_PrepareSurface(IVMRSurfaceAllocator *iface,
DWORD_PTR id, IDirectDrawSurface7 *surface, DWORD flags)
{
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,
IVMRSurfaceAllocatorNotify *notify)
{
FIXME("iface %p, notify %p, stub!\n", iface, notify);
return S_OK;
}
static const IVMRSurfaceAllocatorVtbl surface_allocator_vtbl =
{
surface_allocator_QueryInterface,
surface_allocator_AddRef,
surface_allocator_Release,
surface_allocator_AllocateSurface,
surface_allocator_FreeSurface,
surface_allocator_PrepareSurface,
surface_allocator_AdviseNotify,
};
static struct vmr7_presenter *impl_from_IVMRWindowlessControl(IVMRWindowlessControl *iface)
{
return CONTAINING_RECORD(iface, struct vmr7_presenter, IVMRWindowlessControl_iface);
}
static HRESULT WINAPI windowless_control_QueryInterface(IVMRWindowlessControl *iface, REFIID iid, void **out)
{
struct vmr7_presenter *presenter = impl_from_IVMRWindowlessControl(iface);
return IVMRImagePresenter_QueryInterface(&presenter->IVMRImagePresenter_iface, iid, out);
}
static ULONG WINAPI windowless_control_AddRef(IVMRWindowlessControl *iface)
{
struct vmr7_presenter *presenter = impl_from_IVMRWindowlessControl(iface);
return IVMRImagePresenter_AddRef(&presenter->IVMRImagePresenter_iface);
}
static ULONG WINAPI windowless_control_Release(IVMRWindowlessControl *iface)
{
struct vmr7_presenter *presenter = impl_from_IVMRWindowlessControl(iface);
return IVMRImagePresenter_Release(&presenter->IVMRImagePresenter_iface);
}
static HRESULT WINAPI windowless_control_GetNativeVideoSize(IVMRWindowlessControl *iface,
LONG *width, LONG *height, LONG *aspect_width, LONG *aspect_height)
{
FIXME("iface %p, width %p, height %p, aspect_width %p, aspect_height %p.\n",
iface, width, height, aspect_width, aspect_height);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetMinIdealVideoSize(
IVMRWindowlessControl *iface, LONG *width, LONG *height)
{
FIXME("iface %p, width %p, height %p, stub!\n", iface, width, height);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetMaxIdealVideoSize(
IVMRWindowlessControl *iface, LONG *width, LONG *height)
{
FIXME("iface %p, width %p, height %p, stub!\n", iface, width, height);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_SetVideoPosition(
IVMRWindowlessControl *iface, const RECT *source, const RECT *dest)
{
FIXME("iface %p, source %s, dest %s, stub!.\n", iface, wine_dbgstr_rect(source), wine_dbgstr_rect(dest));
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetVideoPosition(
IVMRWindowlessControl *iface, RECT *source, RECT *dest)
{
FIXME("iface %p, source %p, dest %p.\n", iface, source, dest);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetAspectRatioMode(
IVMRWindowlessControl *iface, DWORD *mode)
{
FIXME("iface %p, mode %p, stub!\n", iface, mode);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_SetAspectRatioMode(
IVMRWindowlessControl *iface, DWORD mode)
{
FIXME("iface %p, mode %#lx, stub!\n", iface, mode);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_SetVideoClippingWindow(
IVMRWindowlessControl *iface, HWND window)
{
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(
IVMRWindowlessControl *iface, HWND window, HDC dc)
{
FIXME("iface %p, window %p, dc %p, stub!\n", iface, window, dc);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_DisplayModeChanged(IVMRWindowlessControl *iface)
{
FIXME("iface %p, stub!\n", iface);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetCurrentImage(IVMRWindowlessControl *iface, BYTE **image)
{
FIXME("iface %p, image %p, stub!\n", iface, image);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_SetBorderColor(IVMRWindowlessControl *iface, COLORREF color)
{
FIXME("iface %p, color %#08lx, stub!\n", iface, color);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetBorderColor(IVMRWindowlessControl *iface, COLORREF *color)
{
FIXME("iface %p, color %p, stub!\n", iface, color);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_SetColorKey(IVMRWindowlessControl *iface, COLORREF color)
{
FIXME("iface %p, color %#08lx, stub!\n", iface, color);
return E_NOTIMPL;
}
static HRESULT WINAPI windowless_control_GetColorKey(IVMRWindowlessControl *iface, COLORREF *color)
{
FIXME("iface %p, color %p, stub!\n", iface, color);
return E_NOTIMPL;
}
static const IVMRWindowlessControlVtbl windowless_control_vtbl =
{
windowless_control_QueryInterface,
windowless_control_AddRef,
windowless_control_Release,
windowless_control_GetNativeVideoSize,
windowless_control_GetMinIdealVideoSize,
windowless_control_GetMaxIdealVideoSize,
windowless_control_SetVideoPosition,
windowless_control_GetVideoPosition,
windowless_control_GetAspectRatioMode,
windowless_control_SetAspectRatioMode,
windowless_control_SetVideoClippingWindow,
windowless_control_RepaintVideo,
windowless_control_DisplayModeChanged,
windowless_control_GetCurrentImage,
windowless_control_SetBorderColor,
windowless_control_GetBorderColor,
windowless_control_SetColorKey,
windowless_control_GetColorKey,
};
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)
FIXME("Ignoring outer %p.\n", outer);
if (!(object = calloc(1, sizeof(*object))))
return E_OUTOFMEMORY;
object->IVMRImagePresenter_iface.lpVtbl = &image_presenter_vtbl;
object->IVMRSurfaceAllocator_iface.lpVtbl = &surface_allocator_vtbl;
object->IVMRWindowlessControl_iface.lpVtbl = &windowless_control_vtbl;
object->refcount = 1;
if (FAILED(hr = DirectDrawCreateEx(NULL, (void **)&object->ddraw, &IID_IDirectDraw7, NULL)))
{
ERR("Failed to create ddraw object, hr %#lx.\n", hr);
free(object);
return hr;
}
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;
}