evr/presenter: Add IMFQualityAdviseLimits stub.
[wine.git] / dlls / evr / presenter.c
blob4614fa5eed254b5e3b158b47d70635c0d67c6b08
1 /*
2 * Copyright 2020 Nikolay Sivov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "evr.h"
22 #include "d3d9.h"
23 #include "mfapi.h"
24 #include "mferror.h"
25 #include "dxva2api.h"
27 #include "evr_classes.h"
28 #include "evr_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(evr);
34 enum presenter_state
36 PRESENTER_STATE_SHUT_DOWN = 0,
37 PRESENTER_STATE_STARTED,
38 PRESENTER_STATE_STOPPED,
39 PRESENTER_STATE_PAUSED,
42 enum presenter_flags
44 PRESENTER_MIXER_HAS_INPUT = 0x1,
47 enum streaming_thread_message
49 EVRM_STOP = WM_USER,
50 EVRM_PRESENT = WM_USER + 1,
51 EVRM_PROCESS_INPUT = WM_USER + 2,
54 struct sample_queue
56 IMFSample **samples;
57 unsigned int size;
58 unsigned int used;
59 unsigned int front;
60 unsigned int back;
63 struct streaming_thread
65 HANDLE hthread;
66 HANDLE ready_event;
67 DWORD tid;
68 struct sample_queue queue;
71 struct video_presenter
73 IMFVideoPresenter IMFVideoPresenter_iface;
74 IMFVideoDeviceID IMFVideoDeviceID_iface;
75 IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
76 IMFVideoDisplayControl IMFVideoDisplayControl_iface;
77 IMFRateSupport IMFRateSupport_iface;
78 IMFGetService IMFGetService_iface;
79 IMFVideoPositionMapper IMFVideoPositionMapper_iface;
80 IQualProp IQualProp_iface;
81 IMFQualityAdvise IMFQualityAdvise_iface;
82 IMFQualityAdviseLimits IMFQualityAdviseLimits_iface;
83 IDirect3DDeviceManager9 IDirect3DDeviceManager9_iface;
84 IMFVideoSampleAllocatorNotify allocator_cb;
85 IUnknown IUnknown_inner;
86 IUnknown *outer_unk;
87 LONG refcount;
89 IMFTransform *mixer;
90 IMFClock *clock;
91 IMediaEventSink *event_sink;
93 IDirect3DDeviceManager9 *device_manager;
94 IDirect3DSwapChain9 *swapchain;
95 HANDLE hdevice;
97 IMFVideoSampleAllocator *allocator;
98 struct streaming_thread thread;
99 unsigned int allocator_capacity;
100 IMFMediaType *media_type;
101 LONGLONG frame_time_threshold;
102 UINT reset_token;
103 HWND video_window;
104 MFVideoNormalizedRect src_rect;
105 RECT dst_rect;
106 DWORD rendering_prefs;
107 SIZE native_size;
108 SIZE native_ratio;
109 unsigned int ar_mode;
110 unsigned int state;
111 unsigned int flags;
112 CRITICAL_SECTION cs;
115 static struct video_presenter *impl_from_IUnknown(IUnknown *iface)
117 return CONTAINING_RECORD(iface, struct video_presenter, IUnknown_inner);
120 static struct video_presenter *impl_from_IMFVideoPresenter(IMFVideoPresenter *iface)
122 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPresenter_iface);
125 static struct video_presenter *impl_from_IMFVideoDeviceID(IMFVideoDeviceID *iface)
127 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoDeviceID_iface);
130 static struct video_presenter *impl_from_IMFTopologyServiceLookupClient(IMFTopologyServiceLookupClient *iface)
132 return CONTAINING_RECORD(iface, struct video_presenter, IMFTopologyServiceLookupClient_iface);
135 static struct video_presenter *impl_from_IMFVideoDisplayControl(IMFVideoDisplayControl *iface)
137 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoDisplayControl_iface);
140 static struct video_presenter *impl_from_IMFRateSupport(IMFRateSupport *iface)
142 return CONTAINING_RECORD(iface, struct video_presenter, IMFRateSupport_iface);
145 static struct video_presenter *impl_from_IMFGetService(IMFGetService *iface)
147 return CONTAINING_RECORD(iface, struct video_presenter, IMFGetService_iface);
150 static struct video_presenter *impl_from_IMFVideoPositionMapper(IMFVideoPositionMapper *iface)
152 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPositionMapper_iface);
155 static struct video_presenter *impl_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
157 return CONTAINING_RECORD(iface, struct video_presenter, allocator_cb);
160 static struct video_presenter *impl_from_IQualProp(IQualProp *iface)
162 return CONTAINING_RECORD(iface, struct video_presenter, IQualProp_iface);
165 static struct video_presenter *impl_from_IMFQualityAdvise(IMFQualityAdvise *iface)
167 return CONTAINING_RECORD(iface, struct video_presenter, IMFQualityAdvise_iface);
170 static struct video_presenter *impl_from_IMFQualityAdviseLimits(IMFQualityAdviseLimits *iface)
172 return CONTAINING_RECORD(iface, struct video_presenter, IMFQualityAdviseLimits_iface);
175 static struct video_presenter *impl_from_IDirect3DDeviceManager9(IDirect3DDeviceManager9 *iface)
177 return CONTAINING_RECORD(iface, struct video_presenter, IDirect3DDeviceManager9_iface);
180 static void video_presenter_notify_renderer(struct video_presenter *presenter,
181 LONG event, LONG_PTR param1, LONG_PTR param2)
183 if (presenter->event_sink)
184 IMediaEventSink_Notify(presenter->event_sink, event, param1, param2);
187 static unsigned int get_gcd(unsigned int a, unsigned int b)
189 unsigned int m;
191 while (b)
193 m = a % b;
194 a = b;
195 b = m;
198 return a;
201 static HRESULT video_presenter_get_device(struct video_presenter *presenter, IDirect3DDevice9 **device)
203 HRESULT hr;
205 if (!presenter->hdevice)
207 if (FAILED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(presenter->device_manager, &presenter->hdevice)))
208 return hr;
211 return IDirect3DDeviceManager9_LockDevice(presenter->device_manager, presenter->hdevice, device, TRUE);
214 static void video_presenter_get_native_video_size(struct video_presenter *presenter)
216 IMFMediaType *media_type;
217 UINT64 frame_size = 0;
219 memset(&presenter->native_size, 0, sizeof(presenter->native_size));
220 memset(&presenter->native_ratio, 0, sizeof(presenter->native_ratio));
222 if (!presenter->mixer)
223 return;
225 if (FAILED(IMFTransform_GetInputCurrentType(presenter->mixer, 0, &media_type)))
226 return;
228 if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
230 unsigned int gcd;
232 presenter->native_size.cx = frame_size >> 32;
233 presenter->native_size.cy = frame_size;
235 if ((gcd = get_gcd(presenter->native_size.cx, presenter->native_size.cy)))
237 presenter->native_ratio.cx = presenter->native_size.cx / gcd;
238 presenter->native_ratio.cy = presenter->native_size.cy / gcd;
242 IMFMediaType_Release(media_type);
245 /* It is important this is called to reset callback too to break circular referencing,
246 when allocator keeps a reference of its container, that created it. */
247 static void video_presenter_set_allocator_callback(struct video_presenter *presenter,
248 IMFVideoSampleAllocatorNotify *notify_cb)
250 IMFVideoSampleAllocatorCallback *cb;
252 IMFVideoSampleAllocator_QueryInterface(presenter->allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&cb);
253 IMFVideoSampleAllocatorCallback_SetCallback(cb, notify_cb);
254 IMFVideoSampleAllocatorCallback_Release(cb);
257 static void video_presenter_reset_media_type(struct video_presenter *presenter)
259 if (presenter->media_type)
260 IMFMediaType_Release(presenter->media_type);
261 presenter->media_type = NULL;
263 IMFVideoSampleAllocator_UninitializeSampleAllocator(presenter->allocator);
264 video_presenter_set_allocator_callback(presenter, NULL);
267 static HRESULT video_presenter_set_media_type(struct video_presenter *presenter, IMFMediaType *media_type)
269 unsigned int flags;
270 HRESULT hr;
272 if (!media_type)
274 video_presenter_reset_media_type(presenter);
275 return S_OK;
278 if (presenter->media_type && IMFMediaType_IsEqual(presenter->media_type, media_type, &flags) == S_OK)
279 return S_OK;
281 video_presenter_reset_media_type(presenter);
283 if (SUCCEEDED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(presenter->allocator,
284 presenter->allocator_capacity, media_type)))
286 MFRatio ratio;
287 UINT64 rate, frametime;
289 presenter->media_type = media_type;
290 IMFMediaType_AddRef(presenter->media_type);
292 if (SUCCEEDED(IMFMediaType_GetUINT64(presenter->media_type, &MF_MT_FRAME_RATE, &rate)))
294 ratio.Denominator = rate;
295 ratio.Numerator = rate >> 32;
297 else
299 ratio.Denominator = 1;
300 ratio.Numerator = 30;
303 MFFrameRateToAverageTimePerFrame(ratio.Numerator, ratio.Denominator, &frametime);
304 presenter->frame_time_threshold = frametime / 4;
306 else
307 WARN("Failed to initialize sample allocator, hr %#x.\n", hr);
309 return hr;
312 static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter)
314 IMFMediaType *media_type, *candidate_type;
315 unsigned int idx = 0;
316 UINT64 frame_size;
317 MFVideoArea aperture;
318 RECT rect;
319 HRESULT hr;
321 if (FAILED(hr = MFCreateMediaType(&media_type)))
322 return hr;
324 video_presenter_get_native_video_size(presenter);
326 rect = presenter->dst_rect;
327 if (rect.left == 0 && rect.right == 0 && rect.bottom == 0 && rect.top == 0)
329 rect.right = presenter->native_size.cx;
330 rect.bottom = presenter->native_size.cy;
333 aperture.Area.cx = rect.right - rect.left;
334 aperture.Area.cy = rect.bottom - rect.top;
335 aperture.OffsetX.value = 0;
336 aperture.OffsetX.fract = 0;
337 aperture.OffsetY.value = 0;
338 aperture.OffsetY.fract = 0;
339 frame_size = (UINT64)aperture.Area.cx << 32 | aperture.Area.cy;
341 while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &candidate_type)))
343 /* FIXME: check that d3d device supports this format */
345 if (FAILED(hr = IMFMediaType_CopyAllItems(candidate_type, (IMFAttributes *)media_type)))
346 WARN("Failed to clone a media type, hr %#x.\n", hr);
347 IMFMediaType_Release(candidate_type);
349 IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, frame_size);
350 IMFMediaType_SetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture, sizeof(aperture));
352 hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
354 if (SUCCEEDED(hr))
355 hr = video_presenter_set_media_type(presenter, media_type);
357 if (SUCCEEDED(hr))
358 hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0);
360 if (SUCCEEDED(hr))
361 break;
364 IMFMediaType_Release(media_type);
366 return hr;
369 static void video_presenter_sample_queue_init(struct video_presenter *presenter)
371 struct sample_queue *queue = &presenter->thread.queue;
373 if (queue->size)
374 return;
376 memset(queue, 0, sizeof(*queue));
377 queue->samples = calloc(presenter->allocator_capacity, sizeof(*queue->samples));
378 queue->size = presenter->allocator_capacity;
379 queue->back = queue->size - 1;
382 static void video_presenter_sample_queue_push(struct video_presenter *presenter, IMFSample *sample)
384 struct sample_queue *queue = &presenter->thread.queue;
386 EnterCriticalSection(&presenter->cs);
387 if (queue->used != queue->size)
389 queue->back = (queue->back + 1) % queue->size;
390 queue->samples[queue->back] = sample;
391 queue->used++;
392 IMFSample_AddRef(sample);
394 LeaveCriticalSection(&presenter->cs);
397 static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, IMFSample **sample)
399 struct sample_queue *queue = &presenter->thread.queue;
401 EnterCriticalSection(&presenter->cs);
402 if (queue->used)
404 *sample = queue->samples[queue->front];
405 queue->front = (queue->front + 1) % queue->size;
406 queue->used--;
408 else
409 *sample = NULL;
410 LeaveCriticalSection(&presenter->cs);
412 return *sample != NULL;
415 static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface)
417 IMFMediaBuffer *buffer;
418 IMFGetService *gs;
419 HRESULT hr;
421 if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer)))
422 return hr;
424 hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&gs);
425 IMFMediaBuffer_Release(buffer);
426 if (FAILED(hr))
427 return hr;
429 hr = IMFGetService_GetService(gs, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)surface);
430 IMFGetService_Release(gs);
431 return hr;
434 static void scale_rect(RECT *rect, unsigned int width, unsigned int height, const MFVideoNormalizedRect *scale)
436 if (rect->left == 0.0f && rect->top == 0.0f && rect->right == 1.0f && rect->bottom == 1.0f)
438 SetRect(rect, 0, 0, width, height);
440 else
442 rect->left = width * scale->left;
443 rect->right = width * scale->right;
444 rect->top = height * scale->top;
445 rect->bottom = height * scale->bottom;
449 static void video_presenter_sample_present(struct video_presenter *presenter, IMFSample *sample)
451 IDirect3DSurface9 *surface, *backbuffer;
452 IDirect3DDevice9 *device;
453 D3DSURFACE_DESC desc;
454 RECT dst, src;
455 HRESULT hr;
457 if (!presenter->swapchain)
458 return;
460 if (FAILED(hr = video_presenter_get_sample_surface(sample, &surface)))
462 WARN("Failed to get sample surface, hr %#x.\n", hr);
463 return;
466 if (FAILED(hr = IDirect3DSwapChain9_GetBackBuffer(presenter->swapchain, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer)))
468 WARN("Failed to get a backbuffer, hr %#x.\n", hr);
469 IDirect3DSurface9_Release(surface);
470 return;
473 IDirect3DSwapChain9_GetDevice(presenter->swapchain, &device);
474 IDirect3DDevice9_StretchRect(device, surface, NULL, backbuffer, NULL, D3DTEXF_POINT);
476 IDirect3DSurface9_GetDesc(surface, &desc);
477 scale_rect(&src, desc.Width, desc.Height, &presenter->src_rect);
479 IDirect3DSurface9_GetDesc(backbuffer, &desc);
480 SetRect(&dst, 0, 0, desc.Width, desc.Height);
482 if (presenter->ar_mode & MFVideoARMode_PreservePicture)
484 unsigned int src_width = src.right - src.left, src_height = src.bottom - src.top;
485 unsigned int dst_width = dst.right - dst.left, dst_height = dst.bottom - dst.top;
487 if (src_width * dst_height > dst_width * src_height)
489 /* src is "wider" than dst. */
490 unsigned int dst_center = (dst.top + dst.bottom) / 2;
491 unsigned int scaled_height = src_height * dst_width / src_width;
493 dst.top = dst_center - scaled_height / 2;
494 dst.bottom = dst.top + scaled_height;
496 else if (src_width * dst_height < dst_width * src_height)
498 /* src is "taller" than dst. */
499 unsigned int dst_center = (dst.left + dst.right) / 2;
500 unsigned int scaled_width = src_width * dst_height / src_height;
502 dst.left = dst_center - scaled_width / 2;
503 dst.right = dst.left + scaled_width;
507 IDirect3DSwapChain9_Present(presenter->swapchain, &src, &dst, NULL, NULL, 0);
509 IDirect3DDevice9_Release(device);
510 IDirect3DSurface9_Release(backbuffer);
511 IDirect3DSurface9_Release(surface);
514 static void video_presenter_check_queue(struct video_presenter *presenter,
515 unsigned int *next_wait)
517 LONGLONG pts, clocktime, delta;
518 unsigned int wait = 0;
519 BOOL present = TRUE;
520 IMFSample *sample;
521 MFTIME systime;
522 HRESULT hr;
524 while (video_presenter_sample_queue_pop(presenter, &sample))
526 wait = 0;
528 if (presenter->clock)
530 pts = clocktime = 0;
532 hr = IMFSample_GetSampleTime(sample, &pts);
533 if (SUCCEEDED(hr))
534 hr = IMFClock_GetCorrelatedTime(presenter->clock, 0, &clocktime, &systime);
536 delta = pts - clocktime;
537 if (delta > 3 * presenter->frame_time_threshold)
539 /* Convert 100ns -> msec */
540 wait = (delta - 3 * presenter->frame_time_threshold) / 100000;
541 present = FALSE;
545 if (present)
546 video_presenter_sample_present(presenter, sample);
547 else
548 video_presenter_sample_queue_push(presenter, sample);
550 IMFSample_Release(sample);
552 if (wait > 0)
553 break;
556 if (!wait)
557 wait = INFINITE;
559 *next_wait = wait;
562 static void video_presenter_schedule_sample(struct video_presenter *presenter, IMFSample *sample)
564 if (!presenter->thread.tid)
566 WARN("Streaming thread hasn't been started.\n");
567 return;
570 if (presenter->clock)
572 video_presenter_sample_queue_push(presenter, sample);
573 PostThreadMessageW(presenter->thread.tid, EVRM_PRESENT, 0, 0);
575 else
577 video_presenter_sample_present(presenter, sample);
581 static HRESULT video_presenter_process_input(struct video_presenter *presenter)
583 MFT_OUTPUT_DATA_BUFFER buffer;
584 HRESULT hr = S_OK;
585 IMFSample *sample;
586 DWORD status;
588 if (!presenter->media_type)
589 return S_OK;
591 while (hr == S_OK)
593 LONGLONG mixing_started, mixing_finished;
594 MFTIME systime;
596 if (!(presenter->flags & PRESENTER_MIXER_HAS_INPUT))
597 break;
599 if (FAILED(hr = IMFVideoSampleAllocator_AllocateSample(presenter->allocator, &sample)))
601 WARN("Failed to allocate a sample, hr %#x.\n", hr);
602 break;
605 memset(&buffer, 0, sizeof(buffer));
606 buffer.pSample = sample;
608 if (presenter->clock)
609 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_started, &systime);
611 if (FAILED(hr = IMFTransform_ProcessOutput(presenter->mixer, 0, 1, &buffer, &status)))
613 /* FIXME: failure path probably needs to handle some errors specifically */
614 presenter->flags &= ~PRESENTER_MIXER_HAS_INPUT;
615 IMFSample_Release(sample);
616 break;
618 else
620 if (presenter->clock)
622 LONGLONG latency;
624 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_finished, &systime);
625 latency = mixing_finished - mixing_started;
626 video_presenter_notify_renderer(presenter, EC_PROCESSING_LATENCY, (LONG_PTR)&latency, 0);
629 if (buffer.pEvents)
630 IMFCollection_Release(buffer.pEvents);
632 video_presenter_schedule_sample(presenter, sample);
634 IMFSample_Release(sample);
638 return S_OK;
641 static DWORD CALLBACK video_presenter_streaming_thread(void *arg)
643 struct video_presenter *presenter = arg;
644 unsigned int wait = INFINITE;
645 BOOL stop_thread = FALSE;
646 MSG msg;
648 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
650 SetEvent(presenter->thread.ready_event);
652 while (!stop_thread)
654 if (MsgWaitForMultipleObjects(0, NULL, FALSE, wait, QS_POSTMESSAGE) == WAIT_TIMEOUT)
655 video_presenter_check_queue(presenter, &wait);
657 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
659 BOOL peek = TRUE;
661 switch (msg.message)
663 case EVRM_STOP:
664 stop_thread = TRUE;
665 break;
667 case EVRM_PRESENT:
668 if (peek)
670 video_presenter_check_queue(presenter, &wait);
671 peek = wait != INFINITE;
673 break;
675 case EVRM_PROCESS_INPUT:
676 EnterCriticalSection(&presenter->cs);
677 video_presenter_process_input(presenter);
678 LeaveCriticalSection(&presenter->cs);
679 break;
680 default:
686 return 0;
689 static HRESULT video_presenter_start_streaming(struct video_presenter *presenter)
691 if (presenter->thread.hthread)
692 return S_OK;
694 video_presenter_sample_queue_init(presenter);
696 if (!(presenter->thread.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
697 return HRESULT_FROM_WIN32(GetLastError());
699 if (!(presenter->thread.hthread = CreateThread(NULL, 0, video_presenter_streaming_thread,
700 presenter, 0, &presenter->thread.tid)))
702 WARN("Failed to create streaming thread.\n");
703 CloseHandle(presenter->thread.ready_event);
704 presenter->thread.ready_event = NULL;
705 return E_FAIL;
708 video_presenter_set_allocator_callback(presenter, &presenter->allocator_cb);
710 WaitForSingleObject(presenter->thread.ready_event, INFINITE);
711 CloseHandle(presenter->thread.ready_event);
712 presenter->thread.ready_event = NULL;
714 TRACE("Started streaming thread, tid %#x.\n", presenter->thread.tid);
716 return S_OK;
719 static HRESULT video_presenter_end_streaming(struct video_presenter *presenter)
721 if (!presenter->thread.hthread)
722 return S_OK;
724 PostThreadMessageW(presenter->thread.tid, EVRM_STOP, 0, 0);
726 WaitForSingleObject(presenter->thread.hthread, INFINITE);
727 CloseHandle(presenter->thread.hthread);
729 TRACE("Terminated streaming thread tid %#x.\n", presenter->thread.tid);
731 memset(&presenter->thread, 0, sizeof(presenter->thread));
732 video_presenter_set_allocator_callback(presenter, NULL);
734 return S_OK;
737 static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
739 struct video_presenter *presenter = impl_from_IUnknown(iface);
741 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
743 if (IsEqualIID(riid, &IID_IUnknown))
745 *obj = iface;
747 else if (IsEqualIID(riid, &IID_IMFClockStateSink)
748 || IsEqualIID(riid, &IID_IMFVideoPresenter))
750 *obj = &presenter->IMFVideoPresenter_iface;
752 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
754 *obj = &presenter->IMFVideoDeviceID_iface;
756 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
758 *obj = &presenter->IMFTopologyServiceLookupClient_iface;
760 else if (IsEqualIID(riid, &IID_IMFVideoDisplayControl))
762 *obj = &presenter->IMFVideoDisplayControl_iface;
764 else if (IsEqualIID(riid, &IID_IMFRateSupport))
766 *obj = &presenter->IMFRateSupport_iface;
768 else if (IsEqualIID(riid, &IID_IMFGetService))
770 *obj = &presenter->IMFGetService_iface;
772 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
774 *obj = &presenter->IMFVideoPositionMapper_iface;
776 else if (IsEqualIID(riid, &IID_IQualProp))
778 *obj = &presenter->IQualProp_iface;
780 else if (IsEqualIID(riid, &IID_IMFQualityAdvise))
782 *obj = &presenter->IMFQualityAdvise_iface;
784 else if (IsEqualIID(riid, &IID_IMFQualityAdviseLimits))
786 *obj = &presenter->IMFQualityAdviseLimits_iface;
788 else if (IsEqualIID(riid, &IID_IDirect3DDeviceManager9))
790 *obj = &presenter->IDirect3DDeviceManager9_iface;
792 else
794 WARN("Unimplemented interface %s.\n", debugstr_guid(riid));
795 *obj = NULL;
796 return E_NOINTERFACE;
799 IUnknown_AddRef((IUnknown *)*obj);
800 return S_OK;
803 static ULONG WINAPI video_presenter_inner_AddRef(IUnknown *iface)
805 struct video_presenter *presenter = impl_from_IUnknown(iface);
806 ULONG refcount = InterlockedIncrement(&presenter->refcount);
808 TRACE("%p, refcount %u.\n", iface, refcount);
810 return refcount;
813 static void video_presenter_clear_container(struct video_presenter *presenter)
815 if (presenter->clock)
816 IMFClock_Release(presenter->clock);
817 if (presenter->mixer)
818 IMFTransform_Release(presenter->mixer);
819 if (presenter->event_sink)
820 IMediaEventSink_Release(presenter->event_sink);
821 presenter->clock = NULL;
822 presenter->mixer = NULL;
823 presenter->event_sink = NULL;
826 static ULONG WINAPI video_presenter_inner_Release(IUnknown *iface)
828 struct video_presenter *presenter = impl_from_IUnknown(iface);
829 ULONG refcount = InterlockedDecrement(&presenter->refcount);
831 TRACE("%p, refcount %u.\n", iface, refcount);
833 if (!refcount)
835 video_presenter_end_streaming(presenter);
836 video_presenter_clear_container(presenter);
837 video_presenter_reset_media_type(presenter);
838 DeleteCriticalSection(&presenter->cs);
839 if (presenter->swapchain)
840 IDirect3DSwapChain9_Release(presenter->swapchain);
841 if (presenter->device_manager)
843 IDirect3DDeviceManager9_CloseDeviceHandle(presenter->device_manager, presenter->hdevice);
844 IDirect3DDeviceManager9_Release(presenter->device_manager);
846 if (presenter->allocator)
847 IMFVideoSampleAllocator_Release(presenter->allocator);
848 free(presenter);
851 return refcount;
854 static const IUnknownVtbl video_presenter_inner_vtbl =
856 video_presenter_inner_QueryInterface,
857 video_presenter_inner_AddRef,
858 video_presenter_inner_Release,
861 static HRESULT WINAPI video_presenter_QueryInterface(IMFVideoPresenter *iface, REFIID riid, void **obj)
863 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
864 return IUnknown_QueryInterface(presenter->outer_unk, riid, obj);
867 static ULONG WINAPI video_presenter_AddRef(IMFVideoPresenter *iface)
869 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
870 return IUnknown_AddRef(presenter->outer_unk);
873 static ULONG WINAPI video_presenter_Release(IMFVideoPresenter *iface)
875 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
876 return IUnknown_Release(presenter->outer_unk);
879 static HRESULT WINAPI video_presenter_OnClockStart(IMFVideoPresenter *iface, MFTIME systime, LONGLONG offset)
881 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
883 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), wine_dbgstr_longlong(offset));
885 EnterCriticalSection(&presenter->cs);
886 presenter->state = PRESENTER_STATE_STARTED;
887 LeaveCriticalSection(&presenter->cs);
889 return S_OK;
892 static HRESULT WINAPI video_presenter_OnClockStop(IMFVideoPresenter *iface, MFTIME systime)
894 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
896 TRACE("%p, %s.\n", iface, debugstr_time(systime));
898 EnterCriticalSection(&presenter->cs);
899 presenter->state = PRESENTER_STATE_STOPPED;
900 LeaveCriticalSection(&presenter->cs);
902 return S_OK;
905 static HRESULT WINAPI video_presenter_OnClockPause(IMFVideoPresenter *iface, MFTIME systime)
907 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
909 TRACE("%p, %s.\n", iface, debugstr_time(systime));
911 EnterCriticalSection(&presenter->cs);
912 presenter->state = PRESENTER_STATE_PAUSED;
913 LeaveCriticalSection(&presenter->cs);
915 return S_OK;
918 static HRESULT WINAPI video_presenter_OnClockRestart(IMFVideoPresenter *iface, MFTIME systime)
920 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
922 TRACE("%p, %s.\n", iface, debugstr_time(systime));
924 EnterCriticalSection(&presenter->cs);
925 presenter->state = PRESENTER_STATE_STARTED;
926 LeaveCriticalSection(&presenter->cs);
928 return S_OK;
931 static HRESULT WINAPI video_presenter_OnClockSetRate(IMFVideoPresenter *iface, MFTIME systime, float rate)
933 FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
935 return E_NOTIMPL;
938 static HRESULT WINAPI video_presenter_ProcessMessage(IMFVideoPresenter *iface, MFVP_MESSAGE_TYPE message, ULONG_PTR param)
940 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
941 HRESULT hr;
943 TRACE("%p, %d, %lu.\n", iface, message, param);
945 EnterCriticalSection(&presenter->cs);
947 switch (message)
949 case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
950 hr = video_presenter_invalidate_media_type(presenter);
951 break;
952 case MFVP_MESSAGE_BEGINSTREAMING:
953 hr = video_presenter_start_streaming(presenter);
954 break;
955 case MFVP_MESSAGE_ENDSTREAMING:
956 hr = video_presenter_end_streaming(presenter);
957 break;
958 case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
959 presenter->flags |= PRESENTER_MIXER_HAS_INPUT;
960 hr = video_presenter_process_input(presenter);
961 break;
962 default:
963 FIXME("Unsupported message %u.\n", message);
964 hr = E_NOTIMPL;
967 LeaveCriticalSection(&presenter->cs);
969 return hr;
972 static HRESULT WINAPI video_presenter_GetCurrentMediaType(IMFVideoPresenter *iface,
973 IMFVideoMediaType **media_type)
975 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
976 HRESULT hr;
978 TRACE("%p, %p.\n", iface, media_type);
980 EnterCriticalSection(&presenter->cs);
982 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
983 hr = MF_E_SHUTDOWN;
984 else if (!presenter->media_type)
985 hr = MF_E_NOT_INITIALIZED;
986 else
988 hr = IMFMediaType_QueryInterface(presenter->media_type, &IID_IMFVideoMediaType,
989 (void **)media_type);
992 LeaveCriticalSection(&presenter->cs);
994 return hr;
997 static const IMFVideoPresenterVtbl video_presenter_vtbl =
999 video_presenter_QueryInterface,
1000 video_presenter_AddRef,
1001 video_presenter_Release,
1002 video_presenter_OnClockStart,
1003 video_presenter_OnClockStop,
1004 video_presenter_OnClockPause,
1005 video_presenter_OnClockRestart,
1006 video_presenter_OnClockSetRate,
1007 video_presenter_ProcessMessage,
1008 video_presenter_GetCurrentMediaType,
1011 static HRESULT WINAPI video_presenter_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
1013 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1014 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1017 static ULONG WINAPI video_presenter_device_id_AddRef(IMFVideoDeviceID *iface)
1019 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1020 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1023 static ULONG WINAPI video_presenter_device_id_Release(IMFVideoDeviceID *iface)
1025 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1026 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1029 static HRESULT WINAPI video_presenter_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
1031 TRACE("%p, %p.\n", iface, device_id);
1033 if (!device_id)
1034 return E_POINTER;
1036 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
1038 return S_OK;
1041 static const IMFVideoDeviceIDVtbl video_presenter_device_id_vtbl =
1043 video_presenter_device_id_QueryInterface,
1044 video_presenter_device_id_AddRef,
1045 video_presenter_device_id_Release,
1046 video_presenter_device_id_GetDeviceID,
1049 static HRESULT WINAPI video_presenter_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
1050 REFIID riid, void **obj)
1052 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1053 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1056 static ULONG WINAPI video_presenter_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
1058 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1059 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1062 static ULONG WINAPI video_presenter_service_client_Release(IMFTopologyServiceLookupClient *iface)
1064 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1065 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1068 static void video_presenter_set_mixer_rect(struct video_presenter *presenter)
1070 IMFAttributes *attributes;
1071 HRESULT hr;
1073 if (!presenter->mixer)
1074 return;
1076 if (SUCCEEDED(IMFTransform_GetAttributes(presenter->mixer, &attributes)))
1078 if (FAILED(hr = IMFAttributes_SetBlob(attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&presenter->src_rect,
1079 sizeof(presenter->src_rect))))
1081 WARN("Failed to set zoom rectangle attribute, hr %#x.\n", hr);
1083 IMFAttributes_Release(attributes);
1087 static HRESULT video_presenter_attach_mixer(struct video_presenter *presenter, IMFTopologyServiceLookup *service_lookup)
1089 IMFVideoDeviceID *device_id;
1090 unsigned int count;
1091 GUID id = { 0 };
1092 HRESULT hr;
1094 count = 1;
1095 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1096 &MR_VIDEO_MIXER_SERVICE, &IID_IMFTransform, (void **)&presenter->mixer, &count)))
1098 WARN("Failed to get mixer interface, hr %#x.\n", hr);
1099 return hr;
1102 if (SUCCEEDED(hr = IMFTransform_QueryInterface(presenter->mixer, &IID_IMFVideoDeviceID, (void **)&device_id)))
1104 if (SUCCEEDED(hr = IMFVideoDeviceID_GetDeviceID(device_id, &id)))
1106 if (!IsEqualGUID(&id, &IID_IDirect3DDevice9))
1107 hr = MF_E_INVALIDREQUEST;
1110 IMFVideoDeviceID_Release(device_id);
1113 if (FAILED(hr))
1115 IMFTransform_Release(presenter->mixer);
1116 presenter->mixer = NULL;
1119 video_presenter_set_mixer_rect(presenter);
1120 video_presenter_get_native_video_size(presenter);
1122 return hr;
1125 static HRESULT WINAPI video_presenter_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
1126 IMFTopologyServiceLookup *service_lookup)
1128 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1129 unsigned int count;
1130 HRESULT hr = S_OK;
1132 TRACE("%p, %p.\n", iface, service_lookup);
1134 if (!service_lookup)
1135 return E_POINTER;
1137 EnterCriticalSection(&presenter->cs);
1139 if (presenter->state == PRESENTER_STATE_STARTED ||
1140 presenter->state == PRESENTER_STATE_PAUSED)
1142 hr = MF_E_INVALIDREQUEST;
1144 else
1146 video_presenter_clear_container(presenter);
1148 count = 1;
1149 IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1150 &MR_VIDEO_RENDER_SERVICE, &IID_IMFClock, (void **)&presenter->clock, &count);
1152 hr = video_presenter_attach_mixer(presenter, service_lookup);
1154 if (SUCCEEDED(hr))
1156 count = 1;
1157 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1158 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&presenter->event_sink, &count)))
1160 WARN("Failed to get renderer event sink, hr %#x.\n", hr);
1164 if (SUCCEEDED(hr))
1165 presenter->state = PRESENTER_STATE_STOPPED;
1168 LeaveCriticalSection(&presenter->cs);
1170 return hr;
1173 static HRESULT WINAPI video_presenter_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
1175 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1177 TRACE("%p.\n", iface);
1179 EnterCriticalSection(&presenter->cs);
1181 presenter->state = PRESENTER_STATE_SHUT_DOWN;
1182 video_presenter_clear_container(presenter);
1184 LeaveCriticalSection(&presenter->cs);
1186 return S_OK;
1189 static const IMFTopologyServiceLookupClientVtbl video_presenter_service_client_vtbl =
1191 video_presenter_service_client_QueryInterface,
1192 video_presenter_service_client_AddRef,
1193 video_presenter_service_client_Release,
1194 video_presenter_service_client_InitServicePointers,
1195 video_presenter_service_client_ReleaseServicePointers,
1198 static HRESULT WINAPI video_presenter_control_QueryInterface(IMFVideoDisplayControl *iface, REFIID riid, void **obj)
1200 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1201 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1204 static ULONG WINAPI video_presenter_control_AddRef(IMFVideoDisplayControl *iface)
1206 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1207 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1210 static ULONG WINAPI video_presenter_control_Release(IMFVideoDisplayControl *iface)
1212 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1213 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1216 static HRESULT WINAPI video_presenter_control_GetNativeVideoSize(IMFVideoDisplayControl *iface, SIZE *video_size,
1217 SIZE *aspect_ratio)
1219 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1221 TRACE("%p, %p, %p.\n", iface, video_size, aspect_ratio);
1223 if (!video_size && !aspect_ratio)
1224 return E_POINTER;
1226 EnterCriticalSection(&presenter->cs);
1227 if (video_size)
1228 *video_size = presenter->native_size;
1229 if (aspect_ratio)
1230 *aspect_ratio = presenter->native_ratio;
1231 LeaveCriticalSection(&presenter->cs);
1233 return S_OK;
1236 static HRESULT WINAPI video_presenter_control_GetIdealVideoSize(IMFVideoDisplayControl *iface, SIZE *min_size,
1237 SIZE *max_size)
1239 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
1241 return E_NOTIMPL;
1244 static HRESULT WINAPI video_presenter_control_SetVideoPosition(IMFVideoDisplayControl *iface,
1245 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect)
1247 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1248 HRESULT hr = S_OK;
1250 TRACE("%p, %p, %s.\n", iface, src_rect, wine_dbgstr_rect(dst_rect));
1252 if (!src_rect && !dst_rect)
1253 return E_POINTER;
1255 if (src_rect && (src_rect->left < 0.0f || src_rect->top < 0.0f ||
1256 src_rect->right > 1.0f || src_rect->bottom > 1.0f ||
1257 src_rect->left > src_rect->right ||
1258 src_rect->top > src_rect->bottom))
1260 return E_INVALIDARG;
1263 if (dst_rect && (dst_rect->left > dst_rect->right ||
1264 dst_rect->top > dst_rect->bottom))
1265 return E_INVALIDARG;
1267 EnterCriticalSection(&presenter->cs);
1268 if (!presenter->video_window)
1269 hr = E_POINTER;
1270 else
1272 if (src_rect)
1274 if (memcmp(&presenter->src_rect, src_rect, sizeof(*src_rect)))
1276 presenter->src_rect = *src_rect;
1277 video_presenter_set_mixer_rect(presenter);
1280 if (dst_rect)
1281 presenter->dst_rect = *dst_rect;
1283 LeaveCriticalSection(&presenter->cs);
1285 return hr;
1288 static HRESULT WINAPI video_presenter_control_GetVideoPosition(IMFVideoDisplayControl *iface, MFVideoNormalizedRect *src_rect,
1289 RECT *dst_rect)
1291 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1293 TRACE("%p, %p, %p.\n", iface, src_rect, dst_rect);
1295 if (!src_rect || !dst_rect)
1296 return E_POINTER;
1298 EnterCriticalSection(&presenter->cs);
1299 *src_rect = presenter->src_rect;
1300 *dst_rect = presenter->dst_rect;
1301 LeaveCriticalSection(&presenter->cs);
1303 return S_OK;
1306 static HRESULT WINAPI video_presenter_control_SetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD mode)
1308 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1310 TRACE("%p, %#x.\n", iface, mode);
1312 if (mode & ~MFVideoARMode_Mask)
1313 return E_INVALIDARG;
1315 EnterCriticalSection(&presenter->cs);
1316 presenter->ar_mode = mode;
1317 LeaveCriticalSection(&presenter->cs);
1319 return S_OK;
1322 static HRESULT WINAPI video_presenter_control_GetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD *mode)
1324 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1326 TRACE("%p, %p.\n", iface, mode);
1328 if (!mode)
1329 return E_POINTER;
1331 EnterCriticalSection(&presenter->cs);
1332 *mode = presenter->ar_mode;
1333 LeaveCriticalSection(&presenter->cs);
1335 return S_OK;
1338 static HRESULT video_presenter_create_swapchain(struct video_presenter *presenter)
1340 D3DPRESENT_PARAMETERS present_params = { 0 };
1341 IDirect3DDevice9 *d3d_device;
1342 HRESULT hr;
1344 if (SUCCEEDED(hr = video_presenter_get_device(presenter, &d3d_device)))
1346 present_params.hDeviceWindow = presenter->video_window;
1347 present_params.Windowed = TRUE;
1348 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
1349 present_params.Flags = D3DPRESENTFLAG_VIDEO;
1350 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1351 hr = IDirect3DDevice9_CreateAdditionalSwapChain(d3d_device, &present_params, &presenter->swapchain);
1353 IDirect3DDevice9_Release(d3d_device);
1354 IDirect3DDeviceManager9_UnlockDevice(presenter->device_manager, presenter->hdevice, FALSE);
1357 return hr;
1360 static HRESULT WINAPI video_presenter_control_SetVideoWindow(IMFVideoDisplayControl *iface, HWND window)
1362 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1363 HRESULT hr = S_OK;
1365 TRACE("%p, %p.\n", iface, window);
1367 if (!IsWindow(window))
1368 return E_INVALIDARG;
1370 EnterCriticalSection(&presenter->cs);
1371 if (presenter->video_window != window)
1373 if (presenter->swapchain)
1374 IDirect3DSwapChain9_Release(presenter->swapchain);
1375 presenter->video_window = window;
1376 hr = video_presenter_create_swapchain(presenter);
1378 LeaveCriticalSection(&presenter->cs);
1380 return hr;
1383 static HRESULT WINAPI video_presenter_control_GetVideoWindow(IMFVideoDisplayControl *iface, HWND *window)
1385 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1387 TRACE("%p, %p.\n", iface, window);
1389 if (!window)
1390 return E_POINTER;
1392 EnterCriticalSection(&presenter->cs);
1393 *window = presenter->video_window;
1394 LeaveCriticalSection(&presenter->cs);
1396 return S_OK;
1399 static HRESULT WINAPI video_presenter_control_RepaintVideo(IMFVideoDisplayControl *iface)
1401 FIXME("%p.\n", iface);
1403 return E_NOTIMPL;
1406 static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayControl *iface, BITMAPINFOHEADER *header,
1407 BYTE **dib, DWORD *dib_size, LONGLONG *timestamp)
1409 FIXME("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp);
1411 return E_NOTIMPL;
1414 static HRESULT WINAPI video_presenter_control_SetBorderColor(IMFVideoDisplayControl *iface, COLORREF color)
1416 FIXME("%p, %#x.\n", iface, color);
1418 return E_NOTIMPL;
1421 static HRESULT WINAPI video_presenter_control_GetBorderColor(IMFVideoDisplayControl *iface, COLORREF *color)
1423 FIXME("%p, %p.\n", iface, color);
1425 return E_NOTIMPL;
1428 static HRESULT WINAPI video_presenter_control_SetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD flags)
1430 FIXME("%p, %#x.\n", iface, flags);
1432 return E_NOTIMPL;
1435 static HRESULT WINAPI video_presenter_control_GetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD *flags)
1437 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1439 TRACE("%p, %p.\n", iface, flags);
1441 if (!flags)
1442 return E_POINTER;
1444 EnterCriticalSection(&presenter->cs);
1445 *flags = presenter->rendering_prefs;
1446 LeaveCriticalSection(&presenter->cs);
1448 return S_OK;
1451 static HRESULT WINAPI video_presenter_control_SetFullscreen(IMFVideoDisplayControl *iface, BOOL fullscreen)
1453 FIXME("%p, %d.\n", iface, fullscreen);
1455 return E_NOTIMPL;
1458 static HRESULT WINAPI video_presenter_control_GetFullscreen(IMFVideoDisplayControl *iface, BOOL *fullscreen)
1460 FIXME("%p, %p.\n", iface, fullscreen);
1462 return E_NOTIMPL;
1465 static const IMFVideoDisplayControlVtbl video_presenter_control_vtbl =
1467 video_presenter_control_QueryInterface,
1468 video_presenter_control_AddRef,
1469 video_presenter_control_Release,
1470 video_presenter_control_GetNativeVideoSize,
1471 video_presenter_control_GetIdealVideoSize,
1472 video_presenter_control_SetVideoPosition,
1473 video_presenter_control_GetVideoPosition,
1474 video_presenter_control_SetAspectRatioMode,
1475 video_presenter_control_GetAspectRatioMode,
1476 video_presenter_control_SetVideoWindow,
1477 video_presenter_control_GetVideoWindow,
1478 video_presenter_control_RepaintVideo,
1479 video_presenter_control_GetCurrentImage,
1480 video_presenter_control_SetBorderColor,
1481 video_presenter_control_GetBorderColor,
1482 video_presenter_control_SetRenderingPrefs,
1483 video_presenter_control_GetRenderingPrefs,
1484 video_presenter_control_SetFullscreen,
1485 video_presenter_control_GetFullscreen,
1488 static HRESULT WINAPI video_presenter_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1490 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1491 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1494 static ULONG WINAPI video_presenter_rate_support_AddRef(IMFRateSupport *iface)
1496 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1497 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1500 static ULONG WINAPI video_presenter_rate_support_Release(IMFRateSupport *iface)
1502 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1503 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1506 static HRESULT WINAPI video_presenter_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1507 BOOL thin, float *rate)
1509 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1511 *rate = 0.0f;
1513 return S_OK;
1516 static HRESULT WINAPI video_presenter_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1517 BOOL thin, float *rate)
1519 return E_NOTIMPL;
1522 static HRESULT WINAPI video_presenter_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1523 float *nearest_supported_rate)
1525 return E_NOTIMPL;
1528 static const IMFRateSupportVtbl video_presenter_rate_support_vtbl =
1530 video_presenter_rate_support_QueryInterface,
1531 video_presenter_rate_support_AddRef,
1532 video_presenter_rate_support_Release,
1533 video_presenter_rate_support_GetSlowestRate,
1534 video_presenter_rate_support_GetFastestRate,
1535 video_presenter_rate_support_IsRateSupported,
1538 static HRESULT WINAPI video_presenter_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1540 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1541 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1544 static ULONG WINAPI video_presenter_getservice_AddRef(IMFGetService *iface)
1546 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1547 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1550 static ULONG WINAPI video_presenter_getservice_Release(IMFGetService *iface)
1552 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1553 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1556 static HRESULT WINAPI video_presenter_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1558 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1560 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1562 if (IsEqualGUID(&MR_VIDEO_ACCELERATION_SERVICE, service))
1563 return IDirect3DDeviceManager9_QueryInterface(presenter->device_manager, riid, obj);
1565 if (IsEqualGUID(&MR_VIDEO_RENDER_SERVICE, service))
1566 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1568 FIXME("Unimplemented service %s.\n", debugstr_guid(service));
1570 return MF_E_UNSUPPORTED_SERVICE;
1573 static const IMFGetServiceVtbl video_presenter_getservice_vtbl =
1575 video_presenter_getservice_QueryInterface,
1576 video_presenter_getservice_AddRef,
1577 video_presenter_getservice_Release,
1578 video_presenter_getservice_GetService,
1581 static HRESULT WINAPI video_presenter_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1583 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1584 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1587 static ULONG WINAPI video_presenter_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1589 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1590 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1593 static ULONG WINAPI video_presenter_position_mapper_Release(IMFVideoPositionMapper *iface)
1595 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1596 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1599 static HRESULT WINAPI video_presenter_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1600 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1602 FIXME("%p, %f, %f, %u, %u, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1604 return E_NOTIMPL;
1607 static const IMFVideoPositionMapperVtbl video_presenter_position_mapper_vtbl =
1609 video_presenter_position_mapper_QueryInterface,
1610 video_presenter_position_mapper_AddRef,
1611 video_presenter_position_mapper_Release,
1612 video_presenter_position_mapper_MapOutputCoordinateToInputStream,
1615 static HRESULT WINAPI video_presenter_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1616 REFIID riid, void **obj)
1618 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1619 IsEqualIID(riid, &IID_IUnknown))
1621 *obj = iface;
1622 IMFVideoSampleAllocatorNotify_AddRef(iface);
1623 return S_OK;
1626 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1627 *obj = NULL;
1628 return E_NOINTERFACE;
1631 static ULONG WINAPI video_presenter_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1633 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1634 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1637 static ULONG WINAPI video_presenter_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1639 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1640 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1643 static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1645 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1647 /* Release notification is executed under allocator lock, instead of processing samples here
1648 notify streaming thread. */
1649 PostThreadMessageW(presenter->thread.tid, EVRM_PROCESS_INPUT, 0, 0);
1651 return S_OK;
1654 static const IMFVideoSampleAllocatorNotifyVtbl video_presenter_allocator_cb_vtbl =
1656 video_presenter_allocator_cb_QueryInterface,
1657 video_presenter_allocator_cb_AddRef,
1658 video_presenter_allocator_cb_Release,
1659 video_presenter_allocator_cb_NotifyRelease,
1662 static HRESULT WINAPI video_presenter_qualprop_QueryInterface(IQualProp *iface, REFIID riid, void **obj)
1664 struct video_presenter *presenter = impl_from_IQualProp(iface);
1665 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1668 static ULONG WINAPI video_presenter_qualprop_AddRef(IQualProp *iface)
1670 struct video_presenter *presenter = impl_from_IQualProp(iface);
1671 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1674 static ULONG WINAPI video_presenter_qualprop_Release(IQualProp *iface)
1676 struct video_presenter *presenter = impl_from_IQualProp(iface);
1677 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1680 static HRESULT WINAPI video_presenter_qualprop_get_FramesDroppedInRenderer(IQualProp *iface, int *frames)
1682 FIXME("%p, %p stub.\n", iface, frames);
1684 return E_NOTIMPL;
1687 static HRESULT WINAPI video_presenter_qualprop_get_FramesDrawn(IQualProp *iface, int *frames)
1689 FIXME("%p, %p stub.\n", iface, frames);
1691 return E_NOTIMPL;
1694 static HRESULT WINAPI video_presenter_qualprop_get_AvgFrameRate(IQualProp *iface, int *avg_frame_rate)
1696 FIXME("%p, %p stub.\n", iface, avg_frame_rate);
1698 return E_NOTIMPL;
1701 static HRESULT WINAPI video_presenter_qualprop_get_Jitter(IQualProp *iface, int *jitter)
1703 FIXME("%p, %p stub.\n", iface, jitter);
1705 return E_NOTIMPL;
1708 static HRESULT WINAPI video_presenter_qualprop_get_AvgSyncOffset(IQualProp *iface, int *offset)
1710 FIXME("%p, %p stub.\n", iface, offset);
1712 return E_NOTIMPL;
1715 static HRESULT WINAPI video_presenter_qualprop_get_DevSyncOffset(IQualProp *iface, int *devoffset)
1717 FIXME("%p, %p stub.\n", iface, devoffset);
1719 return E_NOTIMPL;
1722 static const IQualPropVtbl video_presenter_qualprop_vtbl =
1724 video_presenter_qualprop_QueryInterface,
1725 video_presenter_qualprop_AddRef,
1726 video_presenter_qualprop_Release,
1727 video_presenter_qualprop_get_FramesDroppedInRenderer,
1728 video_presenter_qualprop_get_FramesDrawn,
1729 video_presenter_qualprop_get_AvgFrameRate,
1730 video_presenter_qualprop_get_Jitter,
1731 video_presenter_qualprop_get_AvgSyncOffset,
1732 video_presenter_qualprop_get_DevSyncOffset,
1735 static HRESULT WINAPI video_presenter_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
1737 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1738 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, out);
1741 static ULONG WINAPI video_presenter_quality_advise_AddRef(IMFQualityAdvise *iface)
1743 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1744 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1747 static ULONG WINAPI video_presenter_quality_advise_Release(IMFQualityAdvise *iface)
1749 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1750 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1753 static HRESULT WINAPI video_presenter_quality_advise_SetDropMode(IMFQualityAdvise *iface,
1754 MF_QUALITY_DROP_MODE mode)
1756 FIXME("%p, %u.\n", iface, mode);
1758 return E_NOTIMPL;
1761 static HRESULT WINAPI video_presenter_quality_advise_SetQualityLevel(IMFQualityAdvise *iface,
1762 MF_QUALITY_LEVEL level)
1764 FIXME("%p, %u.\n", iface, level);
1766 return E_NOTIMPL;
1769 static HRESULT WINAPI video_presenter_quality_advise_GetDropMode(IMFQualityAdvise *iface,
1770 MF_QUALITY_DROP_MODE *mode)
1772 FIXME("%p, %p.\n", iface, mode);
1774 return E_NOTIMPL;
1777 static HRESULT WINAPI video_presenter_quality_advise_GetQualityLevel(IMFQualityAdvise *iface,
1778 MF_QUALITY_LEVEL *level)
1780 FIXME("%p, %p.\n", iface, level);
1782 return E_NOTIMPL;
1785 static HRESULT WINAPI video_presenter_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
1787 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
1789 return E_NOTIMPL;
1792 static const IMFQualityAdviseVtbl video_presenter_quality_advise_vtbl =
1794 video_presenter_quality_advise_QueryInterface,
1795 video_presenter_quality_advise_AddRef,
1796 video_presenter_quality_advise_Release,
1797 video_presenter_quality_advise_SetDropMode,
1798 video_presenter_quality_advise_SetQualityLevel,
1799 video_presenter_quality_advise_GetDropMode,
1800 video_presenter_quality_advise_GetQualityLevel,
1801 video_presenter_quality_advise_DropTime,
1804 static HRESULT WINAPI video_presenter_device_manager_QueryInterface(IDirect3DDeviceManager9 *iface,
1805 REFIID riid, void **obj)
1807 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1808 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1811 static ULONG WINAPI video_presenter_device_manager_AddRef(IDirect3DDeviceManager9 *iface)
1813 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1814 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1817 static ULONG WINAPI video_presenter_device_manager_Release(IDirect3DDeviceManager9 *iface)
1819 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1820 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1823 static HRESULT WINAPI video_presenter_device_manager_ResetDevice(IDirect3DDeviceManager9 *iface,
1824 IDirect3DDevice9 *device, UINT token)
1826 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1827 return IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, token);
1830 static HRESULT WINAPI video_presenter_device_manager_OpenDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE *hdevice)
1832 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1833 return IDirect3DDeviceManager9_OpenDeviceHandle(presenter->device_manager, hdevice);
1836 static HRESULT WINAPI video_presenter_device_manager_CloseDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
1838 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1839 return IDirect3DDeviceManager9_CloseDeviceHandle(presenter->device_manager, hdevice);
1842 static HRESULT WINAPI video_presenter_device_manager_TestDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
1844 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1845 return IDirect3DDeviceManager9_TestDevice(presenter->device_manager, hdevice);
1848 static HRESULT WINAPI video_presenter_device_manager_LockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
1849 IDirect3DDevice9 **device, BOOL block)
1851 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1852 return IDirect3DDeviceManager9_LockDevice(presenter->device_manager, hdevice, device, block);
1855 static HRESULT WINAPI video_presenter_device_manager_UnlockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
1856 BOOL savestate)
1858 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1859 return IDirect3DDeviceManager9_UnlockDevice(presenter->device_manager, hdevice, savestate);
1862 static HRESULT WINAPI video_presenter_device_manager_GetVideoService(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
1863 REFIID riid, void **service)
1865 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1866 return IDirect3DDeviceManager9_GetVideoService(presenter->device_manager, hdevice, riid, service);
1869 static const IDirect3DDeviceManager9Vtbl video_presenter_device_manager_vtbl =
1871 video_presenter_device_manager_QueryInterface,
1872 video_presenter_device_manager_AddRef,
1873 video_presenter_device_manager_Release,
1874 video_presenter_device_manager_ResetDevice,
1875 video_presenter_device_manager_OpenDeviceHandle,
1876 video_presenter_device_manager_CloseDeviceHandle,
1877 video_presenter_device_manager_TestDevice,
1878 video_presenter_device_manager_LockDevice,
1879 video_presenter_device_manager_UnlockDevice,
1880 video_presenter_device_manager_GetVideoService,
1883 static HRESULT WINAPI video_presenter_qa_limits_QueryInterface(IMFQualityAdviseLimits *iface, REFIID riid, void **obj)
1885 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
1886 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1889 static ULONG WINAPI video_presenter_qa_limits_AddRef(IMFQualityAdviseLimits *iface)
1891 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
1892 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1895 static ULONG WINAPI video_presenter_qa_limits_Release(IMFQualityAdviseLimits *iface)
1897 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
1898 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1901 static HRESULT WINAPI video_presenter_qa_limits_GetMaximumDropMode(IMFQualityAdviseLimits *iface, MF_QUALITY_DROP_MODE *mode)
1903 FIXME("%p, %p.\n", iface, mode);
1905 return E_NOTIMPL;
1908 static HRESULT WINAPI video_presenter_qa_limits_GetMinimumQualityLevel(IMFQualityAdviseLimits *iface, MF_QUALITY_LEVEL *level)
1910 FIXME("%p, %p.\n", iface, level);
1912 return E_NOTIMPL;
1915 static const IMFQualityAdviseLimitsVtbl video_presenter_qa_limits_vtbl =
1917 video_presenter_qa_limits_QueryInterface,
1918 video_presenter_qa_limits_AddRef,
1919 video_presenter_qa_limits_Release,
1920 video_presenter_qa_limits_GetMaximumDropMode,
1921 video_presenter_qa_limits_GetMinimumQualityLevel,
1924 HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
1926 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
1928 *obj = NULL;
1930 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
1931 return E_INVALIDARG;
1933 return CoCreateInstance(&CLSID_MFVideoPresenter9, owner, CLSCTX_INPROC_SERVER, riid, obj);
1936 static HRESULT video_presenter_init_d3d(struct video_presenter *presenter)
1938 D3DPRESENT_PARAMETERS present_params = { 0 };
1939 IDirect3DDevice9 *device;
1940 IDirect3D9 *d3d;
1941 HRESULT hr;
1943 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1945 present_params.BackBufferCount = 1;
1946 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
1947 present_params.hDeviceWindow = GetDesktopWindow();
1948 present_params.Windowed = TRUE;
1949 present_params.Flags = D3DPRESENTFLAG_VIDEO;
1950 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1951 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
1952 0, &present_params, &device);
1954 IDirect3D9_Release(d3d);
1956 if (FAILED(hr))
1958 WARN("Failed to create d3d device, hr %#x.\n", hr);
1959 return hr;
1962 hr = IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, presenter->reset_token);
1963 IDirect3DDevice9_Release(device);
1964 if (FAILED(hr))
1965 WARN("Failed to set new device for the manager, hr %#x.\n", hr);
1967 if (SUCCEEDED(hr = MFCreateVideoSampleAllocator(&IID_IMFVideoSampleAllocator, (void **)&presenter->allocator)))
1969 hr = IMFVideoSampleAllocator_SetDirectXManager(presenter->allocator, (IUnknown *)presenter->device_manager);
1972 return hr;
1975 HRESULT evr_presenter_create(IUnknown *outer, void **out)
1977 struct video_presenter *object;
1978 HRESULT hr;
1980 *out = NULL;
1982 if (!(object = calloc(1, sizeof(*object))))
1983 return E_OUTOFMEMORY;
1985 object->IMFVideoPresenter_iface.lpVtbl = &video_presenter_vtbl;
1986 object->IMFVideoDeviceID_iface.lpVtbl = &video_presenter_device_id_vtbl;
1987 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_presenter_service_client_vtbl;
1988 object->IMFVideoDisplayControl_iface.lpVtbl = &video_presenter_control_vtbl;
1989 object->IMFRateSupport_iface.lpVtbl = &video_presenter_rate_support_vtbl;
1990 object->IMFGetService_iface.lpVtbl = &video_presenter_getservice_vtbl;
1991 object->IMFVideoPositionMapper_iface.lpVtbl = &video_presenter_position_mapper_vtbl;
1992 object->IQualProp_iface.lpVtbl = &video_presenter_qualprop_vtbl;
1993 object->IMFQualityAdvise_iface.lpVtbl = &video_presenter_quality_advise_vtbl;
1994 object->IMFQualityAdviseLimits_iface.lpVtbl = &video_presenter_qa_limits_vtbl;
1995 object->allocator_cb.lpVtbl = &video_presenter_allocator_cb_vtbl;
1996 object->IUnknown_inner.lpVtbl = &video_presenter_inner_vtbl;
1997 object->IDirect3DDeviceManager9_iface.lpVtbl = &video_presenter_device_manager_vtbl;
1998 object->outer_unk = outer ? outer : &object->IUnknown_inner;
1999 object->refcount = 1;
2000 object->src_rect.right = object->src_rect.bottom = 1.0f;
2001 object->ar_mode = MFVideoARMode_PreservePicture | MFVideoARMode_PreservePixel;
2002 object->allocator_capacity = 3;
2003 InitializeCriticalSection(&object->cs);
2005 if (FAILED(hr = DXVA2CreateDirect3DDeviceManager9(&object->reset_token, &object->device_manager)))
2006 goto failed;
2008 if (FAILED(hr = video_presenter_init_d3d(object)))
2009 goto failed;
2011 *out = &object->IUnknown_inner;
2013 return S_OK;
2015 failed:
2017 IUnknown_Release(&object->IUnknown_inner);
2019 return hr;