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
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
);
37 PRESENTER_STATE_SHUT_DOWN
= 0,
38 PRESENTER_STATE_STARTED
,
39 PRESENTER_STATE_STOPPED
,
40 PRESENTER_STATE_PAUSED
,
45 PRESENTER_MIXER_HAS_INPUT
= 0x1,
48 enum streaming_thread_message
53 struct streaming_thread
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
;
76 IMediaEventSink
*event_sink
;
78 IDirect3DDeviceManager9
*device_manager
;
79 IMFVideoSampleAllocator
*allocator
;
80 struct streaming_thread thread
;
81 IMFMediaType
*media_type
;
84 MFVideoNormalizedRect src_rect
;
86 DWORD rendering_prefs
;
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
)
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
)
172 if (FAILED(IMFTransform_GetInputCurrentType(presenter
->mixer
, 0, &media_type
)))
175 if (SUCCEEDED(IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
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
)
221 video_presenter_reset_media_type(presenter
);
225 if (presenter
->media_type
&& IMFMediaType_IsEqual(presenter
->media_type
, media_type
, &flags
) == 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
);
236 WARN("Failed to initialize sample allocator, hr %#x.\n", hr
);
241 static HRESULT
video_presenter_invalidate_media_type(struct video_presenter
*presenter
)
243 IMFMediaType
*media_type
;
244 unsigned int idx
= 0;
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
);
258 hr
= video_presenter_set_media_type(presenter
, media_type
);
261 hr
= IMFTransform_SetOutputType(presenter
->mixer
, 0, media_type
, 0);
263 IMFMediaType_Release(media_type
);
272 static DWORD CALLBACK
video_presenter_streaming_thread(void *arg
)
274 struct video_presenter
*presenter
= arg
;
275 BOOL stop_thread
= FALSE
;
278 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
280 SetEvent(presenter
->thread
.ready_event
);
284 MsgWaitForMultipleObjects(0, NULL
, FALSE
, INFINITE
, QS_POSTMESSAGE
);
286 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
))
303 static HRESULT
video_presenter_start_streaming(struct video_presenter
*presenter
)
305 if (presenter
->thread
.hthread
)
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
;
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
);
331 static HRESULT
video_presenter_end_streaming(struct video_presenter
*presenter
)
333 if (!presenter
->thread
.hthread
)
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
);
349 static HRESULT
video_presenter_process_input(struct video_presenter
*presenter
)
351 MFT_OUTPUT_DATA_BUFFER buffer
;
356 if (!presenter
->media_type
)
361 LONGLONG mixing_started
, mixing_finished
;
364 if (!(presenter
->flags
& PRESENTER_MIXER_HAS_INPUT
))
367 if (FAILED(hr
= IMFVideoSampleAllocator_AllocateSample(presenter
->allocator
, &sample
)))
369 WARN("Failed to allocate a sample, hr %#x.\n", hr
);
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
);
388 if (presenter
->clock
)
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);
398 IMFCollection_Release(buffer
.pEvents
);
400 /* FIXME: for now drop output sample back to the pool */
401 IMFSample_Release(sample
);
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
))
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
;
449 WARN("Unimplemented interface %s.\n", debugstr_guid(riid
));
451 return E_NOINTERFACE
;
454 IUnknown_AddRef((IUnknown
*)*obj
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
581 static HRESULT WINAPI
video_presenter_OnClockSetRate(IMFVideoPresenter
*iface
, MFTIME systime
, float rate
)
583 FIXME("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
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
);
593 TRACE("%p, %d, %lu.\n", iface
, message
, param
);
595 EnterCriticalSection(&presenter
->cs
);
599 case MFVP_MESSAGE_INVALIDATEMEDIATYPE
:
600 hr
= video_presenter_invalidate_media_type(presenter
);
602 case MFVP_MESSAGE_BEGINSTREAMING
:
603 hr
= video_presenter_start_streaming(presenter
);
605 case MFVP_MESSAGE_ENDSTREAMING
:
606 hr
= video_presenter_end_streaming(presenter
);
608 case MFVP_MESSAGE_PROCESSINPUTNOTIFY
:
609 presenter
->flags
|= PRESENTER_MIXER_HAS_INPUT
;
610 hr
= video_presenter_process_input(presenter
);
613 FIXME("Unsupported message %u.\n", message
);
617 LeaveCriticalSection(&presenter
->cs
);
622 static HRESULT WINAPI
video_presenter_GetCurrentMediaType(IMFVideoPresenter
*iface
,
623 IMFVideoMediaType
**media_type
)
625 struct video_presenter
*presenter
= impl_from_IMFVideoPresenter(iface
);
628 TRACE("%p, %p.\n", iface
, media_type
);
630 EnterCriticalSection(&presenter
->cs
);
632 if (presenter
->state
== PRESENTER_STATE_SHUT_DOWN
)
634 else if (!presenter
->media_type
)
635 hr
= MF_E_NOT_INITIALIZED
;
638 hr
= IMFMediaType_QueryInterface(presenter
->media_type
, &IID_IMFVideoMediaType
,
639 (void **)media_type
);
642 LeaveCriticalSection(&presenter
->cs
);
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
);
686 memcpy(device_id
, &IID_IDirect3DDevice9
, sizeof(*device_id
));
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
;
723 if (!presenter
->mixer
)
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
;
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
);
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
);
765 IMFTransform_Release(presenter
->mixer
);
766 presenter
->mixer
= NULL
;
769 video_presenter_set_mixer_rect(presenter
);
770 video_presenter_get_native_video_size(presenter
);
775 static HRESULT WINAPI
video_presenter_service_client_InitServicePointers(IMFTopologyServiceLookupClient
*iface
,
776 IMFTopologyServiceLookup
*service_lookup
)
778 struct video_presenter
*presenter
= impl_from_IMFTopologyServiceLookupClient(iface
);
782 TRACE("%p, %p.\n", iface
, service_lookup
);
787 EnterCriticalSection(&presenter
->cs
);
789 if (presenter
->state
== PRESENTER_STATE_STARTED
||
790 presenter
->state
== PRESENTER_STATE_PAUSED
)
792 hr
= MF_E_INVALIDREQUEST
;
796 video_presenter_clear_container(presenter
);
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
);
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
);
815 presenter
->state
= PRESENTER_STATE_STOPPED
;
818 LeaveCriticalSection(&presenter
->cs
);
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
);
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
,
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
)
876 EnterCriticalSection(&presenter
->cs
);
878 *video_size
= presenter
->native_size
;
880 *aspect_ratio
= presenter
->native_ratio
;
881 LeaveCriticalSection(&presenter
->cs
);
886 static HRESULT WINAPI
video_presenter_control_GetIdealVideoSize(IMFVideoDisplayControl
*iface
, SIZE
*min_size
,
889 FIXME("%p, %p, %p.\n", iface
, min_size
, max_size
);
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
);
900 TRACE("%p, %p, %s.\n", iface
, src_rect
, wine_dbgstr_rect(dst_rect
));
902 if (!src_rect
&& !dst_rect
)
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
))
913 if (dst_rect
&& (dst_rect
->left
> dst_rect
->right
||
914 dst_rect
->top
> dst_rect
->bottom
))
917 EnterCriticalSection(&presenter
->cs
);
918 if (!presenter
->video_window
)
924 if (memcmp(&presenter
->src_rect
, src_rect
, sizeof(*src_rect
)))
926 presenter
->src_rect
= *src_rect
;
927 video_presenter_set_mixer_rect(presenter
);
931 presenter
->dst_rect
= *dst_rect
;
933 LeaveCriticalSection(&presenter
->cs
);
938 static HRESULT WINAPI
video_presenter_control_GetVideoPosition(IMFVideoDisplayControl
*iface
, MFVideoNormalizedRect
*src_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
)
948 EnterCriticalSection(&presenter
->cs
);
949 *src_rect
= presenter
->src_rect
;
950 *dst_rect
= presenter
->dst_rect
;
951 LeaveCriticalSection(&presenter
->cs
);
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
)
965 EnterCriticalSection(&presenter
->cs
);
966 presenter
->ar_mode
= mode
;
967 LeaveCriticalSection(&presenter
->cs
);
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
);
981 EnterCriticalSection(&presenter
->cs
);
982 *mode
= presenter
->ar_mode
;
983 LeaveCriticalSection(&presenter
->cs
);
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
))
997 EnterCriticalSection(&presenter
->cs
);
998 presenter
->video_window
= window
;
999 LeaveCriticalSection(&presenter
->cs
);
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
);
1013 EnterCriticalSection(&presenter
->cs
);
1014 *window
= presenter
->video_window
;
1015 LeaveCriticalSection(&presenter
->cs
);
1020 static HRESULT WINAPI
video_presenter_control_RepaintVideo(IMFVideoDisplayControl
*iface
)
1022 FIXME("%p.\n", iface
);
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
);
1035 static HRESULT WINAPI
video_presenter_control_SetBorderColor(IMFVideoDisplayControl
*iface
, COLORREF color
)
1037 FIXME("%p, %#x.\n", iface
, color
);
1042 static HRESULT WINAPI
video_presenter_control_GetBorderColor(IMFVideoDisplayControl
*iface
, COLORREF
*color
)
1044 FIXME("%p, %p.\n", iface
, color
);
1049 static HRESULT WINAPI
video_presenter_control_SetRenderingPrefs(IMFVideoDisplayControl
*iface
, DWORD flags
)
1051 FIXME("%p, %#x.\n", iface
, flags
);
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
);
1065 EnterCriticalSection(&presenter
->cs
);
1066 *flags
= presenter
->rendering_prefs
;
1067 LeaveCriticalSection(&presenter
->cs
);
1072 static HRESULT WINAPI
video_presenter_control_SetFullscreen(IMFVideoDisplayControl
*iface
, BOOL fullscreen
)
1074 FIXME("%p, %d.\n", iface
, fullscreen
);
1079 static HRESULT WINAPI
video_presenter_control_GetFullscreen(IMFVideoDisplayControl
*iface
, BOOL
*fullscreen
)
1081 FIXME("%p, %p.\n", iface
, fullscreen
);
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
);
1137 static HRESULT WINAPI
video_presenter_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1138 BOOL thin
, float *rate
)
1143 static HRESULT WINAPI
video_presenter_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1144 float *nearest_supported_rate
)
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
);
1195 FIXME("Unsupported interface %s.\n", debugstr_guid(riid
));
1200 FIXME("Unimplemented service %s.\n", debugstr_guid(service
));
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
);
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
))
1254 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1258 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
)
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
);
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
;
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
);
1322 WARN("Failed to create d3d device, hr %#x.\n", hr
);
1326 hr
= IDirect3DDeviceManager9_ResetDevice(presenter
->device_manager
, device
, presenter
->reset_token
);
1327 IDirect3DDevice9_Release(device
);
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
);
1339 HRESULT
evr_presenter_create(IUnknown
*outer
, void **out
)
1341 struct video_presenter
*object
;
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
)))
1367 if (FAILED(hr
= video_presenter_init_d3d(object
)))
1370 *out
= &object
->IUnknown_inner
;
1376 IUnknown_Release(&object
->IUnknown_inner
);