mf/session: Implement support for sinks that provide sample allocators.
[wine.git] / dlls / evr / presenter.c
blob9bf4cda37257f320d069fcc7ecc0adf005202b0e
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"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(evr);
35 enum presenter_state
37 PRESENTER_STATE_SHUT_DOWN = 0,
38 PRESENTER_STATE_STARTED,
39 PRESENTER_STATE_STOPPED,
40 PRESENTER_STATE_PAUSED,
43 enum presenter_flags
45 PRESENTER_MIXER_HAS_INPUT = 0x1,
48 enum streaming_thread_message
50 EVRM_STOP = WM_USER,
53 struct streaming_thread
55 HANDLE hthread;
56 HANDLE ready_event;
57 DWORD tid;
60 struct video_presenter
62 IMFVideoPresenter IMFVideoPresenter_iface;
63 IMFVideoDeviceID IMFVideoDeviceID_iface;
64 IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
65 IMFVideoDisplayControl IMFVideoDisplayControl_iface;
66 IMFRateSupport IMFRateSupport_iface;
67 IMFGetService IMFGetService_iface;
68 IMFVideoPositionMapper IMFVideoPositionMapper_iface;
69 IMFVideoSampleAllocatorNotify allocator_cb;
70 IUnknown IUnknown_inner;
71 IUnknown *outer_unk;
72 LONG refcount;
74 IMFTransform *mixer;
75 IMFClock *clock;
76 IMediaEventSink *event_sink;
78 IDirect3DDeviceManager9 *device_manager;
79 IMFVideoSampleAllocator *allocator;
80 struct streaming_thread thread;
81 IMFMediaType *media_type;
82 UINT reset_token;
83 HWND video_window;
84 MFVideoNormalizedRect src_rect;
85 RECT dst_rect;
86 DWORD rendering_prefs;
87 SIZE native_size;
88 SIZE native_ratio;
89 unsigned int ar_mode;
90 unsigned int state;
91 unsigned int flags;
92 CRITICAL_SECTION cs;
95 static struct video_presenter *impl_from_IUnknown(IUnknown *iface)
97 return CONTAINING_RECORD(iface, struct video_presenter, IUnknown_inner);
100 static struct video_presenter *impl_from_IMFVideoPresenter(IMFVideoPresenter *iface)
102 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPresenter_iface);
105 static struct video_presenter *impl_from_IMFVideoDeviceID(IMFVideoDeviceID *iface)
107 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoDeviceID_iface);
110 static struct video_presenter *impl_from_IMFTopologyServiceLookupClient(IMFTopologyServiceLookupClient *iface)
112 return CONTAINING_RECORD(iface, struct video_presenter, IMFTopologyServiceLookupClient_iface);
115 static struct video_presenter *impl_from_IMFVideoDisplayControl(IMFVideoDisplayControl *iface)
117 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoDisplayControl_iface);
120 static struct video_presenter *impl_from_IMFRateSupport(IMFRateSupport *iface)
122 return CONTAINING_RECORD(iface, struct video_presenter, IMFRateSupport_iface);
125 static struct video_presenter *impl_from_IMFGetService(IMFGetService *iface)
127 return CONTAINING_RECORD(iface, struct video_presenter, IMFGetService_iface);
130 static struct video_presenter *impl_from_IMFVideoPositionMapper(IMFVideoPositionMapper *iface)
132 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPositionMapper_iface);
135 static struct video_presenter *impl_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
137 return CONTAINING_RECORD(iface, struct video_presenter, allocator_cb);
140 static void video_presenter_notify_renderer(struct video_presenter *presenter,
141 LONG event, LONG_PTR param1, LONG_PTR param2)
143 if (presenter->event_sink)
144 IMediaEventSink_Notify(presenter->event_sink, event, param1, param2);
147 static unsigned int get_gcd(unsigned int a, unsigned int b)
149 unsigned int m;
151 while (b)
153 m = a % b;
154 a = b;
155 b = m;
158 return a;
161 static void video_presenter_get_native_video_size(struct video_presenter *presenter)
163 IMFMediaType *media_type;
164 UINT64 frame_size = 0;
166 memset(&presenter->native_size, 0, sizeof(presenter->native_size));
167 memset(&presenter->native_ratio, 0, sizeof(presenter->native_ratio));
169 if (!presenter->mixer)
170 return;
172 if (FAILED(IMFTransform_GetInputCurrentType(presenter->mixer, 0, &media_type)))
173 return;
175 if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
177 unsigned int gcd;
179 presenter->native_size.cx = frame_size >> 32;
180 presenter->native_size.cy = frame_size;
182 if ((gcd = get_gcd(presenter->native_size.cx, presenter->native_size.cy)))
184 presenter->native_ratio.cx = presenter->native_size.cx / gcd;
185 presenter->native_ratio.cy = presenter->native_size.cy / gcd;
189 IMFMediaType_Release(media_type);
192 /* It is important this is called to reset callback too to break circular referencing,
193 when allocator keeps a reference of its container, that created it. */
194 static void video_presenter_set_allocator_callback(struct video_presenter *presenter,
195 IMFVideoSampleAllocatorNotify *notify_cb)
197 IMFVideoSampleAllocatorCallback *cb;
199 IMFVideoSampleAllocator_QueryInterface(presenter->allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&cb);
200 IMFVideoSampleAllocatorCallback_SetCallback(cb, notify_cb);
201 IMFVideoSampleAllocatorCallback_Release(cb);
204 static void video_presenter_reset_media_type(struct video_presenter *presenter)
206 if (presenter->media_type)
207 IMFMediaType_Release(presenter->media_type);
208 presenter->media_type = NULL;
210 IMFVideoSampleAllocator_UninitializeSampleAllocator(presenter->allocator);
211 video_presenter_set_allocator_callback(presenter, NULL);
214 static HRESULT video_presenter_set_media_type(struct video_presenter *presenter, IMFMediaType *media_type)
216 unsigned int flags;
217 HRESULT hr;
219 if (!media_type)
221 video_presenter_reset_media_type(presenter);
222 return S_OK;
225 if (presenter->media_type && IMFMediaType_IsEqual(presenter->media_type, media_type, &flags) == S_OK)
226 return S_OK;
228 video_presenter_reset_media_type(presenter);
230 if (SUCCEEDED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(presenter->allocator, 3, media_type)))
232 presenter->media_type = media_type;
233 IMFMediaType_AddRef(presenter->media_type);
235 else
236 WARN("Failed to initialize sample allocator, hr %#x.\n", hr);
238 return hr;
241 static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter)
243 IMFMediaType *media_type;
244 unsigned int idx = 0;
245 HRESULT hr;
247 video_presenter_get_native_video_size(presenter);
249 while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &media_type)))
251 /* FIXME: check that d3d device supports this format */
253 /* FIXME: potentially adjust frame size */
255 hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
257 if (SUCCEEDED(hr))
258 hr = video_presenter_set_media_type(presenter, media_type);
260 if (SUCCEEDED(hr))
261 hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0);
263 IMFMediaType_Release(media_type);
265 if (SUCCEEDED(hr))
266 break;
269 return hr;
272 static DWORD CALLBACK video_presenter_streaming_thread(void *arg)
274 struct video_presenter *presenter = arg;
275 BOOL stop_thread = FALSE;
276 MSG msg;
278 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
280 SetEvent(presenter->thread.ready_event);
282 while (!stop_thread)
284 MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_POSTMESSAGE);
286 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
288 switch (msg.message)
290 case EVRM_STOP:
291 stop_thread = TRUE;
292 break;
294 default:
300 return 0;
303 static HRESULT video_presenter_start_streaming(struct video_presenter *presenter)
305 if (presenter->thread.hthread)
306 return S_OK;
308 if (!(presenter->thread.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
309 return HRESULT_FROM_WIN32(GetLastError());
311 if (!(presenter->thread.hthread = CreateThread(NULL, 0, video_presenter_streaming_thread,
312 presenter, 0, &presenter->thread.tid)))
314 WARN("Failed to create streaming thread.\n");
315 CloseHandle(presenter->thread.ready_event);
316 presenter->thread.ready_event = NULL;
317 return E_FAIL;
320 video_presenter_set_allocator_callback(presenter, &presenter->allocator_cb);
322 WaitForSingleObject(presenter->thread.ready_event, INFINITE);
323 CloseHandle(presenter->thread.ready_event);
324 presenter->thread.ready_event = NULL;
326 TRACE("Started streaming thread, tid %#x.\n", presenter->thread.tid);
328 return S_OK;
331 static HRESULT video_presenter_end_streaming(struct video_presenter *presenter)
333 if (!presenter->thread.hthread)
334 return S_OK;
336 PostThreadMessageW(presenter->thread.tid, EVRM_STOP, 0, 0);
338 WaitForSingleObject(presenter->thread.hthread, INFINITE);
339 CloseHandle(presenter->thread.hthread);
341 TRACE("Terminated streaming thread tid %#x.\n", presenter->thread.tid);
343 memset(&presenter->thread, 0, sizeof(presenter->thread));
344 video_presenter_set_allocator_callback(presenter, NULL);
346 return S_OK;
349 static HRESULT video_presenter_process_input(struct video_presenter *presenter)
351 MFT_OUTPUT_DATA_BUFFER buffer;
352 HRESULT hr = S_OK;
353 IMFSample *sample;
354 DWORD status;
356 if (!presenter->media_type)
357 return S_OK;
359 while (hr == S_OK)
361 LONGLONG mixing_started, mixing_finished;
362 MFTIME systime;
364 if (!(presenter->flags & PRESENTER_MIXER_HAS_INPUT))
365 break;
367 if (FAILED(hr = IMFVideoSampleAllocator_AllocateSample(presenter->allocator, &sample)))
369 WARN("Failed to allocate a sample, hr %#x.\n", hr);
370 break;
373 memset(&buffer, 0, sizeof(buffer));
374 buffer.pSample = sample;
376 if (presenter->clock)
377 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_started, &systime);
379 if (FAILED(hr = IMFTransform_ProcessOutput(presenter->mixer, 0, 1, &buffer, &status)))
381 /* FIXME: failure path probably needs to handle some errors specifically */
382 presenter->flags &= ~PRESENTER_MIXER_HAS_INPUT;
383 IMFSample_Release(sample);
384 break;
386 else
388 if (presenter->clock)
390 LONGLONG latency;
392 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_finished, &systime);
393 latency = mixing_finished - mixing_started;
394 video_presenter_notify_renderer(presenter, EC_PROCESSING_LATENCY, (LONG_PTR)&latency, 0);
397 if (buffer.pEvents)
398 IMFCollection_Release(buffer.pEvents);
400 /* FIXME: for now drop output sample back to the pool */
401 IMFSample_Release(sample);
405 return S_OK;
408 static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
410 struct video_presenter *presenter = impl_from_IUnknown(iface);
412 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
414 if (IsEqualIID(riid, &IID_IUnknown))
416 *obj = iface;
418 else if (IsEqualIID(riid, &IID_IMFClockStateSink)
419 || IsEqualIID(riid, &IID_IMFVideoPresenter))
421 *obj = &presenter->IMFVideoPresenter_iface;
423 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
425 *obj = &presenter->IMFVideoDeviceID_iface;
427 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
429 *obj = &presenter->IMFTopologyServiceLookupClient_iface;
431 else if (IsEqualIID(riid, &IID_IMFVideoDisplayControl))
433 *obj = &presenter->IMFVideoDisplayControl_iface;
435 else if (IsEqualIID(riid, &IID_IMFRateSupport))
437 *obj = &presenter->IMFRateSupport_iface;
439 else if (IsEqualIID(riid, &IID_IMFGetService))
441 *obj = &presenter->IMFGetService_iface;
443 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
445 *obj = &presenter->IMFVideoPositionMapper_iface;
447 else
449 WARN("Unimplemented interface %s.\n", debugstr_guid(riid));
450 *obj = NULL;
451 return E_NOINTERFACE;
454 IUnknown_AddRef((IUnknown *)*obj);
455 return S_OK;
458 static ULONG WINAPI video_presenter_inner_AddRef(IUnknown *iface)
460 struct video_presenter *presenter = impl_from_IUnknown(iface);
461 ULONG refcount = InterlockedIncrement(&presenter->refcount);
463 TRACE("%p, refcount %u.\n", iface, refcount);
465 return refcount;
468 static void video_presenter_clear_container(struct video_presenter *presenter)
470 if (presenter->clock)
471 IMFClock_Release(presenter->clock);
472 if (presenter->mixer)
473 IMFTransform_Release(presenter->mixer);
474 if (presenter->event_sink)
475 IMediaEventSink_Release(presenter->event_sink);
476 presenter->clock = NULL;
477 presenter->mixer = NULL;
478 presenter->event_sink = NULL;
481 static ULONG WINAPI video_presenter_inner_Release(IUnknown *iface)
483 struct video_presenter *presenter = impl_from_IUnknown(iface);
484 ULONG refcount = InterlockedDecrement(&presenter->refcount);
486 TRACE("%p, refcount %u.\n", iface, refcount);
488 if (!refcount)
490 video_presenter_end_streaming(presenter);
491 video_presenter_clear_container(presenter);
492 video_presenter_reset_media_type(presenter);
493 DeleteCriticalSection(&presenter->cs);
494 if (presenter->device_manager)
495 IDirect3DDeviceManager9_Release(presenter->device_manager);
496 if (presenter->allocator)
497 IMFVideoSampleAllocator_Release(presenter->allocator);
498 heap_free(presenter);
501 return refcount;
504 static const IUnknownVtbl video_presenter_inner_vtbl =
506 video_presenter_inner_QueryInterface,
507 video_presenter_inner_AddRef,
508 video_presenter_inner_Release,
511 static HRESULT WINAPI video_presenter_QueryInterface(IMFVideoPresenter *iface, REFIID riid, void **obj)
513 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
514 return IUnknown_QueryInterface(presenter->outer_unk, riid, obj);
517 static ULONG WINAPI video_presenter_AddRef(IMFVideoPresenter *iface)
519 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
520 return IUnknown_AddRef(presenter->outer_unk);
523 static ULONG WINAPI video_presenter_Release(IMFVideoPresenter *iface)
525 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
526 return IUnknown_Release(presenter->outer_unk);
529 static HRESULT WINAPI video_presenter_OnClockStart(IMFVideoPresenter *iface, MFTIME systime, LONGLONG offset)
531 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
533 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), wine_dbgstr_longlong(offset));
535 EnterCriticalSection(&presenter->cs);
536 presenter->state = PRESENTER_STATE_STARTED;
537 LeaveCriticalSection(&presenter->cs);
539 return S_OK;
542 static HRESULT WINAPI video_presenter_OnClockStop(IMFVideoPresenter *iface, MFTIME systime)
544 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
546 TRACE("%p, %s.\n", iface, debugstr_time(systime));
548 EnterCriticalSection(&presenter->cs);
549 presenter->state = PRESENTER_STATE_STOPPED;
550 LeaveCriticalSection(&presenter->cs);
552 return S_OK;
555 static HRESULT WINAPI video_presenter_OnClockPause(IMFVideoPresenter *iface, MFTIME systime)
557 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
559 TRACE("%p, %s.\n", iface, debugstr_time(systime));
561 EnterCriticalSection(&presenter->cs);
562 presenter->state = PRESENTER_STATE_PAUSED;
563 LeaveCriticalSection(&presenter->cs);
565 return S_OK;
568 static HRESULT WINAPI video_presenter_OnClockRestart(IMFVideoPresenter *iface, MFTIME systime)
570 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
572 TRACE("%p, %s.\n", iface, debugstr_time(systime));
574 EnterCriticalSection(&presenter->cs);
575 presenter->state = PRESENTER_STATE_STARTED;
576 LeaveCriticalSection(&presenter->cs);
578 return S_OK;
581 static HRESULT WINAPI video_presenter_OnClockSetRate(IMFVideoPresenter *iface, MFTIME systime, float rate)
583 FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
585 return E_NOTIMPL;
588 static HRESULT WINAPI video_presenter_ProcessMessage(IMFVideoPresenter *iface, MFVP_MESSAGE_TYPE message, ULONG_PTR param)
590 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
591 HRESULT hr;
593 TRACE("%p, %d, %lu.\n", iface, message, param);
595 EnterCriticalSection(&presenter->cs);
597 switch (message)
599 case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
600 hr = video_presenter_invalidate_media_type(presenter);
601 break;
602 case MFVP_MESSAGE_BEGINSTREAMING:
603 hr = video_presenter_start_streaming(presenter);
604 break;
605 case MFVP_MESSAGE_ENDSTREAMING:
606 hr = video_presenter_end_streaming(presenter);
607 break;
608 case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
609 presenter->flags |= PRESENTER_MIXER_HAS_INPUT;
610 hr = video_presenter_process_input(presenter);
611 break;
612 default:
613 FIXME("Unsupported message %u.\n", message);
614 hr = E_NOTIMPL;
617 LeaveCriticalSection(&presenter->cs);
619 return hr;
622 static HRESULT WINAPI video_presenter_GetCurrentMediaType(IMFVideoPresenter *iface,
623 IMFVideoMediaType **media_type)
625 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
626 HRESULT hr;
628 TRACE("%p, %p.\n", iface, media_type);
630 EnterCriticalSection(&presenter->cs);
632 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
633 hr = MF_E_SHUTDOWN;
634 else if (!presenter->media_type)
635 hr = MF_E_NOT_INITIALIZED;
636 else
638 hr = IMFMediaType_QueryInterface(presenter->media_type, &IID_IMFVideoMediaType,
639 (void **)media_type);
642 LeaveCriticalSection(&presenter->cs);
644 return hr;
647 static const IMFVideoPresenterVtbl video_presenter_vtbl =
649 video_presenter_QueryInterface,
650 video_presenter_AddRef,
651 video_presenter_Release,
652 video_presenter_OnClockStart,
653 video_presenter_OnClockStop,
654 video_presenter_OnClockPause,
655 video_presenter_OnClockRestart,
656 video_presenter_OnClockSetRate,
657 video_presenter_ProcessMessage,
658 video_presenter_GetCurrentMediaType,
661 static HRESULT WINAPI video_presenter_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
663 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
664 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
667 static ULONG WINAPI video_presenter_device_id_AddRef(IMFVideoDeviceID *iface)
669 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
670 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
673 static ULONG WINAPI video_presenter_device_id_Release(IMFVideoDeviceID *iface)
675 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
676 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
679 static HRESULT WINAPI video_presenter_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
681 TRACE("%p, %p.\n", iface, device_id);
683 if (!device_id)
684 return E_POINTER;
686 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
688 return S_OK;
691 static const IMFVideoDeviceIDVtbl video_presenter_device_id_vtbl =
693 video_presenter_device_id_QueryInterface,
694 video_presenter_device_id_AddRef,
695 video_presenter_device_id_Release,
696 video_presenter_device_id_GetDeviceID,
699 static HRESULT WINAPI video_presenter_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
700 REFIID riid, void **obj)
702 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
703 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
706 static ULONG WINAPI video_presenter_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
708 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
709 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
712 static ULONG WINAPI video_presenter_service_client_Release(IMFTopologyServiceLookupClient *iface)
714 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
715 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
718 static void video_presenter_set_mixer_rect(struct video_presenter *presenter)
720 IMFAttributes *attributes;
721 HRESULT hr;
723 if (!presenter->mixer)
724 return;
726 if (SUCCEEDED(IMFTransform_GetAttributes(presenter->mixer, &attributes)))
728 if (FAILED(hr = IMFAttributes_SetBlob(attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&presenter->src_rect,
729 sizeof(presenter->src_rect))))
731 WARN("Failed to set zoom rectangle attribute, hr %#x.\n", hr);
733 IMFAttributes_Release(attributes);
737 static HRESULT video_presenter_attach_mixer(struct video_presenter *presenter, IMFTopologyServiceLookup *service_lookup)
739 IMFVideoDeviceID *device_id;
740 unsigned int count;
741 GUID id = { 0 };
742 HRESULT hr;
744 count = 1;
745 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
746 &MR_VIDEO_MIXER_SERVICE, &IID_IMFTransform, (void **)&presenter->mixer, &count)))
748 WARN("Failed to get mixer interface, hr %#x.\n", hr);
749 return hr;
752 if (SUCCEEDED(hr = IMFTransform_QueryInterface(presenter->mixer, &IID_IMFVideoDeviceID, (void **)&device_id)))
754 if (SUCCEEDED(hr = IMFVideoDeviceID_GetDeviceID(device_id, &id)))
756 if (!IsEqualGUID(&id, &IID_IDirect3DDevice9))
757 hr = MF_E_INVALIDREQUEST;
760 IMFVideoDeviceID_Release(device_id);
763 if (FAILED(hr))
765 IMFTransform_Release(presenter->mixer);
766 presenter->mixer = NULL;
769 video_presenter_set_mixer_rect(presenter);
770 video_presenter_get_native_video_size(presenter);
772 return hr;
775 static HRESULT WINAPI video_presenter_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
776 IMFTopologyServiceLookup *service_lookup)
778 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
779 unsigned int count;
780 HRESULT hr = S_OK;
782 TRACE("%p, %p.\n", iface, service_lookup);
784 if (!service_lookup)
785 return E_POINTER;
787 EnterCriticalSection(&presenter->cs);
789 if (presenter->state == PRESENTER_STATE_STARTED ||
790 presenter->state == PRESENTER_STATE_PAUSED)
792 hr = MF_E_INVALIDREQUEST;
794 else
796 video_presenter_clear_container(presenter);
798 count = 1;
799 IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
800 &MR_VIDEO_RENDER_SERVICE, &IID_IMFClock, (void **)&presenter->clock, &count);
802 hr = video_presenter_attach_mixer(presenter, service_lookup);
804 if (SUCCEEDED(hr))
806 count = 1;
807 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
808 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&presenter->event_sink, &count)))
810 WARN("Failed to get renderer event sink, hr %#x.\n", hr);
814 if (SUCCEEDED(hr))
815 presenter->state = PRESENTER_STATE_STOPPED;
818 LeaveCriticalSection(&presenter->cs);
820 return hr;
823 static HRESULT WINAPI video_presenter_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
825 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
827 TRACE("%p.\n", iface);
829 EnterCriticalSection(&presenter->cs);
831 presenter->state = PRESENTER_STATE_SHUT_DOWN;
832 video_presenter_clear_container(presenter);
834 LeaveCriticalSection(&presenter->cs);
836 return S_OK;
839 static const IMFTopologyServiceLookupClientVtbl video_presenter_service_client_vtbl =
841 video_presenter_service_client_QueryInterface,
842 video_presenter_service_client_AddRef,
843 video_presenter_service_client_Release,
844 video_presenter_service_client_InitServicePointers,
845 video_presenter_service_client_ReleaseServicePointers,
848 static HRESULT WINAPI video_presenter_control_QueryInterface(IMFVideoDisplayControl *iface, REFIID riid, void **obj)
850 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
851 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
854 static ULONG WINAPI video_presenter_control_AddRef(IMFVideoDisplayControl *iface)
856 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
857 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
860 static ULONG WINAPI video_presenter_control_Release(IMFVideoDisplayControl *iface)
862 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
863 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
866 static HRESULT WINAPI video_presenter_control_GetNativeVideoSize(IMFVideoDisplayControl *iface, SIZE *video_size,
867 SIZE *aspect_ratio)
869 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
871 TRACE("%p, %p, %p.\n", iface, video_size, aspect_ratio);
873 if (!video_size && !aspect_ratio)
874 return E_POINTER;
876 EnterCriticalSection(&presenter->cs);
877 if (video_size)
878 *video_size = presenter->native_size;
879 if (aspect_ratio)
880 *aspect_ratio = presenter->native_ratio;
881 LeaveCriticalSection(&presenter->cs);
883 return S_OK;
886 static HRESULT WINAPI video_presenter_control_GetIdealVideoSize(IMFVideoDisplayControl *iface, SIZE *min_size,
887 SIZE *max_size)
889 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
891 return E_NOTIMPL;
894 static HRESULT WINAPI video_presenter_control_SetVideoPosition(IMFVideoDisplayControl *iface,
895 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect)
897 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
898 HRESULT hr = S_OK;
900 TRACE("%p, %p, %s.\n", iface, src_rect, wine_dbgstr_rect(dst_rect));
902 if (!src_rect && !dst_rect)
903 return E_POINTER;
905 if (src_rect && (src_rect->left < 0.0f || src_rect->top < 0.0f ||
906 src_rect->right > 1.0f || src_rect->bottom > 1.0f ||
907 src_rect->left > src_rect->right ||
908 src_rect->top > src_rect->bottom))
910 return E_INVALIDARG;
913 if (dst_rect && (dst_rect->left > dst_rect->right ||
914 dst_rect->top > dst_rect->bottom))
915 return E_INVALIDARG;
917 EnterCriticalSection(&presenter->cs);
918 if (!presenter->video_window)
919 hr = E_POINTER;
920 else
922 if (src_rect)
924 if (memcmp(&presenter->src_rect, src_rect, sizeof(*src_rect)))
926 presenter->src_rect = *src_rect;
927 video_presenter_set_mixer_rect(presenter);
930 if (dst_rect)
931 presenter->dst_rect = *dst_rect;
933 LeaveCriticalSection(&presenter->cs);
935 return hr;
938 static HRESULT WINAPI video_presenter_control_GetVideoPosition(IMFVideoDisplayControl *iface, MFVideoNormalizedRect *src_rect,
939 RECT *dst_rect)
941 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
943 TRACE("%p, %p, %p.\n", iface, src_rect, dst_rect);
945 if (!src_rect || !dst_rect)
946 return E_POINTER;
948 EnterCriticalSection(&presenter->cs);
949 *src_rect = presenter->src_rect;
950 *dst_rect = presenter->dst_rect;
951 LeaveCriticalSection(&presenter->cs);
953 return S_OK;
956 static HRESULT WINAPI video_presenter_control_SetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD mode)
958 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
960 TRACE("%p, %#x.\n", iface, mode);
962 if (mode & ~MFVideoARMode_Mask)
963 return E_INVALIDARG;
965 EnterCriticalSection(&presenter->cs);
966 presenter->ar_mode = mode;
967 LeaveCriticalSection(&presenter->cs);
969 return S_OK;
972 static HRESULT WINAPI video_presenter_control_GetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD *mode)
974 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
976 TRACE("%p, %p.\n", iface, mode);
978 if (!mode)
979 return E_POINTER;
981 EnterCriticalSection(&presenter->cs);
982 *mode = presenter->ar_mode;
983 LeaveCriticalSection(&presenter->cs);
985 return S_OK;
988 static HRESULT WINAPI video_presenter_control_SetVideoWindow(IMFVideoDisplayControl *iface, HWND window)
990 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
992 TRACE("%p, %p.\n", iface, window);
994 if (!IsWindow(window))
995 return E_INVALIDARG;
997 EnterCriticalSection(&presenter->cs);
998 presenter->video_window = window;
999 LeaveCriticalSection(&presenter->cs);
1001 return S_OK;
1004 static HRESULT WINAPI video_presenter_control_GetVideoWindow(IMFVideoDisplayControl *iface, HWND *window)
1006 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1008 TRACE("%p, %p.\n", iface, window);
1010 if (!window)
1011 return E_POINTER;
1013 EnterCriticalSection(&presenter->cs);
1014 *window = presenter->video_window;
1015 LeaveCriticalSection(&presenter->cs);
1017 return S_OK;
1020 static HRESULT WINAPI video_presenter_control_RepaintVideo(IMFVideoDisplayControl *iface)
1022 FIXME("%p.\n", iface);
1024 return E_NOTIMPL;
1027 static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayControl *iface, BITMAPINFOHEADER *header,
1028 BYTE **dib, DWORD *dib_size, LONGLONG *timestamp)
1030 FIXME("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp);
1032 return E_NOTIMPL;
1035 static HRESULT WINAPI video_presenter_control_SetBorderColor(IMFVideoDisplayControl *iface, COLORREF color)
1037 FIXME("%p, %#x.\n", iface, color);
1039 return E_NOTIMPL;
1042 static HRESULT WINAPI video_presenter_control_GetBorderColor(IMFVideoDisplayControl *iface, COLORREF *color)
1044 FIXME("%p, %p.\n", iface, color);
1046 return E_NOTIMPL;
1049 static HRESULT WINAPI video_presenter_control_SetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD flags)
1051 FIXME("%p, %#x.\n", iface, flags);
1053 return E_NOTIMPL;
1056 static HRESULT WINAPI video_presenter_control_GetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD *flags)
1058 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1060 TRACE("%p, %p.\n", iface, flags);
1062 if (!flags)
1063 return E_POINTER;
1065 EnterCriticalSection(&presenter->cs);
1066 *flags = presenter->rendering_prefs;
1067 LeaveCriticalSection(&presenter->cs);
1069 return S_OK;
1072 static HRESULT WINAPI video_presenter_control_SetFullscreen(IMFVideoDisplayControl *iface, BOOL fullscreen)
1074 FIXME("%p, %d.\n", iface, fullscreen);
1076 return E_NOTIMPL;
1079 static HRESULT WINAPI video_presenter_control_GetFullscreen(IMFVideoDisplayControl *iface, BOOL *fullscreen)
1081 FIXME("%p, %p.\n", iface, fullscreen);
1083 return E_NOTIMPL;
1086 static const IMFVideoDisplayControlVtbl video_presenter_control_vtbl =
1088 video_presenter_control_QueryInterface,
1089 video_presenter_control_AddRef,
1090 video_presenter_control_Release,
1091 video_presenter_control_GetNativeVideoSize,
1092 video_presenter_control_GetIdealVideoSize,
1093 video_presenter_control_SetVideoPosition,
1094 video_presenter_control_GetVideoPosition,
1095 video_presenter_control_SetAspectRatioMode,
1096 video_presenter_control_GetAspectRatioMode,
1097 video_presenter_control_SetVideoWindow,
1098 video_presenter_control_GetVideoWindow,
1099 video_presenter_control_RepaintVideo,
1100 video_presenter_control_GetCurrentImage,
1101 video_presenter_control_SetBorderColor,
1102 video_presenter_control_GetBorderColor,
1103 video_presenter_control_SetRenderingPrefs,
1104 video_presenter_control_GetRenderingPrefs,
1105 video_presenter_control_SetFullscreen,
1106 video_presenter_control_GetFullscreen,
1109 static HRESULT WINAPI video_presenter_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1111 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1112 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1115 static ULONG WINAPI video_presenter_rate_support_AddRef(IMFRateSupport *iface)
1117 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1118 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1121 static ULONG WINAPI video_presenter_rate_support_Release(IMFRateSupport *iface)
1123 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1124 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1127 static HRESULT WINAPI video_presenter_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1128 BOOL thin, float *rate)
1130 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1132 *rate = 0.0f;
1134 return S_OK;
1137 static HRESULT WINAPI video_presenter_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1138 BOOL thin, float *rate)
1140 return E_NOTIMPL;
1143 static HRESULT WINAPI video_presenter_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1144 float *nearest_supported_rate)
1146 return E_NOTIMPL;
1149 static const IMFRateSupportVtbl video_presenter_rate_support_vtbl =
1151 video_presenter_rate_support_QueryInterface,
1152 video_presenter_rate_support_AddRef,
1153 video_presenter_rate_support_Release,
1154 video_presenter_rate_support_GetSlowestRate,
1155 video_presenter_rate_support_GetFastestRate,
1156 video_presenter_rate_support_IsRateSupported,
1159 static HRESULT WINAPI video_presenter_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1161 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1162 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1165 static ULONG WINAPI video_presenter_getservice_AddRef(IMFGetService *iface)
1167 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1168 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1171 static ULONG WINAPI video_presenter_getservice_Release(IMFGetService *iface)
1173 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1174 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1177 static HRESULT WINAPI video_presenter_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1179 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1181 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1183 if (IsEqualGUID(&MR_VIDEO_ACCELERATION_SERVICE, service))
1184 return IDirect3DDeviceManager9_QueryInterface(presenter->device_manager, riid, obj);
1186 if (IsEqualGUID(&MR_VIDEO_RENDER_SERVICE, service))
1188 if (IsEqualIID(riid, &IID_IMFVideoDisplayControl) ||
1189 IsEqualIID(riid, &IID_IMFVideoPositionMapper))
1191 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1193 else
1195 FIXME("Unsupported interface %s.\n", debugstr_guid(riid));
1196 return E_NOTIMPL;
1200 FIXME("Unimplemented service %s.\n", debugstr_guid(service));
1202 return E_NOTIMPL;
1205 static const IMFGetServiceVtbl video_presenter_getservice_vtbl =
1207 video_presenter_getservice_QueryInterface,
1208 video_presenter_getservice_AddRef,
1209 video_presenter_getservice_Release,
1210 video_presenter_getservice_GetService,
1213 static HRESULT WINAPI video_presenter_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1215 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1216 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1219 static ULONG WINAPI video_presenter_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1221 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1222 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1225 static ULONG WINAPI video_presenter_position_mapper_Release(IMFVideoPositionMapper *iface)
1227 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1228 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1231 static HRESULT WINAPI video_presenter_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1232 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1234 FIXME("%p, %f, %f, %u, %u, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1236 return E_NOTIMPL;
1239 static const IMFVideoPositionMapperVtbl video_presenter_position_mapper_vtbl =
1241 video_presenter_position_mapper_QueryInterface,
1242 video_presenter_position_mapper_AddRef,
1243 video_presenter_position_mapper_Release,
1244 video_presenter_position_mapper_MapOutputCoordinateToInputStream,
1247 static HRESULT WINAPI video_presenter_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1248 REFIID riid, void **obj)
1250 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1251 IsEqualIID(riid, &IID_IUnknown))
1253 *obj = iface;
1254 IMFVideoSampleAllocatorNotify_AddRef(iface);
1255 return S_OK;
1258 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1259 *obj = NULL;
1260 return E_NOINTERFACE;
1263 static ULONG WINAPI video_presenter_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1265 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1266 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1269 static ULONG WINAPI video_presenter_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1271 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1272 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1275 static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1277 return E_NOTIMPL;
1280 static const IMFVideoSampleAllocatorNotifyVtbl video_presenter_allocator_cb_vtbl =
1282 video_presenter_allocator_cb_QueryInterface,
1283 video_presenter_allocator_cb_AddRef,
1284 video_presenter_allocator_cb_Release,
1285 video_presenter_allocator_cb_NotifyRelease,
1288 HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
1290 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
1292 *obj = NULL;
1294 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
1295 return E_INVALIDARG;
1297 return CoCreateInstance(&CLSID_MFVideoPresenter9, owner, CLSCTX_INPROC_SERVER, riid, obj);
1300 static HRESULT video_presenter_init_d3d(struct video_presenter *presenter)
1302 D3DPRESENT_PARAMETERS present_params = { 0 };
1303 IDirect3DDevice9 *device;
1304 IDirect3D9 *d3d;
1305 HRESULT hr;
1307 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1309 present_params.BackBufferCount = 1;
1310 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
1311 present_params.hDeviceWindow = GetDesktopWindow();
1312 present_params.Windowed = TRUE;
1313 present_params.Flags = D3DPRESENTFLAG_VIDEO;
1314 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1315 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
1316 0, &present_params, &device);
1318 IDirect3D9_Release(d3d);
1320 if (FAILED(hr))
1322 WARN("Failed to create d3d device, hr %#x.\n", hr);
1323 return hr;
1326 hr = IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, presenter->reset_token);
1327 IDirect3DDevice9_Release(device);
1328 if (FAILED(hr))
1329 WARN("Failed to set new device for the manager, hr %#x.\n", hr);
1331 if (SUCCEEDED(hr = MFCreateVideoSampleAllocator(&IID_IMFVideoSampleAllocator, (void **)&presenter->allocator)))
1333 hr = IMFVideoSampleAllocator_SetDirectXManager(presenter->allocator, (IUnknown *)presenter->device_manager);
1336 return hr;
1339 HRESULT evr_presenter_create(IUnknown *outer, void **out)
1341 struct video_presenter *object;
1342 HRESULT hr;
1344 *out = NULL;
1346 if (!(object = heap_alloc_zero(sizeof(*object))))
1347 return E_OUTOFMEMORY;
1349 object->IMFVideoPresenter_iface.lpVtbl = &video_presenter_vtbl;
1350 object->IMFVideoDeviceID_iface.lpVtbl = &video_presenter_device_id_vtbl;
1351 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_presenter_service_client_vtbl;
1352 object->IMFVideoDisplayControl_iface.lpVtbl = &video_presenter_control_vtbl;
1353 object->IMFRateSupport_iface.lpVtbl = &video_presenter_rate_support_vtbl;
1354 object->IMFGetService_iface.lpVtbl = &video_presenter_getservice_vtbl;
1355 object->IMFVideoPositionMapper_iface.lpVtbl = &video_presenter_position_mapper_vtbl;
1356 object->allocator_cb.lpVtbl = &video_presenter_allocator_cb_vtbl;
1357 object->IUnknown_inner.lpVtbl = &video_presenter_inner_vtbl;
1358 object->outer_unk = outer ? outer : &object->IUnknown_inner;
1359 object->refcount = 1;
1360 object->src_rect.right = object->src_rect.bottom = 1.0f;
1361 object->ar_mode = MFVideoARMode_PreservePicture | MFVideoARMode_PreservePixel;
1362 InitializeCriticalSection(&object->cs);
1364 if (FAILED(hr = DXVA2CreateDirect3DDeviceManager9(&object->reset_token, &object->device_manager)))
1365 goto failed;
1367 if (FAILED(hr = video_presenter_init_d3d(object)))
1368 goto failed;
1370 *out = &object->IUnknown_inner;
1372 return S_OK;
1374 failed:
1376 IUnknown_Release(&object->IUnknown_inner);
1378 return hr;