mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-08 00:16:48 +00:00
1544 lines
48 KiB
C
1544 lines
48 KiB
C
/*
|
|
* Video Mixing Renderer for DirectDraw 7
|
|
*
|
|
* Copyright 2004 Christian Costa
|
|
* Copyright 2008 Maarten Lankhorst
|
|
* Copyright 2012 Aric Stewart
|
|
*
|
|
* 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 "uuids.h"
|
|
#include "vfwmsgs.h"
|
|
#include "amvideo.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "dshow.h"
|
|
#include "evcode.h"
|
|
#include "strmif.h"
|
|
#include "ddraw.h"
|
|
#include "dvdmedia.h"
|
|
#include "d3d9.h"
|
|
#include "videoacc.h"
|
|
#include "vmr9.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
|
|
|
|
static const BITMAPINFOHEADER *get_bitmap_header(const AM_MEDIA_TYPE *mt)
|
|
{
|
|
if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
|
|
return &((VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader;
|
|
else
|
|
return &((VIDEOINFOHEADER2 *)mt->pbFormat)->bmiHeader;
|
|
}
|
|
|
|
struct vmr7
|
|
{
|
|
struct strmbase_renderer renderer;
|
|
struct video_window window;
|
|
|
|
IAMCertifiedOutputProtection IAMCertifiedOutputProtection_iface;
|
|
IAMFilterMiscFlags IAMFilterMiscFlags_iface;
|
|
IVMRFilterConfig IVMRFilterConfig_iface;
|
|
IVMRMonitorConfig IVMRMonitorConfig_iface;
|
|
IVMRSurfaceAllocatorNotify IVMRSurfaceAllocatorNotify_iface;
|
|
IVMRWindowlessControl IVMRWindowlessControl_iface;
|
|
|
|
IAMVideoAccelerator IAMVideoAccelerator_iface;
|
|
IOverlay IOverlay_iface;
|
|
|
|
DWORD stream_count;
|
|
DWORD mixing_prefs;
|
|
|
|
VMRMode mode;
|
|
|
|
IVMRSurfaceAllocator *allocator;
|
|
IVMRImagePresenter *presenter;
|
|
IDirectDrawSurface7 **surfaces;
|
|
DWORD surface_count;
|
|
DWORD surface_index;
|
|
DWORD_PTR cookie;
|
|
|
|
HWND clipping_window;
|
|
|
|
VMR9AspectRatioMode aspect_mode;
|
|
};
|
|
|
|
static const BITMAPINFOHEADER *get_filter_bitmap_header(const struct vmr7 *filter)
|
|
{
|
|
return get_bitmap_header(&filter->renderer.sink.pin.mt);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_video_window(struct video_window *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, window);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IAMCertifiedOutputProtection(IAMCertifiedOutputProtection *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IAMCertifiedOutputProtection_iface);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IAMFilterMiscFlags_iface);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IVMRFilterConfig(IVMRFilterConfig *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IVMRFilterConfig_iface);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IVMRMonitorConfig(IVMRMonitorConfig *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IVMRMonitorConfig_iface);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IVMRSurfaceAllocatorNotify(IVMRSurfaceAllocatorNotify *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IVMRSurfaceAllocatorNotify_iface);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IVMRWindowlessControl(IVMRWindowlessControl *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IVMRWindowlessControl_iface);
|
|
}
|
|
|
|
static struct vmr7 *impl_from_IBaseFilter(IBaseFilter *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, renderer.filter.IBaseFilter_iface);
|
|
}
|
|
|
|
static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
unsigned int data_size, width, depth, src_pitch;
|
|
const BITMAPINFOHEADER *bitmap_header;
|
|
REFERENCE_TIME start_time, end_time;
|
|
VMRPRESENTATIONINFO info = {0};
|
|
DDSURFACEDESC2 surface_desc;
|
|
BYTE *data = NULL;
|
|
HRESULT hr;
|
|
int height;
|
|
|
|
TRACE("filter %p, sample %p.\n", filter, sample);
|
|
|
|
if (!filter->allocator || !filter->presenter)
|
|
{
|
|
ERR("No presenter.\n");
|
|
return S_FALSE;
|
|
}
|
|
|
|
info.dwFlags = VMR9Sample_SrcDstRectsValid;
|
|
|
|
if (SUCCEEDED(hr = IMediaSample_GetTime(sample, &start_time, &end_time)))
|
|
info.dwFlags |= VMR9Sample_TimeValid;
|
|
|
|
if (IMediaSample_IsDiscontinuity(sample) == S_OK)
|
|
info.dwFlags |= VMR9Sample_Discontinuity;
|
|
|
|
if (IMediaSample_IsPreroll(sample) == S_OK)
|
|
info.dwFlags |= VMR9Sample_Preroll;
|
|
|
|
if (IMediaSample_IsSyncPoint(sample) == S_OK)
|
|
info.dwFlags |= VMR9Sample_SyncPoint;
|
|
|
|
if (FAILED(hr = IMediaSample_GetPointer(sample, &data)))
|
|
{
|
|
ERR("Failed to get pointer to sample data, hr %#lx.\n", hr);
|
|
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;
|
|
height = bitmap_header->biHeight;
|
|
depth = bitmap_header->biBitCount;
|
|
if (bitmap_header->biCompression == mmioFOURCC('N','V','1','2')
|
|
|| bitmap_header->biCompression == mmioFOURCC('Y','V','1','2'))
|
|
src_pitch = width;
|
|
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];
|
|
|
|
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;
|
|
}
|
|
|
|
if (height > 0 && bitmap_header->biCompression == BI_RGB)
|
|
{
|
|
BYTE *dst = (BYTE *)surface_desc.lpSurface + (height * surface_desc.lPitch);
|
|
const BYTE *src = data;
|
|
|
|
TRACE("Inverting image.\n");
|
|
|
|
while (height--)
|
|
{
|
|
dst -= surface_desc.lPitch;
|
|
memcpy(dst, src, width * depth / 8);
|
|
src += src_pitch;
|
|
}
|
|
}
|
|
else if (surface_desc.lPitch != src_pitch)
|
|
{
|
|
BYTE *dst = surface_desc.lpSurface;
|
|
const BYTE *src = data;
|
|
|
|
height = abs(height);
|
|
|
|
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 += surface_desc.lPitch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy(surface_desc.lpSurface, data, data_size);
|
|
}
|
|
|
|
IDirectDrawSurface7_Unlock(info.lpSurf, NULL);
|
|
|
|
return IVMRImagePresenter_PresentImage(filter->presenter, filter->cookie, &info);
|
|
}
|
|
|
|
static HRESULT vmr_query_accept(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt)
|
|
{
|
|
if (!IsEqualIID(&mt->majortype, &MEDIATYPE_Video) || !mt->pbFormat)
|
|
return S_FALSE;
|
|
|
|
if (!IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)
|
|
&& !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo2))
|
|
return S_FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT initialize_device(struct vmr7 *filter, VMRALLOCATIONINFO *info, DWORD count)
|
|
{
|
|
IDirectDrawSurface7 *frontbuffer, *prev;
|
|
IVMRWindowlessControl *control;
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = IVMRSurfaceAllocator_AllocateSurface(filter->allocator,
|
|
filter->cookie, info, &count, &frontbuffer)))
|
|
{
|
|
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)
|
|
{
|
|
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--)
|
|
IDirectDrawSurface7_Release(filter->surfaces[i]);
|
|
IVMRSurfaceAllocator_FreeSurface(filter->allocator, filter->cookie);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT allocate_surfaces(struct vmr7 *filter, const AM_MEDIA_TYPE *mt)
|
|
{
|
|
BITMAPINFOHEADER bitmap_header = *get_bitmap_header(mt);
|
|
VMRALLOCATIONINFO info = {0};
|
|
HRESULT hr = E_FAIL;
|
|
DWORD count = 1;
|
|
|
|
TRACE("Initializing in mode %u, our window %p, clipping window %p.\n",
|
|
filter->mode, filter->window.hwnd, filter->clipping_window);
|
|
|
|
if (filter->mode == VMRMode_Windowless && !filter->clipping_window)
|
|
return S_OK;
|
|
|
|
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 (FAILED(hr = initialize_device(filter, &info, count)))
|
|
free(filter->surfaces);
|
|
return hr;
|
|
}
|
|
|
|
static void vmr_init_stream(struct strmbase_renderer *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
|
|
if (filter->window.hwnd && filter->window.AutoShow)
|
|
ShowWindow(filter->window.hwnd, SW_SHOW);
|
|
}
|
|
|
|
static void vmr_start_stream(struct strmbase_renderer *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
|
|
IVMRImagePresenter_StartPresenting(filter->presenter, filter->cookie);
|
|
}
|
|
|
|
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)
|
|
IVMRImagePresenter_StopPresenting(filter->presenter, filter->cookie);
|
|
}
|
|
|
|
static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(mt);
|
|
HWND window = filter->window.hwnd;
|
|
HRESULT hr;
|
|
RECT rect;
|
|
|
|
SetRect(&rect, 0, 0, bitmap_header->biWidth, bitmap_header->biHeight);
|
|
filter->window.src = rect;
|
|
|
|
AdjustWindowRectEx(&rect, GetWindowLongW(window, GWL_STYLE), FALSE,
|
|
GetWindowLongW(window, GWL_EXSTYLE));
|
|
SetWindowPos(window, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
GetClientRect(window, &filter->window.dst);
|
|
|
|
if (filter->mode
|
|
|| SUCCEEDED(hr = IVMRFilterConfig_SetRenderingMode(&filter->IVMRFilterConfig_iface, VMRMode_Windowed)))
|
|
hr = allocate_surfaces(filter, mt);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void deallocate_surfaces(struct vmr7 *filter)
|
|
{
|
|
if (filter->mode && filter->allocator && filter->presenter)
|
|
{
|
|
for (DWORD i = 0; i < filter->surface_count; ++i)
|
|
IDirectDrawSurface7_Release(filter->surfaces[i]);
|
|
free(filter->surfaces);
|
|
|
|
IVMRSurfaceAllocator_FreeSurface(filter->allocator, filter->cookie);
|
|
filter->surface_count = 0;
|
|
}
|
|
}
|
|
|
|
static void vmr_disconnect(struct strmbase_renderer *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
|
|
deallocate_surfaces(filter);
|
|
}
|
|
|
|
static void vmr_destroy(struct strmbase_renderer *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
|
|
video_window_cleanup(&filter->window);
|
|
|
|
if (filter->allocator)
|
|
{
|
|
if (filter->surface_count)
|
|
IVMRSurfaceAllocator_FreeSurface(filter->allocator, filter->cookie);
|
|
IVMRSurfaceAllocator_Release(filter->allocator);
|
|
}
|
|
if (filter->presenter)
|
|
IVMRImagePresenter_Release(filter->presenter);
|
|
|
|
filter->surface_count = 0;
|
|
|
|
strmbase_renderer_cleanup(&filter->renderer);
|
|
free(filter);
|
|
}
|
|
|
|
static HRESULT vmr_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
|
|
if (IsEqualGUID(iid, &IID_IVideoWindow))
|
|
*out = &filter->window.IVideoWindow_iface;
|
|
else if (IsEqualGUID(iid, &IID_IBasicVideo))
|
|
*out = &filter->window.IBasicVideo_iface;
|
|
else if (IsEqualGUID(iid, &IID_IAMCertifiedOutputProtection))
|
|
*out = &filter->IAMCertifiedOutputProtection_iface;
|
|
else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
|
|
*out = &filter->IAMFilterMiscFlags_iface;
|
|
else if (IsEqualGUID(iid, &IID_IVMRFilterConfig))
|
|
*out = &filter->IVMRFilterConfig_iface;
|
|
else if (IsEqualGUID(iid, &IID_IVMRMonitorConfig))
|
|
*out = &filter->IVMRMonitorConfig_iface;
|
|
else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorNotify) && filter->mode == VMRMode_Renderless)
|
|
*out = &filter->IVMRSurfaceAllocatorNotify_iface;
|
|
else if (IsEqualGUID(iid, &IID_IVMRWindowlessControl) && filter->mode == VMRMode_Windowless)
|
|
*out = &filter->IVMRWindowlessControl_iface;
|
|
else
|
|
return E_NOINTERFACE;
|
|
|
|
IUnknown_AddRef((IUnknown *)*out);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT vmr_pin_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
|
|
|
|
if (IsEqualGUID(iid, &IID_IAMVideoAccelerator))
|
|
*out = &filter->IAMVideoAccelerator_iface;
|
|
else if (IsEqualGUID(iid, &IID_IOverlay))
|
|
*out = &filter->IOverlay_iface;
|
|
else
|
|
return E_NOINTERFACE;
|
|
|
|
IUnknown_AddRef((IUnknown *)*out);
|
|
return S_OK;
|
|
}
|
|
|
|
static const struct strmbase_renderer_ops renderer_ops =
|
|
{
|
|
.renderer_query_accept = vmr_query_accept,
|
|
.renderer_render = vmr_render,
|
|
.renderer_init_stream = vmr_init_stream,
|
|
.renderer_start_stream = vmr_start_stream,
|
|
.renderer_stop_stream = vmr_stop_stream,
|
|
.renderer_connect = vmr_connect,
|
|
.renderer_disconnect = vmr_disconnect,
|
|
.renderer_destroy = vmr_destroy,
|
|
.renderer_query_interface = vmr_query_interface,
|
|
.renderer_pin_query_interface = vmr_pin_query_interface,
|
|
};
|
|
|
|
static void vmr_get_default_rect(struct video_window *iface, RECT *rect)
|
|
{
|
|
struct vmr7 *filter = impl_from_video_window(iface);
|
|
const BITMAPINFOHEADER *bitmap_header = get_filter_bitmap_header(filter);
|
|
|
|
SetRect(rect, 0, 0, bitmap_header->biWidth, bitmap_header->biHeight);
|
|
}
|
|
|
|
static HRESULT vmr_get_current_image(struct video_window *iface, LONG *size, LONG *image)
|
|
{
|
|
FIXME("stub!\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const struct video_window_ops window_ops =
|
|
{
|
|
.get_default_rect = vmr_get_default_rect,
|
|
.get_current_image = vmr_get_current_image,
|
|
};
|
|
|
|
static const IVideoWindowVtbl IVideoWindow_VTable =
|
|
{
|
|
BaseControlWindowImpl_QueryInterface,
|
|
BaseControlWindowImpl_AddRef,
|
|
BaseControlWindowImpl_Release,
|
|
BaseControlWindowImpl_GetTypeInfoCount,
|
|
BaseControlWindowImpl_GetTypeInfo,
|
|
BaseControlWindowImpl_GetIDsOfNames,
|
|
BaseControlWindowImpl_Invoke,
|
|
BaseControlWindowImpl_put_Caption,
|
|
BaseControlWindowImpl_get_Caption,
|
|
BaseControlWindowImpl_put_WindowStyle,
|
|
BaseControlWindowImpl_get_WindowStyle,
|
|
BaseControlWindowImpl_put_WindowStyleEx,
|
|
BaseControlWindowImpl_get_WindowStyleEx,
|
|
BaseControlWindowImpl_put_AutoShow,
|
|
BaseControlWindowImpl_get_AutoShow,
|
|
BaseControlWindowImpl_put_WindowState,
|
|
BaseControlWindowImpl_get_WindowState,
|
|
BaseControlWindowImpl_put_BackgroundPalette,
|
|
BaseControlWindowImpl_get_BackgroundPalette,
|
|
BaseControlWindowImpl_put_Visible,
|
|
BaseControlWindowImpl_get_Visible,
|
|
BaseControlWindowImpl_put_Left,
|
|
BaseControlWindowImpl_get_Left,
|
|
BaseControlWindowImpl_put_Width,
|
|
BaseControlWindowImpl_get_Width,
|
|
BaseControlWindowImpl_put_Top,
|
|
BaseControlWindowImpl_get_Top,
|
|
BaseControlWindowImpl_put_Height,
|
|
BaseControlWindowImpl_get_Height,
|
|
BaseControlWindowImpl_put_Owner,
|
|
BaseControlWindowImpl_get_Owner,
|
|
BaseControlWindowImpl_put_MessageDrain,
|
|
BaseControlWindowImpl_get_MessageDrain,
|
|
BaseControlWindowImpl_get_BorderColor,
|
|
BaseControlWindowImpl_put_BorderColor,
|
|
BaseControlWindowImpl_get_FullScreenMode,
|
|
BaseControlWindowImpl_put_FullScreenMode,
|
|
BaseControlWindowImpl_SetWindowForeground,
|
|
BaseControlWindowImpl_NotifyOwnerMessage,
|
|
BaseControlWindowImpl_SetWindowPosition,
|
|
BaseControlWindowImpl_GetWindowPosition,
|
|
BaseControlWindowImpl_GetMinIdealImageSize,
|
|
BaseControlWindowImpl_GetMaxIdealImageSize,
|
|
BaseControlWindowImpl_GetRestorePosition,
|
|
BaseControlWindowImpl_HideCursor,
|
|
BaseControlWindowImpl_IsCursorHidden,
|
|
};
|
|
|
|
static HRESULT WINAPI certified_output_protection_QueryInterface(
|
|
IAMCertifiedOutputProtection *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMCertifiedOutputProtection(iface);
|
|
|
|
return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI certified_output_protection_AddRef(IAMCertifiedOutputProtection *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMCertifiedOutputProtection(iface);
|
|
|
|
return IUnknown_AddRef(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI certified_output_protection_Release(IAMCertifiedOutputProtection *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMCertifiedOutputProtection(iface);
|
|
|
|
return IUnknown_Release(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static HRESULT WINAPI certified_output_protection_KeyExchange(
|
|
IAMCertifiedOutputProtection *iface, GUID *random, BYTE **certificate, DWORD *size)
|
|
{
|
|
FIXME("iface %p, random %p, certificate %p, size %p, stub!\n", iface, random, certificate, size);
|
|
return VFW_E_NO_COPP_HW;
|
|
}
|
|
|
|
static HRESULT WINAPI certified_output_protection_SessionSequenceStart(
|
|
IAMCertifiedOutputProtection *iface, AMCOPPSignature *signature)
|
|
{
|
|
FIXME("iface %p, signature %p, stub!\n", iface, signature);
|
|
return VFW_E_NO_COPP_HW;
|
|
}
|
|
|
|
static HRESULT WINAPI certified_output_protection_ProtectionCommand(
|
|
IAMCertifiedOutputProtection *iface, const AMCOPPCommand *cmd)
|
|
{
|
|
FIXME("iface %p, cmd %p, stub!\n", iface, cmd);
|
|
return VFW_E_NO_COPP_HW;
|
|
}
|
|
|
|
static HRESULT WINAPI certified_output_protection_ProtectionStatus(
|
|
IAMCertifiedOutputProtection *iface, const AMCOPPStatusInput *input, AMCOPPStatusOutput *output)
|
|
{
|
|
FIXME("iface %p, input %p, output %p, stub!\n", iface, input, output);
|
|
return VFW_E_NO_COPP_HW;
|
|
}
|
|
|
|
static const IAMCertifiedOutputProtectionVtbl certified_output_protection_vtbl =
|
|
{
|
|
certified_output_protection_QueryInterface,
|
|
certified_output_protection_AddRef,
|
|
certified_output_protection_Release,
|
|
certified_output_protection_KeyExchange,
|
|
certified_output_protection_SessionSequenceStart,
|
|
certified_output_protection_ProtectionCommand,
|
|
certified_output_protection_ProtectionStatus,
|
|
};
|
|
|
|
static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMFilterMiscFlags(iface);
|
|
|
|
return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMFilterMiscFlags(iface);
|
|
|
|
return IUnknown_AddRef(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMFilterMiscFlags(iface);
|
|
|
|
return IUnknown_Release(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
|
|
{
|
|
return AM_FILTER_MISC_FLAGS_IS_RENDERER;
|
|
}
|
|
|
|
static const IAMFilterMiscFlagsVtbl misc_flags_vtbl =
|
|
{
|
|
misc_flags_QueryInterface,
|
|
misc_flags_AddRef,
|
|
misc_flags_Release,
|
|
misc_flags_GetMiscFlags,
|
|
};
|
|
|
|
static HRESULT WINAPI filter_config_QueryInterface(IVMRFilterConfig *iface, REFIID iid, void** out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRFilterConfig(iface);
|
|
|
|
return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI filter_config_AddRef(IVMRFilterConfig *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRFilterConfig(iface);
|
|
|
|
return IUnknown_AddRef(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI filter_config_Release(IVMRFilterConfig *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRFilterConfig(iface);
|
|
|
|
return IUnknown_Release(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_SetImageCompositor(
|
|
IVMRFilterConfig *iface, IVMRImageCompositor *compositor)
|
|
{
|
|
FIXME("iface %p, compositor %p, stub!\n", iface, compositor);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_SetNumberOfStreams(IVMRFilterConfig *iface, DWORD count)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRFilterConfig(iface);
|
|
|
|
FIXME("iface %p, count %lu, stub!\n", iface, count);
|
|
|
|
if (!count)
|
|
{
|
|
WARN("Application requested zero streams; returning E_INVALIDARG.\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
EnterCriticalSection(&filter->renderer.filter.filter_cs);
|
|
|
|
if (filter->stream_count)
|
|
{
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
WARN("Stream count is already set; returning VFW_E_WRONG_STATE.\n");
|
|
return VFW_E_WRONG_STATE;
|
|
}
|
|
|
|
filter->stream_count = count;
|
|
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_GetNumberOfStreams(IVMRFilterConfig *iface, DWORD *count)
|
|
{
|
|
FIXME("iface %p, count %p, stub!\n", iface, count);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_SetRenderingPrefs(IVMRFilterConfig *iface, DWORD flags)
|
|
{
|
|
FIXME("iface %p, flags %#lx, stub!\n", iface, flags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_GetRenderingPrefs(IVMRFilterConfig *iface, DWORD *flags)
|
|
{
|
|
FIXME("iface %p, flags %p, stub!\n", iface, flags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_SetRenderingMode(IVMRFilterConfig *iface, DWORD mode)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRFilterConfig(iface);
|
|
IUnknown *default_presenter;
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("filter %p, mode %lu.\n", filter, mode);
|
|
|
|
EnterCriticalSection(&filter->renderer.filter.filter_cs);
|
|
|
|
if (filter->mode)
|
|
{
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
return VFW_E_WRONG_STATE;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case VMRMode_Windowed:
|
|
case VMRMode_Windowless:
|
|
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;
|
|
}
|
|
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:
|
|
break;
|
|
|
|
default:
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (mode != VMRMode_Windowed)
|
|
video_window_cleanup(&filter->window);
|
|
|
|
filter->mode = mode;
|
|
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI filter_config_GetRenderingMode(IVMRFilterConfig *iface, DWORD *mode)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRFilterConfig(iface);
|
|
|
|
TRACE("filter %p, mode %p.\n", filter, mode);
|
|
|
|
if (!mode)
|
|
return E_POINTER;
|
|
|
|
if (filter->mode)
|
|
*mode = filter->mode;
|
|
else
|
|
*mode = VMRMode_Windowed;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IVMRFilterConfigVtbl filter_config_vtbl =
|
|
{
|
|
filter_config_QueryInterface,
|
|
filter_config_AddRef,
|
|
filter_config_Release,
|
|
filter_config_SetImageCompositor,
|
|
filter_config_SetNumberOfStreams,
|
|
filter_config_GetNumberOfStreams,
|
|
filter_config_SetRenderingPrefs,
|
|
filter_config_GetRenderingPrefs,
|
|
filter_config_SetRenderingMode,
|
|
filter_config_GetRenderingMode,
|
|
};
|
|
|
|
struct get_available_monitors_args
|
|
{
|
|
VMRMONITORINFO *info7;
|
|
VMR9MonitorInfo *info9;
|
|
DWORD capacity;
|
|
DWORD count;
|
|
};
|
|
|
|
static BOOL CALLBACK get_available_monitors_proc(HMONITOR monitor, HDC dc, RECT *rect, LPARAM ctx)
|
|
{
|
|
struct get_available_monitors_args *args = (struct get_available_monitors_args *)ctx;
|
|
MONITORINFOEXW mi;
|
|
|
|
if (args->info7 || args->info9)
|
|
{
|
|
|
|
if (!args->capacity)
|
|
return FALSE;
|
|
|
|
mi.cbSize = sizeof(mi);
|
|
if (!GetMonitorInfoW(monitor, (MONITORINFO*)&mi))
|
|
return TRUE;
|
|
|
|
/* fill VMRMONITORINFO struct */
|
|
if (args->info7)
|
|
{
|
|
VMRMONITORINFO *info = args->info7++;
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
if (args->count > 0)
|
|
{
|
|
info->guid.pGUID = &info->guid.GUID;
|
|
info->guid.GUID.Data4[7] = args->count;
|
|
}
|
|
else
|
|
info->guid.pGUID = NULL;
|
|
|
|
info->rcMonitor = mi.rcMonitor;
|
|
info->hMon = monitor;
|
|
info->dwFlags = mi.dwFlags;
|
|
|
|
lstrcpynW(info->szDevice, mi.szDevice, ARRAY_SIZE(info->szDevice));
|
|
|
|
/* FIXME: how to get these values? */
|
|
info->szDescription[0] = 0;
|
|
}
|
|
|
|
/* fill VMR9MonitorInfo struct */
|
|
if (args->info9)
|
|
{
|
|
VMR9MonitorInfo *info = args->info9++;
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
info->uDevID = 0; /* FIXME */
|
|
info->rcMonitor = mi.rcMonitor;
|
|
info->hMon = monitor;
|
|
info->dwFlags = mi.dwFlags;
|
|
|
|
lstrcpynW(info->szDevice, mi.szDevice, ARRAY_SIZE(info->szDevice));
|
|
|
|
/* FIXME: how to get these values? */
|
|
info->szDescription[0] = 0;
|
|
info->dwVendorId = 0;
|
|
info->dwDeviceId = 0;
|
|
info->dwSubSysId = 0;
|
|
info->dwRevision = 0;
|
|
}
|
|
|
|
args->capacity--;
|
|
}
|
|
|
|
args->count++;
|
|
return TRUE;
|
|
}
|
|
|
|
static HRESULT WINAPI monitor_config_QueryInterface(IVMRMonitorConfig *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRMonitorConfig(iface);
|
|
|
|
return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI monitor_config_AddRef(IVMRMonitorConfig *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRMonitorConfig(iface);
|
|
|
|
return IUnknown_AddRef(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI monitor_config_Release(IVMRMonitorConfig *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRMonitorConfig(iface);
|
|
|
|
return IUnknown_Release(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static HRESULT WINAPI monitor_config_SetMonitor(IVMRMonitorConfig *iface, const VMRGUID *guid)
|
|
{
|
|
FIXME("iface %p, guid %p, stub!\n", iface, guid);
|
|
|
|
if (!guid)
|
|
return E_POINTER;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI monitor_config_GetMonitor(IVMRMonitorConfig *iface, VMRGUID *guid)
|
|
{
|
|
FIXME("iface %p, guid %p, stub!\n", iface, guid);
|
|
|
|
if (!guid)
|
|
return E_POINTER;
|
|
|
|
guid->pGUID = NULL; /* default DirectDraw device */
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI monitor_config_SetDefaultMonitor(IVMRMonitorConfig *iface, const VMRGUID *guid)
|
|
{
|
|
FIXME("iface %p, guid %p, stub!\n", iface, guid);
|
|
|
|
if (!guid)
|
|
return E_POINTER;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI monitor_config_GetDefaultMonitor(IVMRMonitorConfig *iface, VMRGUID *guid)
|
|
{
|
|
FIXME("iface %p, guid %p, stub!\n", iface, guid);
|
|
|
|
if (!guid)
|
|
return E_POINTER;
|
|
|
|
guid->pGUID = NULL; /* default DirectDraw device */
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI monitor_config_GetAvailableMonitors(IVMRMonitorConfig *iface,
|
|
VMRMONITORINFO *info, DWORD capacity, DWORD *count)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRMonitorConfig(iface);
|
|
struct get_available_monitors_args args;
|
|
|
|
TRACE("filter %p, info %p, capacity %lu, count %p.\n", filter, info, capacity, count);
|
|
|
|
if (!count)
|
|
return E_POINTER;
|
|
|
|
if (info && !capacity)
|
|
return E_INVALIDARG;
|
|
|
|
args.info7 = info;
|
|
args.info9 = NULL;
|
|
args.capacity = capacity;
|
|
args.count = 0;
|
|
EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args);
|
|
|
|
*count = args.count;
|
|
return S_OK;
|
|
}
|
|
|
|
static const IVMRMonitorConfigVtbl monitor_config_vtbl =
|
|
{
|
|
monitor_config_QueryInterface,
|
|
monitor_config_AddRef,
|
|
monitor_config_Release,
|
|
monitor_config_SetMonitor,
|
|
monitor_config_GetMonitor,
|
|
monitor_config_SetDefaultMonitor,
|
|
monitor_config_GetDefaultMonitor,
|
|
monitor_config_GetAvailableMonitors,
|
|
};
|
|
|
|
static HRESULT WINAPI windowless_control_QueryInterface(IVMRWindowlessControl *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
|
|
return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI windowless_control_AddRef(IVMRWindowlessControl *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
|
|
return IUnknown_AddRef(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI windowless_control_Release(IVMRWindowlessControl *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
|
|
return IUnknown_Release(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static HRESULT WINAPI windowless_control_GetNativeVideoSize(IVMRWindowlessControl *iface,
|
|
LONG *width, LONG *height, LONG *aspect_width, LONG *aspect_height)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
const BITMAPINFOHEADER *bitmap_header = 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);
|
|
|
|
if (!width || !height)
|
|
return E_POINTER;
|
|
|
|
*width = bitmap_header->biWidth;
|
|
*height = bitmap_header->biHeight;
|
|
if (aspect_width)
|
|
*aspect_width = bitmap_header->biWidth;
|
|
if (aspect_height)
|
|
*aspect_height = bitmap_header->biHeight;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
|
|
TRACE("filter %p, source %s, dest %s.\n", filter, wine_dbgstr_rect(source), wine_dbgstr_rect(dest));
|
|
|
|
EnterCriticalSection(&filter->renderer.filter.filter_cs);
|
|
|
|
if (source)
|
|
filter->window.src = *source;
|
|
if (dest)
|
|
filter->window.dst = *dest;
|
|
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI windowless_control_GetVideoPosition(
|
|
IVMRWindowlessControl *iface, RECT *source, RECT *dest)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
|
|
TRACE("filter %p, source %p, dest %p.\n", filter, source, dest);
|
|
|
|
if (source)
|
|
*source = filter->window.src;
|
|
|
|
if (dest)
|
|
*dest = filter->window.dst;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
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 *filter = impl_from_IVMRWindowlessControl(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("filter %p, window %p.\n", filter, window);
|
|
|
|
if (!IsWindow(window))
|
|
{
|
|
WARN("Invalid window %p, returning E_INVALIDARG.\n", window);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
EnterCriticalSection(&filter->renderer.filter.filter_cs);
|
|
|
|
if (filter->renderer.sink.pin.peer)
|
|
{
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
WARN("Attempt to set the clipping window while connected; returning VFW_E_WRONG_STATE.\n");
|
|
return VFW_E_WRONG_STATE;
|
|
}
|
|
|
|
filter->clipping_window = window;
|
|
|
|
hr = IVMRFilterConfig_SetNumberOfStreams(&filter->IVMRFilterConfig_iface, 4);
|
|
|
|
LeaveCriticalSection(&filter->renderer.filter.filter_cs);
|
|
return hr;
|
|
}
|
|
|
|
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,
|
|
};
|
|
|
|
static HRESULT WINAPI surface_allocator_notify_QueryInterface(
|
|
IVMRSurfaceAllocatorNotify *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRSurfaceAllocatorNotify(iface);
|
|
|
|
return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI surface_allocator_notify_AddRef(IVMRSurfaceAllocatorNotify *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRSurfaceAllocatorNotify(iface);
|
|
|
|
return IUnknown_AddRef(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static ULONG WINAPI surface_allocator_notify_Release(IVMRSurfaceAllocatorNotify *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IVMRSurfaceAllocatorNotify(iface);
|
|
|
|
return IUnknown_Release(filter->renderer.filter.outer_unk);
|
|
}
|
|
|
|
static HRESULT WINAPI surface_allocator_notify_AdviseSurfaceAllocator(
|
|
IVMRSurfaceAllocatorNotify *iface, DWORD_PTR cookie, IVMRSurfaceAllocator *allocator)
|
|
{
|
|
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(
|
|
IVMRSurfaceAllocatorNotify *iface, IDirectDraw7 *device, HMONITOR monitor)
|
|
{
|
|
FIXME("iface %p, device %p, monitor %p, stub!\n", iface, device, monitor);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI surface_allocator_notify_ChangeDDrawDevice(
|
|
IVMRSurfaceAllocatorNotify *iface, IDirectDraw7 *device, HMONITOR monitor)
|
|
{
|
|
FIXME("iface %p, device %p, monitor %p, stub!\n", iface, device, monitor);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI surface_allocator_notify_RestoreDDrawSurfaces(IVMRSurfaceAllocatorNotify *iface)
|
|
{
|
|
FIXME("iface %p, stub!\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI surface_allocator_notify_NotifyEvent(
|
|
IVMRSurfaceAllocatorNotify *iface, LONG code, LONG_PTR param1, LONG_PTR param2)
|
|
{
|
|
FIXME("iface %p, code %#lx, param1 %#Ix, param2 %#Ix, stub!\n", iface, code, param1, param2);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI surface_allocator_notify_SetBorderColor(
|
|
IVMRSurfaceAllocatorNotify *iface, COLORREF color)
|
|
{
|
|
FIXME("iface %p, color %#08lx, stub!\n", iface, color);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IVMRSurfaceAllocatorNotifyVtbl surface_allocator_notify_vtbl =
|
|
{
|
|
surface_allocator_notify_QueryInterface,
|
|
surface_allocator_notify_AddRef,
|
|
surface_allocator_notify_Release,
|
|
surface_allocator_notify_AdviseSurfaceAllocator,
|
|
surface_allocator_notify_SetDDrawDevice,
|
|
surface_allocator_notify_ChangeDDrawDevice,
|
|
surface_allocator_notify_RestoreDDrawSurfaces,
|
|
surface_allocator_notify_NotifyEvent,
|
|
surface_allocator_notify_SetBorderColor,
|
|
};
|
|
|
|
static struct vmr7 *impl_from_IAMVideoAccelerator(IAMVideoAccelerator *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IAMVideoAccelerator_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_QueryInterface(IAMVideoAccelerator *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMVideoAccelerator(iface);
|
|
|
|
return IPin_QueryInterface(&filter->renderer.sink.pin.IPin_iface, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI video_accelerator_AddRef(IAMVideoAccelerator *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMVideoAccelerator(iface);
|
|
|
|
return IPin_AddRef(&filter->renderer.sink.pin.IPin_iface);
|
|
}
|
|
|
|
static ULONG WINAPI video_accelerator_Release(IAMVideoAccelerator *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IAMVideoAccelerator(iface);
|
|
|
|
return IPin_Release(&filter->renderer.sink.pin.IPin_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_GetVideoAcceleratorGUIDs(
|
|
IAMVideoAccelerator *iface, DWORD *count, GUID *accelerators)
|
|
{
|
|
FIXME("iface %p, count %p, accelerators %p, stub!\n", iface, count, accelerators);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_GetUncompFormatsSupported(IAMVideoAccelerator *iface,
|
|
const GUID *accelerator, DWORD *count, DDPIXELFORMAT *formats)
|
|
{
|
|
FIXME("iface %p, accelerator %s, count %p, formats %p, stub!\n",
|
|
iface, debugstr_guid(accelerator), count, formats);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_GetInternalMemInfo(IAMVideoAccelerator *iface,
|
|
const GUID *accelerator, const AMVAUncompDataInfo *format_info, AMVAInternalMemInfo *mem_info)
|
|
{
|
|
FIXME("iface %p, accelerator %s, format_info %p, mem_info %p, stub!\n",
|
|
iface, debugstr_guid(accelerator), format_info, mem_info);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_GetCompBufferInfo(IAMVideoAccelerator *iface,
|
|
const GUID *accelerator, const AMVAUncompDataInfo *uncompressed_info,
|
|
DWORD *compressed_info_count, AMVACompBufferInfo *compressed_infos)
|
|
{
|
|
FIXME("iface %p, accelerator %s, uncompressed_info %p, compressed_info_count %p, compressed_infos %p, stub!\n",
|
|
iface, debugstr_guid(accelerator), uncompressed_info, compressed_info_count, compressed_infos);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_GetInternalCompBufferInfo(
|
|
IAMVideoAccelerator *iface, DWORD *count, AMVACompBufferInfo *infos)
|
|
{
|
|
FIXME("iface %p, count %p, infos %p, stub!\n", iface, count, infos);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_BeginFrame(IAMVideoAccelerator *iface, const AMVABeginFrameInfo *info)
|
|
{
|
|
FIXME("iface %p, info %p, stub!\n", iface, info);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_EndFrame(IAMVideoAccelerator *iface, const AMVAEndFrameInfo *info)
|
|
{
|
|
FIXME("iface %p, info %p, stub!\n", iface, info);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_GetBuffer(IAMVideoAccelerator *iface,
|
|
DWORD type_index, DWORD buffer_index, BOOL read_only, void **buffer, LONG *stride)
|
|
{
|
|
FIXME("iface %p, type_index %lu, buffer_index %lu, read_only %d, buffer %p, stride %p, stub!\n",
|
|
iface, type_index, buffer_index, read_only, buffer, stride);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_ReleaseBuffer(
|
|
IAMVideoAccelerator *iface, DWORD type_index, DWORD buffer_index)
|
|
{
|
|
FIXME("iface %p, type_index %lu, buffer_index %lu, stub!\n", iface, type_index, buffer_index);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_Execute(IAMVideoAccelerator *iface,
|
|
DWORD function, void *in_data, DWORD in_size, void *out_data,
|
|
DWORD out_size, DWORD buffer_count, const AMVABUFFERINFO *buffers)
|
|
{
|
|
FIXME("iface %p, function %#lx, in_data %p, in_size %lu,"
|
|
" out_data %p, out_size %lu, buffer_count %lu, buffers %p, stub!\n",
|
|
iface, function, in_data, in_size, out_data, out_size, buffer_count, buffers);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_QueryRenderStatus(IAMVideoAccelerator *iface,
|
|
DWORD type_index, DWORD buffer_index, DWORD flags)
|
|
{
|
|
FIXME("iface %p, type_index %lu, buffer_index %lu, flags %#lx, stub!\n",
|
|
iface, type_index, buffer_index, flags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI video_accelerator_DisplayFrame(
|
|
IAMVideoAccelerator *iface, DWORD index, IMediaSample *sample)
|
|
{
|
|
FIXME("iface %p, index %lu, sample %p, stub!\n", iface, index, sample);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IAMVideoAcceleratorVtbl video_accelerator_vtbl =
|
|
{
|
|
video_accelerator_QueryInterface,
|
|
video_accelerator_AddRef,
|
|
video_accelerator_Release,
|
|
video_accelerator_GetVideoAcceleratorGUIDs,
|
|
video_accelerator_GetUncompFormatsSupported,
|
|
video_accelerator_GetInternalMemInfo,
|
|
video_accelerator_GetCompBufferInfo,
|
|
video_accelerator_GetInternalCompBufferInfo,
|
|
video_accelerator_BeginFrame,
|
|
video_accelerator_EndFrame,
|
|
video_accelerator_GetBuffer,
|
|
video_accelerator_ReleaseBuffer,
|
|
video_accelerator_Execute,
|
|
video_accelerator_QueryRenderStatus,
|
|
video_accelerator_DisplayFrame,
|
|
};
|
|
|
|
static struct vmr7 *impl_from_IOverlay(IOverlay *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct vmr7, IOverlay_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_QueryInterface(IOverlay *iface, REFIID iid, void **out)
|
|
{
|
|
struct vmr7 *filter = impl_from_IOverlay(iface);
|
|
|
|
return IPin_QueryInterface(&filter->renderer.sink.pin.IPin_iface, iid, out);
|
|
}
|
|
|
|
static ULONG WINAPI overlay_AddRef(IOverlay *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IOverlay(iface);
|
|
|
|
return IPin_AddRef(&filter->renderer.sink.pin.IPin_iface);
|
|
}
|
|
|
|
static ULONG WINAPI overlay_Release(IOverlay *iface)
|
|
{
|
|
struct vmr7 *filter = impl_from_IOverlay(iface);
|
|
|
|
return IPin_Release(&filter->renderer.sink.pin.IPin_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_GetPalette(IOverlay *iface, DWORD *count, PALETTEENTRY **palette)
|
|
{
|
|
FIXME("iface %p, count %p, palette %p, stub!\n", iface, count, palette);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_SetPalette(IOverlay *iface, DWORD count, PALETTEENTRY *palette)
|
|
{
|
|
FIXME("iface %p, count %lu, palette %p, stub!\n", iface, count, palette);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_GetDefaultColorKey(IOverlay *iface, COLORKEY *key)
|
|
{
|
|
FIXME("iface %p, key %p, stub!\n", iface, key);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_GetColorKey(IOverlay *iface, COLORKEY *key)
|
|
{
|
|
FIXME("iface %p, key %p, stub!\n", iface, key);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_SetColorKey(IOverlay *iface, COLORKEY *key)
|
|
{
|
|
FIXME("iface %p, key %p, stub!\n", iface, key);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_GetWindowHandle(IOverlay *iface, HWND *window)
|
|
{
|
|
struct vmr7 *filter = impl_from_IOverlay(iface);
|
|
|
|
TRACE("filter %p, window %p.\n", filter, window);
|
|
|
|
if (!filter->window.hwnd)
|
|
return VFW_E_WRONG_STATE;
|
|
|
|
*window = filter->window.hwnd;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_GetClipList(IOverlay *iface, RECT *source, RECT *dest, RGNDATA **region)
|
|
{
|
|
FIXME("iface %p, source %p, dest %p, region %p, stub!\n", iface, source, dest, region);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_GetVideoPosition(IOverlay *iface, RECT *source, RECT *dest)
|
|
{
|
|
FIXME("iface %p, source %p, dest %p, stub!\n", iface, source, dest);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_Advise(IOverlay *iface, IOverlayNotify *sink, DWORD flags)
|
|
{
|
|
FIXME("iface %p, sink %p, flags %#lx, stub!\n", iface, sink, flags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI overlay_Unadvise(IOverlay *iface)
|
|
{
|
|
FIXME("iface %p, stub!\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IOverlayVtbl overlay_vtbl =
|
|
{
|
|
overlay_QueryInterface,
|
|
overlay_AddRef,
|
|
overlay_Release,
|
|
overlay_GetPalette,
|
|
overlay_SetPalette,
|
|
overlay_GetDefaultColorKey,
|
|
overlay_GetColorKey,
|
|
overlay_SetColorKey,
|
|
overlay_GetWindowHandle,
|
|
overlay_GetClipList,
|
|
overlay_GetVideoPosition,
|
|
overlay_Advise,
|
|
overlay_Unadvise,
|
|
};
|
|
|
|
HRESULT vmr7_create(IUnknown *outer, IUnknown **out)
|
|
{
|
|
struct vmr7 *object;
|
|
HRESULT hr;
|
|
|
|
if (!(object = calloc(1, sizeof(*object))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
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;
|
|
object->IVMRFilterConfig_iface.lpVtbl = &filter_config_vtbl;
|
|
object->IVMRMonitorConfig_iface.lpVtbl = &monitor_config_vtbl;
|
|
object->IVMRSurfaceAllocatorNotify_iface.lpVtbl = &surface_allocator_notify_vtbl;
|
|
object->IVMRWindowlessControl_iface.lpVtbl = &windowless_control_vtbl;
|
|
|
|
object->IAMVideoAccelerator_iface.lpVtbl = &video_accelerator_vtbl;
|
|
object->IOverlay_iface.lpVtbl = &overlay_vtbl;
|
|
|
|
video_window_init(&object->window, &IVideoWindow_VTable,
|
|
&object->renderer.filter, &object->renderer.sink.pin, &window_ops);
|
|
|
|
if (FAILED(hr = video_window_create_window(&object->window)))
|
|
{
|
|
video_window_cleanup(&object->window);
|
|
strmbase_renderer_cleanup(&object->renderer);
|
|
free(object);
|
|
return hr;
|
|
}
|
|
|
|
object->mixing_prefs = MixerPref9_NoDecimation | MixerPref9_ARAdjustXorY
|
|
| MixerPref9_BiLinearFiltering | MixerPref9_RenderTargetRGB;
|
|
|
|
TRACE("Created VMR %p.\n", object);
|
|
*out = &object->renderer.filter.IUnknown_inner;
|
|
return S_OK;
|
|
}
|