/* * Video Mixing Renderer for dx9 * * 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 "vmr9.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); static inline const char *debugstr_normalized_rect(const VMR9NormalizedRect *rect) { if (!rect) return "(null)"; return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)", rect->left, rect->top, rect->right, rect->bottom); } 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 quartz_vmr { struct strmbase_renderer renderer; struct video_window window; IAMCertifiedOutputProtection IAMCertifiedOutputProtection_iface; IAMFilterMiscFlags IAMFilterMiscFlags_iface; IVMRFilterConfig IVMRFilterConfig_iface; IVMRFilterConfig9 IVMRFilterConfig9_iface; IVMRMixerBitmap9 IVMRMixerBitmap9_iface; IVMRMixerControl9 IVMRMixerControl9_iface; IVMRMonitorConfig IVMRMonitorConfig_iface; IVMRMonitorConfig9 IVMRMonitorConfig9_iface; IVMRSurfaceAllocatorNotify IVMRSurfaceAllocatorNotify_iface; IVMRSurfaceAllocatorNotify9 IVMRSurfaceAllocatorNotify9_iface; IVMRWindowlessControl IVMRWindowlessControl_iface; IVMRWindowlessControl9 IVMRWindowlessControl9_iface; /* Devil May Cry 3 releases the last IBaseFilter reference while still * holding an IVMRSurfaceAllocatorNotify9 reference, and depends on * IVMRSurfaceAllocator9::TerminateDevice() being called as a result. * Native uses a separate reference count for IVMRSurfaceAllocatorNotify9. */ LONG IVMRSurfaceAllocatorNotify9_refcount; IOverlay IOverlay_iface; IVMRSurfaceAllocator9 *allocator; IVMRImagePresenter9 *presenter; DWORD stream_count; DWORD mixing_prefs; /* * The Video Mixing Renderer supports 3 modes, renderless, windowless and windowed * What I do is implement windowless as a special case of renderless, and then * windowed also as a special case of windowless. This is probably the easiest way. */ VMR9Mode mode; BITMAPINFOHEADER bmiheader; HMODULE hD3d9; /* Presentation related members */ IDirect3DDevice9 *allocator_d3d9_dev; IDirect3DSurface9 **surfaces; DWORD num_surfaces; DWORD cur_surface; DWORD_PTR cookie; HWND clipping_window; LONG VideoWidth; LONG VideoHeight; VMR9AspectRatioMode aspect_mode; HANDLE run_event; }; static inline BOOL is_vmr9(const struct quartz_vmr *filter) { return IsEqualGUID(&filter->renderer.filter.clsid, &CLSID_VideoMixingRenderer9); } static inline struct quartz_vmr *impl_from_video_window(struct video_window *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, window); } static inline struct quartz_vmr *impl_from_IAMCertifiedOutputProtection(IAMCertifiedOutputProtection *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IAMCertifiedOutputProtection_iface); } static inline struct quartz_vmr *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IAMFilterMiscFlags_iface); } static inline struct quartz_vmr *impl_from_IVMRFilterConfig(IVMRFilterConfig *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRFilterConfig_iface); } static inline struct quartz_vmr *impl_from_IVMRFilterConfig9(IVMRFilterConfig9 *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRFilterConfig9_iface); } static inline struct quartz_vmr *impl_from_IVMRMonitorConfig(IVMRMonitorConfig *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMonitorConfig_iface); } static inline struct quartz_vmr *impl_from_IVMRMonitorConfig9(IVMRMonitorConfig9 *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMonitorConfig9_iface); } static inline struct quartz_vmr *impl_from_IVMRSurfaceAllocatorNotify(IVMRSurfaceAllocatorNotify *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRSurfaceAllocatorNotify_iface); } static inline struct quartz_vmr *impl_from_IVMRSurfaceAllocatorNotify9(IVMRSurfaceAllocatorNotify9 *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRSurfaceAllocatorNotify9_iface); } static inline struct quartz_vmr *impl_from_IVMRWindowlessControl(IVMRWindowlessControl *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRWindowlessControl_iface); } static inline struct quartz_vmr *impl_from_IVMRWindowlessControl9(IVMRWindowlessControl9 *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRWindowlessControl9_iface); } struct default_presenter { IVMRImagePresenter9 IVMRImagePresenter9_iface; IVMRSurfaceAllocator9 IVMRSurfaceAllocator9_iface; LONG refCount; IDirect3DDevice9 *d3d9_dev; IDirect3D9 *d3d9_ptr; IDirect3DSurface9 **d3d9_surfaces; HMONITOR hMon; DWORD num_surfaces; VMR9AllocationInfo info; struct quartz_vmr* pVMR9; IVMRSurfaceAllocatorNotify9 *SurfaceAllocatorNotify; }; static inline struct default_presenter *impl_from_IVMRImagePresenter9(IVMRImagePresenter9 *iface) { return CONTAINING_RECORD(iface, struct default_presenter, IVMRImagePresenter9_iface); } static inline struct default_presenter *impl_from_IVMRSurfaceAllocator9(IVMRSurfaceAllocator9 *iface) { return CONTAINING_RECORD(iface, struct default_presenter, IVMRSurfaceAllocator9_iface); } static HRESULT VMR9DefaultAllocatorPresenterImpl_create(struct quartz_vmr *parent, LPVOID * ppv); static inline struct quartz_vmr *impl_from_IBaseFilter(IBaseFilter *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, renderer.filter.IBaseFilter_iface); } static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMediaSample *sample) { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); const HANDLE events[2] = {filter->run_event, filter->renderer.flush_event}; unsigned int data_size, width, depth, src_pitch; const BITMAPINFOHEADER *bitmap_header; REFERENCE_TIME start_time, end_time; VMR9PresentationInfo info = {}; D3DLOCKED_RECT locked_rect; BYTE *data = NULL; HRESULT hr; int height; TRACE("filter %p, sample %p.\n", filter, sample); /* It is possible that there is no device at this point */ 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 we render ourselves, and this is a preroll sample, discard it */ if (info.dwFlags & VMR9Sample_Preroll) { return S_OK; } if (FAILED(hr = IMediaSample_GetPointer(sample, &data))) { ERR("Failed to get pointer to sample data, hr %#x.\n", hr); return hr; } data_size = IMediaSample_GetActualDataLength(sample); bitmap_header = get_bitmap_header(&filter->renderer.sink.pin.mt); 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.rtStart = start_time; info.rtEnd = end_time; info.szAspectRatio.cx = width; info.szAspectRatio.cy = height; info.lpSurf = filter->surfaces[(++filter->cur_surface) % filter->num_surfaces]; if (FAILED(hr = IDirect3DSurface9_LockRect(info.lpSurf, &locked_rect, NULL, D3DLOCK_DISCARD))) { ERR("Failed to lock surface, hr %#x.\n", hr); return hr; } if (height > 0 && bitmap_header->biCompression == BI_RGB) { BYTE *dst = (BYTE *)locked_rect.pBits + (height * locked_rect.Pitch); const BYTE *src = data; TRACE("Inverting image.\n"); while (height--) { dst -= locked_rect.Pitch; memcpy(dst, src, width * depth / 8); src += src_pitch; } } else if (locked_rect.Pitch != src_pitch) { BYTE *dst = locked_rect.pBits; 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); while (height--) { memcpy(dst, src, width * depth / 8); src += src_pitch; dst += locked_rect.Pitch; } } else { memcpy(locked_rect.pBits, data, data_size); } IDirect3DSurface9_UnlockRect(info.lpSurf); hr = IVMRImagePresenter9_PresentImage(filter->presenter, filter->cookie, &info); if (filter->renderer.filter.state == State_Paused) { LeaveCriticalSection(&filter->renderer.csRenderLock); WaitForMultipleObjects(2, events, FALSE, INFINITE); EnterCriticalSection(&filter->renderer.csRenderLock); } return hr; } static HRESULT WINAPI VMR9_CheckMediaType(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 quartz_vmr *filter, VMR9AllocationInfo *info, DWORD count) { HRESULT hr; DWORD i; if (FAILED(hr = IVMRSurfaceAllocator9_InitializeDevice(filter->allocator, filter->cookie, info, &count))) { WARN("Failed to initialize device (flags %#x), hr %#x.\n", info->dwFlags, hr); return hr; } for (i = 0; i < count; ++i) { if (FAILED(hr = IVMRSurfaceAllocator9_GetSurface(filter->allocator, filter->cookie, i, 0, &filter->surfaces[i]))) { ERR("Failed to get surface %u, hr %#x.\n", i, hr); while (i--) IDirect3DSurface9_Release(filter->surfaces[i]); IVMRSurfaceAllocator9_TerminateDevice(filter->allocator, filter->cookie); return hr; } } return hr; } static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE *mt) { VMR9AllocationInfo info = {}; HRESULT hr = E_FAIL; DWORD count = 1; unsigned int i; static const struct { const GUID *subtype; D3DFORMAT format; DWORD flags; } formats[] = { {&MEDIASUBTYPE_ARGB1555, D3DFMT_A1R5G5B5, VMR9AllocFlag_TextureSurface}, {&MEDIASUBTYPE_ARGB32, D3DFMT_A8R8G8B8, VMR9AllocFlag_TextureSurface}, {&MEDIASUBTYPE_ARGB4444, D3DFMT_A4R4G4B4, VMR9AllocFlag_TextureSurface}, {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_NV12, MAKEFOURCC('N','V','1','2'), VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_UYVY, D3DFMT_UYVY, VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_YUY2, D3DFMT_YUY2, VMR9AllocFlag_OffscreenSurface}, {&MEDIASUBTYPE_YV12, MAKEFOURCC('Y','V','1','2'), VMR9AllocFlag_OffscreenSurface}, }; TRACE("Initializing in mode %u, our window %p, clipping window %p.\n", filter->mode, filter->window.hwnd, filter->clipping_window); if (filter->mode == VMR9Mode_Windowless && !filter->clipping_window) return S_OK; info.Pool = D3DPOOL_DEFAULT; info.MinBuffers = count; info.dwWidth = info.szAspectRatio.cx = info.szNativeSize.cx = filter->bmiheader.biWidth; info.dwHeight = info.szAspectRatio.cy = info.szNativeSize.cy = filter->bmiheader.biHeight; if (!(filter->surfaces = calloc(count, sizeof(IDirect3DSurface9 *)))) return E_OUTOFMEMORY; filter->num_surfaces = count; filter->cur_surface = 0; if (!is_vmr9(filter)) { switch (filter->bmiheader.biCompression) { case BI_RGB: switch (filter->bmiheader.biBitCount) { case 24: info.Format = D3DFMT_R8G8B8; break; case 32: info.Format = D3DFMT_X8R8G8B8; break; default: FIXME("Unhandled bit depth %u.\n", filter->bmiheader.biBitCount); 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 = filter->bmiheader.biCompression; info.dwFlags = VMR9AllocFlag_OffscreenSurface; break; default: WARN("Unhandled video compression %#x.\n", filter->bmiheader.biCompression); free(filter->surfaces); return VFW_E_TYPE_NOT_ACCEPTED; } if (FAILED(hr = initialize_device(filter, &info, count))) free(filter->surfaces); return hr; } for (i = 0; i < ARRAY_SIZE(formats); ++i) { if (IsEqualGUID(&mt->subtype, formats[i].subtype)) { info.Format = formats[i].format; if (formats[i].flags & VMR9AllocFlag_TextureSurface) { info.dwFlags = VMR9AllocFlag_TextureSurface; if (SUCCEEDED(hr = initialize_device(filter, &info, count))) return hr; } if (formats[i].flags & VMR9AllocFlag_OffscreenSurface) { info.dwFlags = VMR9AllocFlag_OffscreenSurface; if (SUCCEEDED(hr = initialize_device(filter, &info, count))) return hr; } } } free(filter->surfaces); return VFW_E_TYPE_NOT_ACCEPTED; } static void vmr_start_stream(struct strmbase_renderer *iface) { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); IVMRImagePresenter9_StartPresenting(filter->presenter, filter->cookie); if (filter->window.hwnd) ShowWindow(filter->window.hwnd, SW_SHOW); SetEvent(filter->run_event); } static void vmr_stop_stream(struct strmbase_renderer *iface) { struct quartz_vmr *This = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); TRACE("(%p)\n", This); if (This->renderer.filter.state == State_Running) IVMRImagePresenter9_StopPresenting(This->presenter, This->cookie); ResetEvent(This->run_event); } static HRESULT WINAPI VMR9_ShouldDrawSampleNow(struct strmbase_renderer *iface, IMediaSample *pSample, REFERENCE_TIME *start, REFERENCE_TIME *end) { /* Preroll means the sample isn't shown, this is used for key frames and things like that */ if (IMediaSample_IsPreroll(pSample) == S_OK) return E_FAIL; return S_FALSE; } static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt) { struct quartz_vmr *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; filter->bmiheader = *bitmap_header; filter->VideoWidth = bitmap_header->biWidth; filter->VideoHeight = bitmap_header->biHeight; SetRect(&rect, 0, 0, filter->VideoWidth, filter->VideoHeight); filter->window.src = filter->window.dst = 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); if (filter->mode || SUCCEEDED(hr = IVMRFilterConfig9_SetRenderingMode(&filter->IVMRFilterConfig9_iface, VMR9Mode_Windowed))) hr = allocate_surfaces(filter, mt); return hr; } static HRESULT WINAPI VMR9_BreakConnect(struct strmbase_renderer *This) { struct quartz_vmr *pVMR9 = impl_from_IBaseFilter(&This->filter.IBaseFilter_iface); HRESULT hr = S_OK; DWORD i; if (!pVMR9->mode) return S_FALSE; if (This->sink.pin.peer && pVMR9->allocator && pVMR9->presenter) { if (pVMR9->renderer.filter.state != State_Stopped) { ERR("Disconnecting while not stopped! UNTESTED!!\n"); } if (pVMR9->renderer.filter.state == State_Running) hr = IVMRImagePresenter9_StopPresenting(pVMR9->presenter, pVMR9->cookie); for (i = 0; i < pVMR9->num_surfaces; ++i) IDirect3DSurface9_Release(pVMR9->surfaces[i]); free(pVMR9->surfaces); IVMRSurfaceAllocator9_TerminateDevice(pVMR9->allocator, pVMR9->cookie); pVMR9->num_surfaces = 0; } return hr; } static void vmr_free(struct quartz_vmr *filter) { free(filter); InterlockedDecrement(&object_locks); } static void vmr_destroy(struct strmbase_renderer *iface) { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); video_window_cleanup(&filter->window); /* Devil May Cry 3 releases the IVMRSurfaceAllocatorNotify9 interface from * TerminateDevice(). Artificially increase the reference count so that we * don't free the filter yet. */ InterlockedIncrement(&filter->renderer.filter.refcount); if (filter->allocator) { IVMRSurfaceAllocator9_TerminateDevice(filter->allocator, filter->cookie); IVMRSurfaceAllocator9_Release(filter->allocator); } if (filter->presenter) IVMRImagePresenter9_Release(filter->presenter); filter->num_surfaces = 0; if (filter->allocator_d3d9_dev) { IDirect3DDevice9_Release(filter->allocator_d3d9_dev); filter->allocator_d3d9_dev = NULL; } CloseHandle(filter->run_event); FreeLibrary(filter->hD3d9); strmbase_renderer_cleanup(&filter->renderer); if (!filter->IVMRSurfaceAllocatorNotify9_refcount) vmr_free(filter); } static HRESULT vmr_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out) { struct quartz_vmr *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_IVMRFilterConfig9)) *out = &filter->IVMRFilterConfig9_iface; else if (IsEqualGUID(iid, &IID_IVMRMixerBitmap9) && is_vmr9(filter)) *out = &filter->IVMRMixerBitmap9_iface; else if (IsEqualGUID(iid, &IID_IVMRMixerControl9) && is_vmr9(filter) && filter->stream_count) *out = &filter->IVMRMixerControl9_iface; else if (IsEqualGUID(iid, &IID_IVMRMonitorConfig)) *out = &filter->IVMRMonitorConfig_iface; else if (IsEqualGUID(iid, &IID_IVMRMonitorConfig9)) *out = &filter->IVMRMonitorConfig9_iface; else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorNotify) && filter->mode == (VMR9Mode)VMRMode_Renderless && !is_vmr9(filter)) *out = &filter->IVMRSurfaceAllocatorNotify_iface; else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorNotify9) && filter->mode == VMR9Mode_Renderless && is_vmr9(filter)) *out = &filter->IVMRSurfaceAllocatorNotify9_iface; else if (IsEqualGUID(iid, &IID_IVMRWindowlessControl) && filter->mode == (VMR9Mode)VMRMode_Windowless && !is_vmr9(filter)) *out = &filter->IVMRWindowlessControl_iface; else if (IsEqualGUID(iid, &IID_IVMRWindowlessControl9) && filter->mode == VMR9Mode_Windowless && is_vmr9(filter)) *out = &filter->IVMRWindowlessControl9_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 quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); 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 = { .pfnCheckMediaType = VMR9_CheckMediaType, .pfnDoRenderSample = VMR9_DoRenderSample, .renderer_start_stream = vmr_start_stream, .renderer_stop_stream = vmr_stop_stream, .pfnShouldDrawSampleNow = VMR9_ShouldDrawSampleNow, .renderer_connect = vmr_connect, .pfnBreakConnect = VMR9_BreakConnect, .renderer_destroy = vmr_destroy, .renderer_query_interface = vmr_query_interface, .renderer_pin_query_interface = vmr_pin_query_interface, }; static RECT vmr_get_default_rect(struct video_window *This) { struct quartz_vmr *pVMR9 = impl_from_video_window(This); static RECT defRect; SetRect(&defRect, 0, 0, pVMR9->VideoWidth, pVMR9->VideoHeight); return defRect; } static HRESULT vmr_get_current_image(struct video_window *iface, LONG *size, LONG *image) { struct quartz_vmr *filter = impl_from_video_window(iface); IDirect3DSurface9 *rt = NULL, *surface = NULL; D3DLOCKED_RECT locked_rect; IDirect3DDevice9 *device; unsigned int row_size; BITMAPINFOHEADER bih; LONG i, size_left; char *dst; HRESULT hr; EnterCriticalSection(&filter->renderer.csRenderLock); device = filter->allocator_d3d9_dev; bih = *get_bitmap_header(&filter->renderer.sink.pin.mt); bih.biSizeImage = bih.biWidth * bih.biHeight * bih.biBitCount / 8; if (!image) { *size = sizeof(BITMAPINFOHEADER) + bih.biSizeImage; LeaveCriticalSection(&filter->renderer.csRenderLock); 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 (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.csRenderLock); return hr; } 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 AMCertifiedOutputProtection_QueryInterface(IAMCertifiedOutputProtection *iface, REFIID riid, void **ppv) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI AMCertifiedOutputProtection_AddRef(IAMCertifiedOutputProtection *iface) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI AMCertifiedOutputProtection_Release(IAMCertifiedOutputProtection *iface) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI AMCertifiedOutputProtection_KeyExchange(IAMCertifiedOutputProtection *iface, GUID* pRandom, BYTE** VarLenCertGH, DWORD* pdwLengthCertGH) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); FIXME("(%p/%p)->(%p, %p, %p) stub\n", iface, This, pRandom, VarLenCertGH, pdwLengthCertGH); return VFW_E_NO_COPP_HW; } static HRESULT WINAPI AMCertifiedOutputProtection_SessionSequenceStart(IAMCertifiedOutputProtection *iface, AMCOPPSignature* pSig) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, pSig); return VFW_E_NO_COPP_HW; } static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionCommand(IAMCertifiedOutputProtection *iface, const AMCOPPCommand* cmd) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, cmd); return VFW_E_NO_COPP_HW; } static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionStatus(IAMCertifiedOutputProtection *iface, const AMCOPPStatusInput* pStatusInput, AMCOPPStatusOutput* pStatusOutput) { struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface); FIXME("(%p/%p)->(%p, %p) stub\n", iface, This, pStatusInput, pStatusOutput); return VFW_E_NO_COPP_HW; } static const IAMCertifiedOutputProtectionVtbl IAMCertifiedOutputProtection_Vtbl = { AMCertifiedOutputProtection_QueryInterface, AMCertifiedOutputProtection_AddRef, AMCertifiedOutputProtection_Release, AMCertifiedOutputProtection_KeyExchange, AMCertifiedOutputProtection_SessionSequenceStart, AMCertifiedOutputProtection_ProtectionCommand, AMCertifiedOutputProtection_ProtectionStatus }; static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) { struct quartz_vmr *This = impl_from_IAMFilterMiscFlags(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) { struct quartz_vmr *This = impl_from_IAMFilterMiscFlags(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) { struct quartz_vmr *This = impl_from_IAMFilterMiscFlags(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) { return AM_FILTER_MISC_FLAGS_IS_RENDERER; } static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = { AMFilterMiscFlags_QueryInterface, AMFilterMiscFlags_AddRef, AMFilterMiscFlags_Release, AMFilterMiscFlags_GetMiscFlags }; static HRESULT WINAPI VMR7FilterConfig_QueryInterface(IVMRFilterConfig *iface, REFIID riid, void** ppv) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR7FilterConfig_AddRef(IVMRFilterConfig *iface) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR7FilterConfig_Release(IVMRFilterConfig *iface) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR7FilterConfig_SetImageCompositor(IVMRFilterConfig *iface, IVMRImageCompositor *compositor) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor); return E_NOTIMPL; } static HRESULT WINAPI VMR7FilterConfig_SetNumberOfStreams(IVMRFilterConfig *iface, DWORD max) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); FIXME("(%p/%p)->(%u) stub\n", iface, This, max); return E_NOTIMPL; } static HRESULT WINAPI VMR7FilterConfig_GetNumberOfStreams(IVMRFilterConfig *iface, DWORD *max) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, max); return E_NOTIMPL; } static HRESULT WINAPI VMR7FilterConfig_SetRenderingPrefs(IVMRFilterConfig *iface, DWORD renderflags) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags); return E_NOTIMPL; } static HRESULT WINAPI VMR7FilterConfig_GetRenderingPrefs(IVMRFilterConfig *iface, DWORD *renderflags) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags); return E_NOTIMPL; } static HRESULT WINAPI VMR7FilterConfig_SetRenderingMode(IVMRFilterConfig *iface, DWORD mode) { struct quartz_vmr *filter = impl_from_IVMRFilterConfig(iface); TRACE("iface %p, mode %#x.\n", iface, mode); return IVMRFilterConfig9_SetRenderingMode(&filter->IVMRFilterConfig9_iface, mode); } static HRESULT WINAPI VMR7FilterConfig_GetRenderingMode(IVMRFilterConfig *iface, DWORD *mode) { struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface); TRACE("(%p/%p)->(%p)\n", iface, This, mode); if (!mode) return E_POINTER; if (This->mode) *mode = This->mode; else *mode = VMRMode_Windowed; return S_OK; } static const IVMRFilterConfigVtbl VMR7_FilterConfig_Vtbl = { VMR7FilterConfig_QueryInterface, VMR7FilterConfig_AddRef, VMR7FilterConfig_Release, VMR7FilterConfig_SetImageCompositor, VMR7FilterConfig_SetNumberOfStreams, VMR7FilterConfig_GetNumberOfStreams, VMR7FilterConfig_SetRenderingPrefs, VMR7FilterConfig_GetRenderingPrefs, VMR7FilterConfig_SetRenderingMode, VMR7FilterConfig_GetRenderingMode }; struct get_available_monitors_args { VMRMONITORINFO *info7; VMR9MonitorInfo *info9; DWORD arraysize; DWORD numdev; }; static BOOL CALLBACK get_available_monitors_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, LPARAM lparam) { struct get_available_monitors_args *args = (struct get_available_monitors_args *)lparam; MONITORINFOEXW mi; if (args->info7 || args->info9) { if (!args->arraysize) return FALSE; mi.cbSize = sizeof(mi); if (!GetMonitorInfoW(hmon, (MONITORINFO*)&mi)) return TRUE; /* fill VMRMONITORINFO struct */ if (args->info7) { VMRMONITORINFO *info = args->info7++; memset(info, 0, sizeof(*info)); if (args->numdev > 0) { info->guid.pGUID = &info->guid.GUID; info->guid.GUID.Data4[7] = args->numdev; } else info->guid.pGUID = NULL; info->rcMonitor = mi.rcMonitor; info->hMon = hmon; 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 = hmon; 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->arraysize--; } args->numdev++; return TRUE; } static HRESULT WINAPI VMR7MonitorConfig_QueryInterface(IVMRMonitorConfig *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR7MonitorConfig_AddRef(IVMRMonitorConfig *iface) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR7MonitorConfig_Release(IVMRMonitorConfig *iface) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR7MonitorConfig_SetMonitor(IVMRMonitorConfig *iface, const VMRGUID *pGUID) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID); if (!pGUID) return E_POINTER; return S_OK; } static HRESULT WINAPI VMR7MonitorConfig_GetMonitor(IVMRMonitorConfig *iface, VMRGUID *pGUID) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID); if (!pGUID) return E_POINTER; pGUID->pGUID = NULL; /* default DirectDraw device */ return S_OK; } static HRESULT WINAPI VMR7MonitorConfig_SetDefaultMonitor(IVMRMonitorConfig *iface, const VMRGUID *pGUID) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID); if (!pGUID) return E_POINTER; return S_OK; } static HRESULT WINAPI VMR7MonitorConfig_GetDefaultMonitor(IVMRMonitorConfig *iface, VMRGUID *pGUID) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID); if (!pGUID) return E_POINTER; pGUID->pGUID = NULL; /* default DirectDraw device */ return S_OK; } static HRESULT WINAPI VMR7MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig *iface, VMRMONITORINFO *info, DWORD arraysize, DWORD *numdev) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface); struct get_available_monitors_args args; FIXME("(%p/%p)->(%p, %u, %p) semi-stub\n", iface, This, info, arraysize, numdev); if (!numdev) return E_POINTER; if (info && arraysize == 0) return E_INVALIDARG; args.info7 = info; args.info9 = NULL; args.arraysize = arraysize; args.numdev = 0; EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args); *numdev = args.numdev; return S_OK; } static const IVMRMonitorConfigVtbl VMR7_MonitorConfig_Vtbl = { VMR7MonitorConfig_QueryInterface, VMR7MonitorConfig_AddRef, VMR7MonitorConfig_Release, VMR7MonitorConfig_SetMonitor, VMR7MonitorConfig_GetMonitor, VMR7MonitorConfig_SetDefaultMonitor, VMR7MonitorConfig_GetDefaultMonitor, VMR7MonitorConfig_GetAvailableMonitors }; static HRESULT WINAPI VMR9MonitorConfig_QueryInterface(IVMRMonitorConfig9 *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR9MonitorConfig_AddRef(IVMRMonitorConfig9 *iface) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR9MonitorConfig_Release(IVMRMonitorConfig9 *iface) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR9MonitorConfig_SetMonitor(IVMRMonitorConfig9 *iface, UINT uDev) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); FIXME("(%p/%p)->(%u) stub\n", iface, This, uDev); return S_OK; } static HRESULT WINAPI VMR9MonitorConfig_GetMonitor(IVMRMonitorConfig9 *iface, UINT *uDev) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, uDev); if (!uDev) return E_POINTER; *uDev = 0; return S_OK; } static HRESULT WINAPI VMR9MonitorConfig_SetDefaultMonitor(IVMRMonitorConfig9 *iface, UINT uDev) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); FIXME("(%p/%p)->(%u) stub\n", iface, This, uDev); return S_OK; } static HRESULT WINAPI VMR9MonitorConfig_GetDefaultMonitor(IVMRMonitorConfig9 *iface, UINT *uDev) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, uDev); if (!uDev) return E_POINTER; *uDev = 0; return S_OK; } static HRESULT WINAPI VMR9MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig9 *iface, VMR9MonitorInfo *info, DWORD arraysize, DWORD *numdev) { struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface); struct get_available_monitors_args args; FIXME("(%p/%p)->(%p, %u, %p) semi-stub\n", iface, This, info, arraysize, numdev); if (!numdev) return E_POINTER; if (info && arraysize == 0) return E_INVALIDARG; args.info7 = NULL; args.info9 = info; args.arraysize = arraysize; args.numdev = 0; EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args); *numdev = args.numdev; return S_OK; } static const IVMRMonitorConfig9Vtbl VMR9_MonitorConfig_Vtbl = { VMR9MonitorConfig_QueryInterface, VMR9MonitorConfig_AddRef, VMR9MonitorConfig_Release, VMR9MonitorConfig_SetMonitor, VMR9MonitorConfig_GetMonitor, VMR9MonitorConfig_SetDefaultMonitor, VMR9MonitorConfig_GetDefaultMonitor, VMR9MonitorConfig_GetAvailableMonitors }; static HRESULT WINAPI VMR9FilterConfig_QueryInterface(IVMRFilterConfig9 *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR9FilterConfig_AddRef(IVMRFilterConfig9 *iface) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR9FilterConfig_Release(IVMRFilterConfig9 *iface) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR9FilterConfig_SetImageCompositor(IVMRFilterConfig9 *iface, IVMRImageCompositor9 *compositor) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor); return E_NOTIMPL; } static HRESULT WINAPI VMR9FilterConfig_SetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD count) { struct quartz_vmr *filter = impl_from_IVMRFilterConfig9(iface); FIXME("iface %p, count %u, stub!\n", iface, count); if (!count) { WARN("Application requested zero streams; returning E_INVALIDARG.\n"); return E_INVALIDARG; } EnterCriticalSection(&filter->renderer.filter.csFilter); if (filter->stream_count) { LeaveCriticalSection(&filter->renderer.filter.csFilter); 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.csFilter); return S_OK; } static HRESULT WINAPI VMR9FilterConfig_GetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD *count) { struct quartz_vmr *filter = impl_from_IVMRFilterConfig9(iface); TRACE("filter %p, count %p.\n", filter, count); EnterCriticalSection(&filter->renderer.filter.csFilter); if (!filter->stream_count) { LeaveCriticalSection(&filter->renderer.filter.csFilter); return VFW_E_VMR_NOT_IN_MIXER_MODE; } *count = filter->stream_count; LeaveCriticalSection(&filter->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI VMR9FilterConfig_SetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD renderflags) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags); return E_NOTIMPL; } static HRESULT WINAPI VMR9FilterConfig_GetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD *renderflags) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags); return E_NOTIMPL; } static HRESULT WINAPI VMR9FilterConfig_SetRenderingMode(IVMRFilterConfig9 *iface, DWORD mode) { HRESULT hr = S_OK; struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); TRACE("(%p/%p)->(%u)\n", iface, This, mode); EnterCriticalSection(&This->renderer.filter.csFilter); if (This->mode) { LeaveCriticalSection(&This->renderer.filter.csFilter); return VFW_E_WRONG_STATE; } if (This->allocator) IVMRSurfaceAllocator9_Release(This->allocator); if (This->presenter) IVMRImagePresenter9_Release(This->presenter); This->allocator = NULL; This->presenter = NULL; switch (mode) { case VMR9Mode_Windowed: case VMR9Mode_Windowless: This->cookie = ~0; hr = VMR9DefaultAllocatorPresenterImpl_create(This, (LPVOID*)&This->presenter); if (SUCCEEDED(hr)) hr = IVMRImagePresenter9_QueryInterface(This->presenter, &IID_IVMRSurfaceAllocator9, (void **)&This->allocator); if (FAILED(hr)) { ERR("Unable to find Presenter interface\n"); IVMRImagePresenter9_Release(This->presenter); This->allocator = NULL; This->presenter = NULL; } else hr = IVMRSurfaceAllocator9_AdviseNotify(This->allocator, &This->IVMRSurfaceAllocatorNotify9_iface); break; case VMR9Mode_Renderless: break; default: LeaveCriticalSection(&This->renderer.filter.csFilter); return E_INVALIDARG; } if (mode != VMR9Mode_Windowed) video_window_cleanup(&This->window); This->mode = mode; LeaveCriticalSection(&This->renderer.filter.csFilter); return hr; } static HRESULT WINAPI VMR9FilterConfig_GetRenderingMode(IVMRFilterConfig9 *iface, DWORD *mode) { struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface); TRACE("(%p/%p)->(%p)\n", iface, This, mode); if (!mode) return E_POINTER; if (This->mode) *mode = This->mode; else *mode = VMR9Mode_Windowed; return S_OK; } static const IVMRFilterConfig9Vtbl VMR9_FilterConfig_Vtbl = { VMR9FilterConfig_QueryInterface, VMR9FilterConfig_AddRef, VMR9FilterConfig_Release, VMR9FilterConfig_SetImageCompositor, VMR9FilterConfig_SetNumberOfStreams, VMR9FilterConfig_GetNumberOfStreams, VMR9FilterConfig_SetRenderingPrefs, VMR9FilterConfig_GetRenderingPrefs, VMR9FilterConfig_SetRenderingMode, VMR9FilterConfig_GetRenderingMode }; static HRESULT WINAPI VMR7WindowlessControl_QueryInterface(IVMRWindowlessControl *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR7WindowlessControl_AddRef(IVMRWindowlessControl *iface) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR7WindowlessControl_Release(IVMRWindowlessControl *iface) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR7WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl *iface, LONG *width, LONG *height, LONG *arwidth, LONG *arheight) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); TRACE("(%p/%p)->(%p, %p, %p, %p)\n", iface, This, width, height, arwidth, arheight); if (!width || !height || !arwidth || !arheight) { ERR("Got no pointer\n"); return E_POINTER; } *width = This->bmiheader.biWidth; *height = This->bmiheader.biHeight; *arwidth = This->bmiheader.biWidth; *arheight = This->bmiheader.biHeight; return S_OK; } static HRESULT WINAPI VMR7WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl *iface, LONG *width, LONG *height) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl *iface, LONG *width, LONG *height) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_SetVideoPosition(IVMRWindowlessControl *iface, const RECT *source, const RECT *dest) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); TRACE("(%p/%p)->(%p, %p)\n", iface, This, source, dest); EnterCriticalSection(&This->renderer.filter.csFilter); if (source) This->window.src = *source; if (dest) This->window.dst = *dest; LeaveCriticalSection(&This->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI VMR7WindowlessControl_GetVideoPosition(IVMRWindowlessControl *iface, RECT *source, RECT *dest) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); if (source) *source = This->window.src; if (dest) *dest = This->window.dst; FIXME("(%p/%p)->(%p/%p) stub\n", iface, This, source, dest); return S_OK; } static HRESULT WINAPI VMR7WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl *iface, DWORD *mode) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl *iface, DWORD mode) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl *iface, HWND window) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl(iface); TRACE("iface %p, window %p.\n", iface, window); return IVMRWindowlessControl9_SetVideoClippingWindow(&filter->IVMRWindowlessControl9_iface, window); } static HRESULT WINAPI VMR7WindowlessControl_RepaintVideo(IVMRWindowlessControl *iface, HWND hwnd, HDC hdc) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_DisplayModeChanged(IVMRWindowlessControl *iface) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_GetCurrentImage(IVMRWindowlessControl *iface, BYTE **dib) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_SetBorderColor(IVMRWindowlessControl *iface, COLORREF color) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_GetBorderColor(IVMRWindowlessControl *iface, COLORREF *color) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_SetColorKey(IVMRWindowlessControl *iface, COLORREF color) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7WindowlessControl_GetColorKey(IVMRWindowlessControl *iface, COLORREF *color) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static const IVMRWindowlessControlVtbl VMR7_WindowlessControl_Vtbl = { VMR7WindowlessControl_QueryInterface, VMR7WindowlessControl_AddRef, VMR7WindowlessControl_Release, VMR7WindowlessControl_GetNativeVideoSize, VMR7WindowlessControl_GetMinIdealVideoSize, VMR7WindowlessControl_GetMaxIdealVideoSize, VMR7WindowlessControl_SetVideoPosition, VMR7WindowlessControl_GetVideoPosition, VMR7WindowlessControl_GetAspectRatioMode, VMR7WindowlessControl_SetAspectRatioMode, VMR7WindowlessControl_SetVideoClippingWindow, VMR7WindowlessControl_RepaintVideo, VMR7WindowlessControl_DisplayModeChanged, VMR7WindowlessControl_GetCurrentImage, VMR7WindowlessControl_SetBorderColor, VMR7WindowlessControl_GetBorderColor, VMR7WindowlessControl_SetColorKey, VMR7WindowlessControl_GetColorKey }; static HRESULT WINAPI VMR9WindowlessControl_QueryInterface(IVMRWindowlessControl9 *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR9WindowlessControl_AddRef(IVMRWindowlessControl9 *iface) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR9WindowlessControl_Release(IVMRWindowlessControl9 *iface) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height, LONG *aspect_width, LONG *aspect_height) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(iface); 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 = filter->bmiheader.biWidth; *height = filter->bmiheader.biHeight; if (aspect_width) *aspect_width = filter->bmiheader.biWidth; if (aspect_height) *aspect_height = filter->bmiheader.biHeight; return S_OK; } static HRESULT WINAPI VMR9WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR9WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR9WindowlessControl_SetVideoPosition(IVMRWindowlessControl9 *iface, const RECT *src, const RECT *dst) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(iface); TRACE("filter %p, src %s, dst %s.\n", filter, wine_dbgstr_rect(src), wine_dbgstr_rect(dst)); EnterCriticalSection(&filter->renderer.filter.csFilter); if (src) filter->window.src = *src; if (dst) filter->window.dst = *dst; LeaveCriticalSection(&filter->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI VMR9WindowlessControl_GetVideoPosition(IVMRWindowlessControl9 *iface, RECT *src, RECT *dst) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(iface); TRACE("filter %p, src %p, dst %p.\n", filter, src, dst); if (src) *src = filter->window.src; if (dst) *dst = filter->window.dst; return S_OK; } static HRESULT WINAPI VMR9WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD *mode) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(iface); TRACE("filter %p, mode %p.\n", filter, mode); EnterCriticalSection(&filter->renderer.filter.csFilter); *mode = filter->aspect_mode; LeaveCriticalSection(&filter->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI VMR9WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD mode) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(iface); TRACE("filter %p, mode %u.\n", filter, mode); EnterCriticalSection(&filter->renderer.filter.csFilter); filter->aspect_mode = mode; LeaveCriticalSection(&filter->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl9 *iface, HWND window) { struct quartz_vmr *filter = impl_from_IVMRWindowlessControl9(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.csFilter); if (filter->renderer.sink.pin.peer) { LeaveCriticalSection(&filter->renderer.filter.csFilter); 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 = IVMRFilterConfig9_SetNumberOfStreams(&filter->IVMRFilterConfig9_iface, 4); LeaveCriticalSection(&filter->renderer.filter.csFilter); return hr; } static HRESULT WINAPI VMR9WindowlessControl_RepaintVideo(IVMRWindowlessControl9 *iface, HWND hwnd, HDC hdc) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); HRESULT hr; FIXME("(%p/%p)->(...) semi-stub\n", iface, This); EnterCriticalSection(&This->renderer.filter.csFilter); if (hwnd != This->clipping_window) { ERR("Not handling changing windows yet!!!\n"); LeaveCriticalSection(&This->renderer.filter.csFilter); return S_OK; } if (!This->allocator_d3d9_dev) { ERR("No d3d9 device!\n"); LeaveCriticalSection(&This->renderer.filter.csFilter); return VFW_E_WRONG_STATE; } /* Windowless extension */ hr = IDirect3DDevice9_Present(This->allocator_d3d9_dev, NULL, NULL, NULL, NULL); LeaveCriticalSection(&This->renderer.filter.csFilter); return hr; } static HRESULT WINAPI VMR9WindowlessControl_DisplayModeChanged(IVMRWindowlessControl9 *iface) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR9WindowlessControl_GetCurrentImage(IVMRWindowlessControl9 *iface, BYTE **dib) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR9WindowlessControl_SetBorderColor(IVMRWindowlessControl9 *iface, COLORREF color) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR9WindowlessControl_GetBorderColor(IVMRWindowlessControl9 *iface, COLORREF *color) { struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static const IVMRWindowlessControl9Vtbl VMR9_WindowlessControl_Vtbl = { VMR9WindowlessControl_QueryInterface, VMR9WindowlessControl_AddRef, VMR9WindowlessControl_Release, VMR9WindowlessControl_GetNativeVideoSize, VMR9WindowlessControl_GetMinIdealVideoSize, VMR9WindowlessControl_GetMaxIdealVideoSize, VMR9WindowlessControl_SetVideoPosition, VMR9WindowlessControl_GetVideoPosition, VMR9WindowlessControl_GetAspectRatioMode, VMR9WindowlessControl_SetAspectRatioMode, VMR9WindowlessControl_SetVideoClippingWindow, VMR9WindowlessControl_RepaintVideo, VMR9WindowlessControl_DisplayModeChanged, VMR9WindowlessControl_GetCurrentImage, VMR9WindowlessControl_SetBorderColor, VMR9WindowlessControl_GetBorderColor }; static HRESULT WINAPI VMR7SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR7SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify *iface) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); return IUnknown_AddRef(This->renderer.filter.outer_unk); } static ULONG WINAPI VMR7SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify *iface) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); return IUnknown_Release(This->renderer.filter.outer_unk); } static HRESULT WINAPI VMR7SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify *iface, DWORD_PTR id, IVMRSurfaceAllocator *alloc) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7SurfaceAllocatorNotify_SetDDrawDevice(IVMRSurfaceAllocatorNotify *iface, IDirectDraw7 *device, HMONITOR monitor) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7SurfaceAllocatorNotify_ChangeDDrawDevice(IVMRSurfaceAllocatorNotify *iface, IDirectDraw7 *device, HMONITOR monitor) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7SurfaceAllocatorNotify_RestoreDDrawSurfaces(IVMRSurfaceAllocatorNotify *iface) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify *iface, LONG code, LONG_PTR param1, LONG_PTR param2) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI VMR7SurfaceAllocatorNotify_SetBorderColor(IVMRSurfaceAllocatorNotify *iface, COLORREF clrBorder) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static const IVMRSurfaceAllocatorNotifyVtbl VMR7_SurfaceAllocatorNotify_Vtbl = { VMR7SurfaceAllocatorNotify_QueryInterface, VMR7SurfaceAllocatorNotify_AddRef, VMR7SurfaceAllocatorNotify_Release, VMR7SurfaceAllocatorNotify_AdviseSurfaceAllocator, VMR7SurfaceAllocatorNotify_SetDDrawDevice, VMR7SurfaceAllocatorNotify_ChangeDDrawDevice, VMR7SurfaceAllocatorNotify_RestoreDDrawSurfaces, VMR7SurfaceAllocatorNotify_NotifyEvent, VMR7SurfaceAllocatorNotify_SetBorderColor }; static HRESULT WINAPI VMR9SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify9 *iface, REFIID riid, LPVOID * ppv) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppv); } static ULONG WINAPI VMR9SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify9 *iface) { struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface); ULONG refcount = InterlockedIncrement(&filter->IVMRSurfaceAllocatorNotify9_refcount); TRACE("%p increasing refcount to %u.\n", iface, refcount); return refcount; } static ULONG WINAPI VMR9SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify9 *iface) { struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface); ULONG refcount = InterlockedDecrement(&filter->IVMRSurfaceAllocatorNotify9_refcount); TRACE("%p decreasing refcount to %u.\n", iface, refcount); if (!refcount && !filter->renderer.filter.refcount) vmr_free(filter); return refcount; } static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator( IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR cookie, IVMRSurfaceAllocator9 *allocator) { struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface); TRACE("filter %p, cookie %#Ix, allocator %p.\n", filter, cookie, allocator); filter->cookie = cookie; if (filter->presenter) return VFW_E_WRONG_STATE; if (FAILED(IVMRSurfaceAllocator9_QueryInterface(allocator, &IID_IVMRImagePresenter9, (void **)&filter->presenter))) return E_NOINTERFACE; filter->allocator = allocator; IVMRSurfaceAllocator9_AddRef(allocator); return S_OK; } static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor) { struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface); TRACE("filter %p, device %p, monitor %p.\n", filter, device, monitor); if (filter->allocator_d3d9_dev) IDirect3DDevice9_Release(filter->allocator_d3d9_dev); filter->allocator_d3d9_dev = device; IDirect3DDevice9_AddRef(device); return S_OK; } static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); FIXME("(%p/%p)->(...) semi-stub\n", iface, This); if (This->allocator_d3d9_dev) IDirect3DDevice9_Release(This->allocator_d3d9_dev); This->allocator_d3d9_dev = device; IDirect3DDevice9_AddRef(This->allocator_d3d9_dev); return S_OK; } static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfaceAllocatorNotify9 *iface, VMR9AllocationInfo *allocinfo, DWORD *numbuffers, IDirect3DSurface9 **surface) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); DWORD i; HRESULT hr = S_OK; TRACE("filter %p, allocinfo %p, numbuffers %p, surface %p.\n", This, numbuffers, allocinfo, surface); if (!allocinfo || !numbuffers || !surface) return E_POINTER; TRACE("Flags %#x, size %ux%u, format %u (%#x), pool %u, minimum buffers %u.\n", allocinfo->dwFlags, allocinfo->dwWidth, allocinfo->dwHeight, allocinfo->Format, allocinfo->Format, allocinfo->Pool, allocinfo->MinBuffers); if (!allocinfo->Format) { IDirect3DSurface9 *backbuffer; D3DSURFACE_DESC desc; IDirect3DDevice9_GetBackBuffer(This->allocator_d3d9_dev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); IDirect3DSurface9_GetDesc(backbuffer, &desc); IDirect3DSurface9_Release(backbuffer); allocinfo->Format = desc.Format; } if (!*numbuffers || *numbuffers < allocinfo->MinBuffers) { WARN("%u surfaces requested (minimum %u); returning E_INVALIDARG.\n", *numbuffers, allocinfo->MinBuffers); return E_INVALIDARG; } if (!This->allocator_d3d9_dev) { WARN("No Direct3D device; returning VFW_E_WRONG_STATE.\n"); return VFW_E_WRONG_STATE; } if (allocinfo->dwFlags == VMR9AllocFlag_OffscreenSurface) { for (i = 0; i < *numbuffers; ++i) { hr = IDirect3DDevice9_CreateOffscreenPlainSurface(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, allocinfo->Format, allocinfo->Pool, &surface[i], NULL); if (FAILED(hr)) break; } } else if (allocinfo->dwFlags == VMR9AllocFlag_TextureSurface) { for (i = 0; i < *numbuffers; ++i) { IDirect3DTexture9 *texture; hr = IDirect3DDevice9_CreateTexture(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, 1, D3DUSAGE_DYNAMIC, allocinfo->Format, allocinfo->Pool, &texture, NULL); if (FAILED(hr)) break; IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface[i]); IDirect3DTexture9_Release(texture); } } else if (allocinfo->dwFlags == VMR9AllocFlag_3DRenderTarget) { for (i = 0; i < *numbuffers; ++i) { if (FAILED(hr = IDirect3DDevice9_CreateRenderTarget(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, allocinfo->Format, D3DMULTISAMPLE_NONE, 0, FALSE, &surface[i], NULL))) break; } } else { FIXME("Unhandled flags %#x.\n", allocinfo->dwFlags); return E_NOTIMPL; } if (FAILED(hr)) WARN("%u/%u surfaces allocated, hr %#x.\n", i, *numbuffers, hr); if (i >= allocinfo->MinBuffers) { hr = S_OK; *numbuffers = i; } else { for ( ; i > 0; --i) IDirect3DSurface9_Release(surface[i - 1]); *numbuffers = 0; } return hr; } static HRESULT WINAPI VMR9SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify9 *iface, LONG code, LONG_PTR param1, LONG_PTR param2) { struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); FIXME("(%p/%p)->(...) stub\n", iface, This); return E_NOTIMPL; } static const IVMRSurfaceAllocatorNotify9Vtbl VMR9_SurfaceAllocatorNotify_Vtbl = { VMR9SurfaceAllocatorNotify_QueryInterface, VMR9SurfaceAllocatorNotify_AddRef, VMR9SurfaceAllocatorNotify_Release, VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator, VMR9SurfaceAllocatorNotify_SetD3DDevice, VMR9SurfaceAllocatorNotify_ChangeD3DDevice, VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper, VMR9SurfaceAllocatorNotify_NotifyEvent }; static inline struct quartz_vmr *impl_from_IVMRMixerControl9(IVMRMixerControl9 *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMixerControl9_iface); } static HRESULT WINAPI mixer_control9_QueryInterface(IVMRMixerControl9 *iface, REFIID iid, void **out) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out); } static ULONG WINAPI mixer_control9_AddRef(IVMRMixerControl9 *iface) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); return IUnknown_AddRef(filter->renderer.filter.outer_unk); } static ULONG WINAPI mixer_control9_Release(IVMRMixerControl9 *iface) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); return IUnknown_Release(filter->renderer.filter.outer_unk); } static HRESULT WINAPI mixer_control9_SetAlpha(IVMRMixerControl9 *iface, DWORD stream, float alpha) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, stream %u, alpha %.8e, stub!\n", filter, stream, alpha); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_GetAlpha(IVMRMixerControl9 *iface, DWORD stream, float *alpha) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, stream %u, alpha %p, stub!\n", filter, stream, alpha); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_SetZOrder(IVMRMixerControl9 *iface, DWORD stream, DWORD z) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, stream %u, z %u, stub!\n", filter, stream, z); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_GetZOrder(IVMRMixerControl9 *iface, DWORD stream, DWORD *z) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, stream %u, z %p, stub!\n", filter, stream, z); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_SetOutputRect(IVMRMixerControl9 *iface, DWORD stream, const VMR9NormalizedRect *rect) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, stream %u, rect %s, stub!\n", filter, stream, debugstr_normalized_rect(rect)); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_GetOutputRect(IVMRMixerControl9 *iface, DWORD stream, VMR9NormalizedRect *rect) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, stream %u, rect %p, stub!\n", filter, stream, rect); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_SetBackgroundClr(IVMRMixerControl9 *iface, COLORREF color) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, color #%06x, stub!\n", filter, color); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_GetBackgroundClr(IVMRMixerControl9 *iface, COLORREF *color) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, color %p, stub!\n", filter, color); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_SetMixingPrefs(IVMRMixerControl9 *iface, DWORD flags) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, flags %#x, stub!\n", filter, flags); EnterCriticalSection(&filter->renderer.filter.csFilter); filter->mixing_prefs = flags; LeaveCriticalSection(&filter->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI mixer_control9_GetMixingPrefs(IVMRMixerControl9 *iface, DWORD *flags) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, flags %p, stub!\n", filter, flags); EnterCriticalSection(&filter->renderer.filter.csFilter); *flags = filter->mixing_prefs; LeaveCriticalSection(&filter->renderer.filter.csFilter); return S_OK; } static HRESULT WINAPI mixer_control9_SetProcAmpControl(IVMRMixerControl9 *iface, DWORD stream, VMR9ProcAmpControl *settings) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, settings %p, stub!\n", filter, settings); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_GetProcAmpControl(IVMRMixerControl9 *iface, DWORD stream, VMR9ProcAmpControl *settings) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, settings %p, stub!\n", filter, settings); return E_NOTIMPL; } static HRESULT WINAPI mixer_control9_GetProcAmpControlRange(IVMRMixerControl9 *iface, DWORD stream, VMR9ProcAmpControlRange *settings) { struct quartz_vmr *filter = impl_from_IVMRMixerControl9(iface); FIXME("filter %p, settings %p, stub!\n", filter, settings); return E_NOTIMPL; } static const IVMRMixerControl9Vtbl mixer_control9_vtbl = { mixer_control9_QueryInterface, mixer_control9_AddRef, mixer_control9_Release, mixer_control9_SetAlpha, mixer_control9_GetAlpha, mixer_control9_SetZOrder, mixer_control9_GetZOrder, mixer_control9_SetOutputRect, mixer_control9_GetOutputRect, mixer_control9_SetBackgroundClr, mixer_control9_GetBackgroundClr, mixer_control9_SetMixingPrefs, mixer_control9_GetMixingPrefs, mixer_control9_SetProcAmpControl, mixer_control9_GetProcAmpControl, mixer_control9_GetProcAmpControlRange, }; static inline struct quartz_vmr *impl_from_IVMRMixerBitmap9(IVMRMixerBitmap9 *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMixerBitmap9_iface); } static HRESULT WINAPI mixer_bitmap9_QueryInterface(IVMRMixerBitmap9 *iface, REFIID iid, void **out) { struct quartz_vmr *filter = impl_from_IVMRMixerBitmap9(iface); return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out); } static ULONG WINAPI mixer_bitmap9_AddRef(IVMRMixerBitmap9 *iface) { struct quartz_vmr *filter = impl_from_IVMRMixerBitmap9(iface); return IUnknown_AddRef(filter->renderer.filter.outer_unk); } static ULONG WINAPI mixer_bitmap9_Release(IVMRMixerBitmap9 *iface) { struct quartz_vmr *filter = impl_from_IVMRMixerBitmap9(iface); return IUnknown_Release(filter->renderer.filter.outer_unk); } static HRESULT WINAPI mixer_bitmap9_SetAlphaBitmap(IVMRMixerBitmap9 *iface, const VMR9AlphaBitmap *bitmap) { FIXME("iface %p, bitmap %p, stub!\n", iface, bitmap); TRACE("dwFlags %#x, hdc %p, pDDS %p, rSrc %s, rDest %s, fAlpha %.8e, clrSrcKey #%06x, dwFilterMode %#x.\n", bitmap->dwFlags, bitmap->hdc, bitmap->pDDS, wine_dbgstr_rect(&bitmap->rSrc), debugstr_normalized_rect(&bitmap->rDest), bitmap->fAlpha, bitmap->clrSrcKey, bitmap->dwFilterMode); return E_NOTIMPL; } static HRESULT WINAPI mixer_bitmap9_UpdateAlphaBitmapParameters(IVMRMixerBitmap9 *iface, const VMR9AlphaBitmap *bitmap) { FIXME("iface %p, bitmap %p, stub!\n", iface, bitmap); return E_NOTIMPL; } static HRESULT WINAPI mixer_bitmap9_GetAlphaBitmapParameters(IVMRMixerBitmap9 *iface, VMR9AlphaBitmap *bitmap) { FIXME("iface %p, bitmap %p, stub!\n", iface, bitmap); return E_NOTIMPL; } static const IVMRMixerBitmap9Vtbl mixer_bitmap9_vtbl = { mixer_bitmap9_QueryInterface, mixer_bitmap9_AddRef, mixer_bitmap9_Release, mixer_bitmap9_SetAlphaBitmap, mixer_bitmap9_UpdateAlphaBitmapParameters, mixer_bitmap9_GetAlphaBitmapParameters, }; static inline struct quartz_vmr *impl_from_IOverlay(IOverlay *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IOverlay_iface); } static HRESULT WINAPI overlay_QueryInterface(IOverlay *iface, REFIID iid, void **out) { struct quartz_vmr *filter = impl_from_IOverlay(iface); return IPin_QueryInterface(&filter->renderer.sink.pin.IPin_iface, iid, out); } static ULONG WINAPI overlay_AddRef(IOverlay *iface) { struct quartz_vmr *filter = impl_from_IOverlay(iface); return IPin_AddRef(&filter->renderer.sink.pin.IPin_iface); } static ULONG WINAPI overlay_Release(IOverlay *iface) { struct quartz_vmr *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 %u, 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 quartz_vmr *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 %#x, 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, }; static HRESULT vmr_create(IUnknown *outer, IUnknown **out, const CLSID *clsid) { struct quartz_vmr *object; HRESULT hr; if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; object->hD3d9 = LoadLibraryA("d3d9.dll"); if (!object->hD3d9) { WARN("Could not load d3d9.dll\n"); free(object); return VFW_E_DDRAW_CAPS_NOT_SUITABLE; } strmbase_renderer_init(&object->renderer, outer, clsid, L"VMR Input0", &renderer_ops); object->IAMCertifiedOutputProtection_iface.lpVtbl = &IAMCertifiedOutputProtection_Vtbl; object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl; object->IVMRFilterConfig_iface.lpVtbl = &VMR7_FilterConfig_Vtbl; object->IVMRFilterConfig9_iface.lpVtbl = &VMR9_FilterConfig_Vtbl; object->IVMRMixerBitmap9_iface.lpVtbl = &mixer_bitmap9_vtbl; object->IVMRMixerControl9_iface.lpVtbl = &mixer_control9_vtbl; object->IVMRMonitorConfig_iface.lpVtbl = &VMR7_MonitorConfig_Vtbl; object->IVMRMonitorConfig9_iface.lpVtbl = &VMR9_MonitorConfig_Vtbl; object->IVMRSurfaceAllocatorNotify_iface.lpVtbl = &VMR7_SurfaceAllocatorNotify_Vtbl; object->IVMRSurfaceAllocatorNotify9_iface.lpVtbl = &VMR9_SurfaceAllocatorNotify_Vtbl; object->IVMRWindowlessControl_iface.lpVtbl = &VMR7_WindowlessControl_Vtbl; object->IVMRWindowlessControl9_iface.lpVtbl = &VMR9_WindowlessControl_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); FreeLibrary(object->hD3d9); free(object); return hr; } object->run_event = CreateEventW(NULL, TRUE, FALSE, NULL); 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; } HRESULT vmr7_create(IUnknown *outer, IUnknown **out) { return vmr_create(outer, out, &CLSID_VideoMixingRenderer); } HRESULT vmr9_create(IUnknown *outer, IUnknown **out) { return vmr_create(outer, out, &CLSID_VideoMixingRenderer9); } static HRESULT WINAPI VMR9_ImagePresenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID riid, void **ppv) { struct default_presenter *This = impl_from_IVMRImagePresenter9(iface); TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); *ppv = NULL; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IVMRImagePresenter9)) *ppv = &This->IVMRImagePresenter9_iface; else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocator9)) *ppv = &This->IVMRSurfaceAllocator9_iface; if (*ppv) { IUnknown_AddRef((IUnknown *)(*ppv)); return S_OK; } FIXME("No interface for %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } static ULONG WINAPI VMR9_ImagePresenter_AddRef(IVMRImagePresenter9 *iface) { struct default_presenter *This = impl_from_IVMRImagePresenter9(iface); ULONG refCount = InterlockedIncrement(&This->refCount); TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); return refCount; } static ULONG WINAPI VMR9_ImagePresenter_Release(IVMRImagePresenter9 *iface) { struct default_presenter *This = impl_from_IVMRImagePresenter9(iface); ULONG refCount = InterlockedDecrement(&This->refCount); TRACE("(%p)->() Release from %d\n", iface, refCount + 1); if (!refCount) { DWORD i; TRACE("Destroying\n"); IDirect3D9_Release(This->d3d9_ptr); TRACE("Number of surfaces: %u\n", This->num_surfaces); for (i = 0; i < This->num_surfaces; ++i) { IDirect3DSurface9 *surface = This->d3d9_surfaces[i]; TRACE("Releasing surface %p\n", surface); if (surface) IDirect3DSurface9_Release(surface); } free(This->d3d9_surfaces); This->d3d9_surfaces = NULL; This->num_surfaces = 0; free(This); 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); const struct quartz_vmr *filter = presenter->pVMR9; IDirect3DDevice9 *device = presenter->d3d9_dev; 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); /* This 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 %#x.\n", hr); if (FAILED(hr = IDirect3DDevice9_BeginScene(device))) ERR("Failed to begin scene, hr %#x.\n", hr); if (FAILED(hr = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer))) { ERR("Failed to get backbuffer, hr %#x.\n", hr); return hr; } if (FAILED(hr = IDirect3DDevice9_StretchRect(device, info->lpSurf, NULL, backbuffer, NULL, D3DTEXF_POINT))) ERR("Failed to blit image, hr %#x.\n", hr); IDirect3DSurface9_Release(backbuffer); if (FAILED(hr = IDirect3DDevice9_EndScene(device))) ERR("Failed to end scene, hr %#x.\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 %#x.\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 HRESULT VMR9_SurfaceAllocator_SetAllocationSettings(struct default_presenter *This, VMR9AllocationInfo *allocinfo) { D3DCAPS9 caps; UINT width, height; HRESULT hr; if (!(allocinfo->dwFlags & VMR9AllocFlag_TextureSurface)) /* Only needed for texture surfaces */ return S_OK; hr = IDirect3DDevice9_GetDeviceCaps(This->d3d9_dev, &caps); if (FAILED(hr)) return hr; if (!(caps.TextureCaps & D3DPTEXTURECAPS_POW2) || (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)) { width = allocinfo->dwWidth; height = allocinfo->dwHeight; } else { width = height = 1; while (width < allocinfo->dwWidth) width *= 2; while (height < allocinfo->dwHeight) height *= 2; FIXME("NPOW2 support missing, not using proper surfaces!\n"); } if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) { if (height > width) width = height; else height = width; FIXME("Square texture support required..\n"); } allocinfo->dwHeight = height; allocinfo->dwWidth = width; return hr; } static UINT d3d9_adapter_from_hwnd(IDirect3D9 *d3d9, HWND hwnd, HMONITOR *mon_out) { UINT d3d9_adapter; HMONITOR mon; mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); if (!mon) d3d9_adapter = 0; else { for (d3d9_adapter = 0; d3d9_adapter < IDirect3D9_GetAdapterCount(d3d9); ++d3d9_adapter) { if (mon == IDirect3D9_GetAdapterMonitor(d3d9, d3d9_adapter)) break; } if (d3d9_adapter >= IDirect3D9_GetAdapterCount(d3d9)) d3d9_adapter = 0; } if (mon_out) *mon_out = mon; return d3d9_adapter; } static HRESULT WINAPI VMR9_SurfaceAllocator_InitializeDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *numbuffers) { struct default_presenter *This = impl_from_IVMRSurfaceAllocator9(iface); D3DPRESENT_PARAMETERS d3dpp; IDirect3DDevice9 *device; DWORD d3d9_adapter; D3DCAPS9 caps; HWND window; HRESULT hr; TRACE("presenter %p, cookie %#Ix, info %p, numbuffers %p.\n", This, cookie, info, numbuffers); This->info = *info; if (This->pVMR9->mode == VMR9Mode_Windowed) window = This->pVMR9->window.hwnd; else window = This->pVMR9->clipping_window; /* Obtain a monitor and d3d9 device */ d3d9_adapter = d3d9_adapter_from_hwnd(This->d3d9_ptr, window, &This->hMon); /* Now try to create the d3d9 device */ ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.hDeviceWindow = window; d3dpp.SwapEffect = D3DSWAPEFFECT_COPY; d3dpp.BackBufferWidth = info->dwWidth; d3dpp.BackBufferHeight = info->dwHeight; hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device); if (FAILED(hr)) { ERR("Could not create device: %08x\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; } This->d3d9_dev = device; IVMRSurfaceAllocatorNotify9_SetD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon); if (!(This->d3d9_surfaces = calloc(*numbuffers, sizeof(IDirect3DSurface9 *)))) return E_OUTOFMEMORY; hr = VMR9_SurfaceAllocator_SetAllocationSettings(This, info); if (FAILED(hr)) ERR("Setting allocation settings failed: %08x\n", hr); if (SUCCEEDED(hr)) { hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, info, numbuffers, This->d3d9_surfaces); if (FAILED(hr)) ERR("Allocating surfaces failed: %08x\n", hr); } if (FAILED(hr)) { IVMRSurfaceAllocator9_TerminateDevice(This->pVMR9->allocator, This->pVMR9->cookie); return hr; } This->num_surfaces = *numbuffers; return S_OK; } static HRESULT WINAPI VMR9_SurfaceAllocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie) { TRACE("iface %p, cookie %#lx.\n", iface, cookie); return S_OK; } static HRESULT WINAPI VMR9_SurfaceAllocator_GetSurface(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie, DWORD surfaceindex, DWORD flags, IDirect3DSurface9 **surface) { struct default_presenter *This = impl_from_IVMRSurfaceAllocator9(iface); /* Update everything first, this is needed because the surface might be destroyed in the reset */ if (!This->d3d9_dev) { TRACE("Device has left me!\n"); return E_FAIL; } if (surfaceindex >= This->num_surfaces) { ERR("surfaceindex is greater than num_surfaces\n"); return E_FAIL; } *surface = This->d3d9_surfaces[surfaceindex]; IDirect3DSurface9_AddRef(*surface); return S_OK; } static HRESULT WINAPI VMR9_SurfaceAllocator_AdviseNotify(IVMRSurfaceAllocator9 *iface, IVMRSurfaceAllocatorNotify9 *notify) { struct default_presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface); TRACE("presenter %p, notify %p.\n", presenter, notify); /* No AddRef taken here or the base VMR9 filter would never be destroyed */ presenter->SurfaceAllocatorNotify = notify; 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 SDKVersion); d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9"); if (!d3d9_create) return NULL; return d3d9_create(D3D_SDK_VERSION); } static HRESULT VMR9DefaultAllocatorPresenterImpl_create(struct quartz_vmr *parent, LPVOID * ppv) { struct default_presenter *object; HRESULT hr = S_OK; int i; if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; object->d3d9_ptr = init_d3d9(parent->hD3d9); if (!object->d3d9_ptr) { WARN("Could not initialize d3d9.dll\n"); free(object); return VFW_E_DDRAW_CAPS_NOT_SUITABLE; } i = 0; do { D3DDISPLAYMODE mode; hr = IDirect3D9_EnumAdapterModes(object->d3d9_ptr, i++, D3DFMT_X8R8G8B8, 0, &mode); if (hr == D3DERR_INVALIDCALL) break; /* out of adapters */ } while (FAILED(hr)); if (FAILED(hr)) ERR("HR: %08x\n", hr); if (hr == D3DERR_NOTAVAILABLE) { ERR("Format not supported\n"); IDirect3D9_Release(object->d3d9_ptr); 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->pVMR9 = parent; TRACE("Created default presenter %p.\n", object); *ppv = &object->IVMRImagePresenter9_iface; return S_OK; }