conhost: Fix ctrl-c handling.
[wine.git] / dlls / quartz / videorenderer.c
blobf725a9998cebde629844481a41f2c5007ad2b28b
1 /*
2 * Video Renderer (Fullscreen and Windowed using Direct Draw)
4 * Copyright 2004 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "quartz_private.h"
23 #include "uuids.h"
24 #include "vfwmsgs.h"
25 #include "amvideo.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "dshow.h"
29 #include "evcode.h"
30 #include "strmif.h"
31 #include "ddraw.h"
32 #include "dvdmedia.h"
34 #include <assert.h>
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
39 struct video_renderer
41 struct strmbase_renderer renderer;
42 struct video_window window;
44 IOverlay IOverlay_iface;
46 LONG VideoWidth;
47 LONG VideoHeight;
48 LONG FullScreenMode;
50 DWORD saved_style;
53 static inline struct video_renderer *impl_from_video_window(struct video_window *iface)
55 return CONTAINING_RECORD(iface, struct video_renderer, window);
58 static inline struct video_renderer *impl_from_strmbase_renderer(struct strmbase_renderer *iface)
60 return CONTAINING_RECORD(iface, struct video_renderer, renderer);
63 static inline struct video_renderer *impl_from_IVideoWindow(IVideoWindow *iface)
65 return CONTAINING_RECORD(iface, struct video_renderer, window.IVideoWindow_iface);
68 static const BITMAPINFOHEADER *get_bitmap_header(const AM_MEDIA_TYPE *mt)
70 if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
71 return &((VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader;
72 else
73 return &((VIDEOINFOHEADER2 *)mt->pbFormat)->bmiHeader;
76 static void VideoRenderer_AutoShowWindow(struct video_renderer *This)
78 if (This->window.AutoShow)
79 ShowWindow(This->window.hwnd, SW_SHOW);
82 static HRESULT video_renderer_render(struct strmbase_renderer *iface, IMediaSample *pSample)
84 struct video_renderer *filter = impl_from_strmbase_renderer(iface);
85 RECT src = filter->window.src, dst = filter->window.dst;
86 LPBYTE pbSrcStream = NULL;
87 HRESULT hr;
88 HDC dc;
90 TRACE("filter %p, sample %p.\n", filter, pSample);
92 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
93 if (FAILED(hr))
95 ERR("Failed to get buffer pointer, hr %#lx.\n", hr);
96 return hr;
99 dc = GetDC(filter->window.hwnd);
100 StretchDIBits(dc, dst.left, dst.top, dst.right - dst.left, dst.bottom - dst.top,
101 src.left, src.top, src.right - src.left, src.bottom - src.top, pbSrcStream,
102 (BITMAPINFO *)get_bitmap_header(&filter->renderer.sink.pin.mt), DIB_RGB_COLORS, SRCCOPY);
103 ReleaseDC(filter->window.hwnd, dc);
105 return S_OK;
108 static HRESULT video_renderer_query_accept(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt)
110 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video))
111 return S_FALSE;
113 if (!IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB32)
114 && !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB24)
115 && !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB565)
116 && !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8))
117 return S_FALSE;
119 if (!IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)
120 && !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo2))
121 return S_FALSE;
123 return S_OK;
126 static void video_renderer_destroy(struct strmbase_renderer *iface)
128 struct video_renderer *filter = impl_from_strmbase_renderer(iface);
130 video_window_cleanup(&filter->window);
131 strmbase_renderer_cleanup(&filter->renderer);
132 free(filter);
135 static HRESULT video_renderer_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out)
137 struct video_renderer *filter = impl_from_strmbase_renderer(iface);
139 if (IsEqualGUID(iid, &IID_IBasicVideo))
140 *out = &filter->window.IBasicVideo_iface;
141 else if (IsEqualGUID(iid, &IID_IVideoWindow))
142 *out = &filter->window.IVideoWindow_iface;
143 else
144 return E_NOINTERFACE;
146 IUnknown_AddRef((IUnknown *)*out);
147 return S_OK;
150 static HRESULT video_renderer_pin_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out)
152 struct video_renderer *filter = impl_from_strmbase_renderer(iface);
154 if (IsEqualGUID(iid, &IID_IOverlay))
155 *out = &filter->IOverlay_iface;
156 else
157 return E_NOINTERFACE;
159 IUnknown_AddRef((IUnknown *)*out);
160 return S_OK;
163 static void video_renderer_stop_stream(struct strmbase_renderer *iface)
165 struct video_renderer *This = impl_from_strmbase_renderer(iface);
167 TRACE("(%p)->()\n", This);
169 if (This->window.AutoShow)
170 /* Black it out */
171 RedrawWindow(This->window.hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
174 static void video_renderer_init_stream(struct strmbase_renderer *iface)
176 struct video_renderer *filter = impl_from_strmbase_renderer(iface);
178 VideoRenderer_AutoShowWindow(filter);
181 static HRESULT video_renderer_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt)
183 struct video_renderer *filter = impl_from_strmbase_renderer(iface);
184 const BITMAPINFOHEADER *bitmap_header = get_bitmap_header(mt);
185 HWND window = filter->window.hwnd;
186 RECT rect;
188 filter->VideoWidth = bitmap_header->biWidth;
189 filter->VideoHeight = abs(bitmap_header->biHeight);
190 SetRect(&rect, 0, 0, filter->VideoWidth, filter->VideoHeight);
191 filter->window.src = rect;
193 AdjustWindowRectEx(&rect, GetWindowLongW(window, GWL_STYLE), FALSE,
194 GetWindowLongW(window, GWL_EXSTYLE));
195 SetWindowPos(window, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
196 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
197 GetClientRect(window, &filter->window.dst);
199 return S_OK;
202 static RECT video_renderer_get_default_rect(struct video_window *iface)
204 struct video_renderer *This = impl_from_video_window(iface);
205 static RECT defRect;
207 SetRect(&defRect, 0, 0, This->VideoWidth, This->VideoHeight);
209 return defRect;
212 static const struct strmbase_renderer_ops renderer_ops =
214 .renderer_query_accept = video_renderer_query_accept,
215 .renderer_render = video_renderer_render,
216 .renderer_init_stream = video_renderer_init_stream,
217 .renderer_stop_stream = video_renderer_stop_stream,
218 .renderer_destroy = video_renderer_destroy,
219 .renderer_query_interface = video_renderer_query_interface,
220 .renderer_pin_query_interface = video_renderer_pin_query_interface,
221 .renderer_connect = video_renderer_connect,
224 static HRESULT video_renderer_get_current_image(struct video_window *iface, LONG *size, LONG *image)
226 struct video_renderer *filter = impl_from_video_window(iface);
227 const BITMAPINFOHEADER *bih;
228 size_t image_size;
229 BYTE *sample_data;
231 EnterCriticalSection(&filter->renderer.filter.stream_cs);
233 bih = get_bitmap_header(&filter->renderer.sink.pin.mt);
234 image_size = bih->biWidth * bih->biHeight * bih->biBitCount / 8;
236 if (!image)
238 LeaveCriticalSection(&filter->renderer.filter.stream_cs);
239 *size = sizeof(BITMAPINFOHEADER) + image_size;
240 return S_OK;
243 if (filter->renderer.filter.state != State_Paused)
245 LeaveCriticalSection(&filter->renderer.filter.stream_cs);
246 return VFW_E_NOT_PAUSED;
249 if (!filter->renderer.current_sample)
251 LeaveCriticalSection(&filter->renderer.filter.stream_cs);
252 return E_UNEXPECTED;
255 if (*size < sizeof(BITMAPINFOHEADER) + image_size)
257 LeaveCriticalSection(&filter->renderer.filter.stream_cs);
258 return E_OUTOFMEMORY;
261 memcpy(image, bih, sizeof(BITMAPINFOHEADER));
262 IMediaSample_GetPointer(filter->renderer.current_sample, &sample_data);
263 memcpy((char *)image + sizeof(BITMAPINFOHEADER), sample_data, image_size);
265 LeaveCriticalSection(&filter->renderer.filter.stream_cs);
266 return S_OK;
269 static const struct video_window_ops window_ops =
271 .get_default_rect = video_renderer_get_default_rect,
272 .get_current_image = video_renderer_get_current_image,
275 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
276 LONG *FullScreenMode)
278 struct video_renderer *This = impl_from_IVideoWindow(iface);
280 TRACE("window %p, fullscreen %p.\n", This, FullScreenMode);
282 if (!FullScreenMode)
283 return E_POINTER;
285 *FullScreenMode = This->FullScreenMode;
287 return S_OK;
290 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, LONG fullscreen)
292 struct video_renderer *filter = impl_from_IVideoWindow(iface);
293 HWND window = filter->window.hwnd;
295 FIXME("filter %p, fullscreen %ld.\n", filter, fullscreen);
297 if (fullscreen)
299 filter->saved_style = GetWindowLongW(window, GWL_STYLE);
300 ShowWindow(window, SW_HIDE);
301 SetParent(window, NULL);
302 SetWindowLongW(window, GWL_STYLE, WS_POPUP);
303 SetWindowPos(window, HWND_TOP, 0, 0,
304 GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW);
305 GetWindowRect(window, &filter->window.dst);
307 else
309 ShowWindow(window, SW_HIDE);
310 SetParent(window, filter->window.hwndOwner);
311 SetWindowLongW(window, GWL_STYLE, filter->saved_style);
312 GetClientRect(window, &filter->window.dst);
313 SetWindowPos(window, 0, filter->window.dst.left, filter->window.dst.top,
314 filter->window.dst.right, filter->window.dst.bottom, SWP_NOZORDER | SWP_SHOWWINDOW);
316 filter->FullScreenMode = fullscreen;
318 return S_OK;
321 static const IVideoWindowVtbl IVideoWindow_VTable =
323 BaseControlWindowImpl_QueryInterface,
324 BaseControlWindowImpl_AddRef,
325 BaseControlWindowImpl_Release,
326 BaseControlWindowImpl_GetTypeInfoCount,
327 BaseControlWindowImpl_GetTypeInfo,
328 BaseControlWindowImpl_GetIDsOfNames,
329 BaseControlWindowImpl_Invoke,
330 BaseControlWindowImpl_put_Caption,
331 BaseControlWindowImpl_get_Caption,
332 BaseControlWindowImpl_put_WindowStyle,
333 BaseControlWindowImpl_get_WindowStyle,
334 BaseControlWindowImpl_put_WindowStyleEx,
335 BaseControlWindowImpl_get_WindowStyleEx,
336 BaseControlWindowImpl_put_AutoShow,
337 BaseControlWindowImpl_get_AutoShow,
338 BaseControlWindowImpl_put_WindowState,
339 BaseControlWindowImpl_get_WindowState,
340 BaseControlWindowImpl_put_BackgroundPalette,
341 BaseControlWindowImpl_get_BackgroundPalette,
342 BaseControlWindowImpl_put_Visible,
343 BaseControlWindowImpl_get_Visible,
344 BaseControlWindowImpl_put_Left,
345 BaseControlWindowImpl_get_Left,
346 BaseControlWindowImpl_put_Width,
347 BaseControlWindowImpl_get_Width,
348 BaseControlWindowImpl_put_Top,
349 BaseControlWindowImpl_get_Top,
350 BaseControlWindowImpl_put_Height,
351 BaseControlWindowImpl_get_Height,
352 BaseControlWindowImpl_put_Owner,
353 BaseControlWindowImpl_get_Owner,
354 BaseControlWindowImpl_put_MessageDrain,
355 BaseControlWindowImpl_get_MessageDrain,
356 BaseControlWindowImpl_get_BorderColor,
357 BaseControlWindowImpl_put_BorderColor,
358 VideoWindow_get_FullScreenMode,
359 VideoWindow_put_FullScreenMode,
360 BaseControlWindowImpl_SetWindowForeground,
361 BaseControlWindowImpl_NotifyOwnerMessage,
362 BaseControlWindowImpl_SetWindowPosition,
363 BaseControlWindowImpl_GetWindowPosition,
364 BaseControlWindowImpl_GetMinIdealImageSize,
365 BaseControlWindowImpl_GetMaxIdealImageSize,
366 BaseControlWindowImpl_GetRestorePosition,
367 BaseControlWindowImpl_HideCursor,
368 BaseControlWindowImpl_IsCursorHidden
371 static inline struct video_renderer *impl_from_IOverlay(IOverlay *iface)
373 return CONTAINING_RECORD(iface, struct video_renderer, IOverlay_iface);
376 static HRESULT WINAPI overlay_QueryInterface(IOverlay *iface, REFIID iid, void **out)
378 struct video_renderer *filter = impl_from_IOverlay(iface);
379 return IPin_QueryInterface(&filter->renderer.sink.pin.IPin_iface, iid, out);
382 static ULONG WINAPI overlay_AddRef(IOverlay *iface)
384 struct video_renderer *filter = impl_from_IOverlay(iface);
385 return IPin_AddRef(&filter->renderer.sink.pin.IPin_iface);
388 static ULONG WINAPI overlay_Release(IOverlay *iface)
390 struct video_renderer *filter = impl_from_IOverlay(iface);
391 return IPin_Release(&filter->renderer.sink.pin.IPin_iface);
394 static HRESULT WINAPI overlay_GetPalette(IOverlay *iface, DWORD *count, PALETTEENTRY **palette)
396 FIXME("iface %p, count %p, palette %p, stub!\n", iface, count, palette);
397 return E_NOTIMPL;
400 static HRESULT WINAPI overlay_SetPalette(IOverlay *iface, DWORD count, PALETTEENTRY *palette)
402 FIXME("iface %p, count %lu, palette %p, stub!\n", iface, count, palette);
403 return E_NOTIMPL;
406 static HRESULT WINAPI overlay_GetDefaultColorKey(IOverlay *iface, COLORKEY *key)
408 FIXME("iface %p, key %p, stub!\n", iface, key);
409 return E_NOTIMPL;
412 static HRESULT WINAPI overlay_GetColorKey(IOverlay *iface, COLORKEY *key)
414 FIXME("iface %p, key %p, stub!\n", iface, key);
415 return E_NOTIMPL;
418 static HRESULT WINAPI overlay_SetColorKey(IOverlay *iface, COLORKEY *key)
420 FIXME("iface %p, key %p, stub!\n", iface, key);
421 return E_NOTIMPL;
424 static HRESULT WINAPI overlay_GetWindowHandle(IOverlay *iface, HWND *window)
426 struct video_renderer *filter = impl_from_IOverlay(iface);
428 TRACE("filter %p, window %p.\n", filter, window);
430 *window = filter->window.hwnd;
431 return S_OK;
434 static HRESULT WINAPI overlay_GetClipList(IOverlay *iface, RECT *source, RECT *dest, RGNDATA **region)
436 FIXME("iface %p, source %p, dest %p, region %p, stub!\n", iface, source, dest, region);
437 return E_NOTIMPL;
440 static HRESULT WINAPI overlay_GetVideoPosition(IOverlay *iface, RECT *source, RECT *dest)
442 FIXME("iface %p, source %p, dest %p, stub!\n", iface, source, dest);
443 return E_NOTIMPL;
446 static HRESULT WINAPI overlay_Advise(IOverlay *iface, IOverlayNotify *sink, DWORD flags)
448 FIXME("iface %p, sink %p, flags %#lx, stub!\n", iface, sink, flags);
449 return E_NOTIMPL;
452 static HRESULT WINAPI overlay_Unadvise(IOverlay *iface)
454 FIXME("iface %p, stub!\n", iface);
455 return E_NOTIMPL;
458 static const IOverlayVtbl overlay_vtbl =
460 overlay_QueryInterface,
461 overlay_AddRef,
462 overlay_Release,
463 overlay_GetPalette,
464 overlay_SetPalette,
465 overlay_GetDefaultColorKey,
466 overlay_GetColorKey,
467 overlay_SetColorKey,
468 overlay_GetWindowHandle,
469 overlay_GetClipList,
470 overlay_GetVideoPosition,
471 overlay_Advise,
472 overlay_Unadvise,
475 HRESULT video_renderer_create(IUnknown *outer, IUnknown **out)
477 struct video_renderer *object;
478 HRESULT hr;
480 if (!(object = calloc(1, sizeof(*object))))
481 return E_OUTOFMEMORY;
483 strmbase_renderer_init(&object->renderer, outer, &CLSID_VideoRenderer, L"In", &renderer_ops);
484 wcscpy(object->renderer.sink.pin.name, L"Input");
486 object->IOverlay_iface.lpVtbl = &overlay_vtbl;
488 video_window_init(&object->window, &IVideoWindow_VTable,
489 &object->renderer.filter, &object->renderer.sink.pin, &window_ops);
491 if (FAILED(hr = video_window_create_window(&object->window)))
493 video_window_cleanup(&object->window);
494 strmbase_renderer_cleanup(&object->renderer);
495 free(object);
496 return hr;
499 TRACE("Created video renderer %p.\n", object);
500 *out = &object->renderer.filter.IUnknown_inner;
501 return S_OK;
504 HRESULT video_renderer_default_create(IUnknown *outer, IUnknown **out)
506 HRESULT hr;
508 if (SUCCEEDED(hr = vmr7_create(outer, out)))
509 return hr;
511 return video_renderer_create(outer, out);