ddraw: Move the wined3d_texture_update_desc() call into ddraw_surface_create_wined3d_...
[wine.git] / dlls / evr / presenter.c
blobd8bdbee39159cbff72f66461415d2c0d23450957
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);
35 Initial state represents just created object, presenter never returns to this state.
36 Shutdown state is entered on ReleaseServicePointers(), terminal state.
37 Started/stopped/paused states are controlled by clock state changes.
40 enum presenter_state
42 PRESENTER_STATE_INITIAL = 0,
43 PRESENTER_STATE_SHUT_DOWN,
44 PRESENTER_STATE_STARTED,
45 PRESENTER_STATE_STOPPED,
46 PRESENTER_STATE_PAUSED,
49 enum presenter_flags
51 PRESENTER_MIXER_HAS_INPUT = 0x1,
54 enum streaming_thread_message
56 EVRM_STOP = WM_USER,
57 EVRM_PRESENT = WM_USER + 1,
58 EVRM_PROCESS_INPUT = WM_USER + 2,
61 struct sample_queue
63 IMFSample **samples;
64 unsigned int size;
65 unsigned int used;
66 unsigned int front;
67 unsigned int back;
68 IMFSample *last_presented;
71 struct streaming_thread
73 HANDLE hthread;
74 HANDLE ready_event;
75 DWORD tid;
76 struct sample_queue queue;
79 struct video_presenter
81 IMFVideoPresenter IMFVideoPresenter_iface;
82 IMFVideoDeviceID IMFVideoDeviceID_iface;
83 IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
84 IMFVideoDisplayControl IMFVideoDisplayControl_iface;
85 IMFRateSupport IMFRateSupport_iface;
86 IMFGetService IMFGetService_iface;
87 IMFVideoPositionMapper IMFVideoPositionMapper_iface;
88 IQualProp IQualProp_iface;
89 IMFQualityAdvise IMFQualityAdvise_iface;
90 IMFQualityAdviseLimits IMFQualityAdviseLimits_iface;
91 IDirect3DDeviceManager9 IDirect3DDeviceManager9_iface;
92 IMFVideoSampleAllocatorNotify allocator_cb;
93 IUnknown IUnknown_inner;
94 IUnknown *outer_unk;
95 LONG refcount;
97 IMFTransform *mixer;
98 IMFClock *clock;
99 IMediaEventSink *event_sink;
101 IDirect3DDeviceManager9 *device_manager;
102 IDirect3DSwapChain9 *swapchain;
103 HANDLE hdevice;
105 IMFVideoSampleAllocator *allocator;
106 struct streaming_thread thread;
107 unsigned int allocator_capacity;
108 IMFMediaType *media_type;
109 LONGLONG frame_time_threshold;
110 UINT reset_token;
111 HWND video_window;
112 MFVideoNormalizedRect src_rect;
113 RECT dst_rect;
114 DWORD rendering_prefs;
115 SIZE native_size;
116 SIZE native_ratio;
117 unsigned int ar_mode;
118 unsigned int state;
119 unsigned int flags;
121 struct
123 int presented;
124 LONGLONG sampletime;
125 } frame_stats;
127 CRITICAL_SECTION cs;
130 static struct video_presenter *impl_from_IUnknown(IUnknown *iface)
132 return CONTAINING_RECORD(iface, struct video_presenter, IUnknown_inner);
135 static struct video_presenter *impl_from_IMFVideoPresenter(IMFVideoPresenter *iface)
137 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPresenter_iface);
140 static struct video_presenter *impl_from_IMFVideoDeviceID(IMFVideoDeviceID *iface)
142 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoDeviceID_iface);
145 static struct video_presenter *impl_from_IMFTopologyServiceLookupClient(IMFTopologyServiceLookupClient *iface)
147 return CONTAINING_RECORD(iface, struct video_presenter, IMFTopologyServiceLookupClient_iface);
150 static struct video_presenter *impl_from_IMFVideoDisplayControl(IMFVideoDisplayControl *iface)
152 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoDisplayControl_iface);
155 static struct video_presenter *impl_from_IMFRateSupport(IMFRateSupport *iface)
157 return CONTAINING_RECORD(iface, struct video_presenter, IMFRateSupport_iface);
160 static struct video_presenter *impl_from_IMFGetService(IMFGetService *iface)
162 return CONTAINING_RECORD(iface, struct video_presenter, IMFGetService_iface);
165 static struct video_presenter *impl_from_IMFVideoPositionMapper(IMFVideoPositionMapper *iface)
167 return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPositionMapper_iface);
170 static struct video_presenter *impl_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
172 return CONTAINING_RECORD(iface, struct video_presenter, allocator_cb);
175 static struct video_presenter *impl_from_IQualProp(IQualProp *iface)
177 return CONTAINING_RECORD(iface, struct video_presenter, IQualProp_iface);
180 static struct video_presenter *impl_from_IMFQualityAdvise(IMFQualityAdvise *iface)
182 return CONTAINING_RECORD(iface, struct video_presenter, IMFQualityAdvise_iface);
185 static struct video_presenter *impl_from_IMFQualityAdviseLimits(IMFQualityAdviseLimits *iface)
187 return CONTAINING_RECORD(iface, struct video_presenter, IMFQualityAdviseLimits_iface);
190 static struct video_presenter *impl_from_IDirect3DDeviceManager9(IDirect3DDeviceManager9 *iface)
192 return CONTAINING_RECORD(iface, struct video_presenter, IDirect3DDeviceManager9_iface);
195 static void video_presenter_notify_renderer(struct video_presenter *presenter,
196 LONG event, LONG_PTR param1, LONG_PTR param2)
198 if (presenter->event_sink)
199 IMediaEventSink_Notify(presenter->event_sink, event, param1, param2);
202 static unsigned int get_gcd(unsigned int a, unsigned int b)
204 unsigned int m;
206 while (b)
208 m = a % b;
209 a = b;
210 b = m;
213 return a;
216 static HRESULT video_presenter_get_device(struct video_presenter *presenter, IDirect3DDevice9 **device)
218 HRESULT hr;
220 if (!presenter->hdevice)
222 if (FAILED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(presenter->device_manager, &presenter->hdevice)))
223 return hr;
226 return IDirect3DDeviceManager9_LockDevice(presenter->device_manager, presenter->hdevice, device, TRUE);
229 static void video_presenter_get_native_video_size(struct video_presenter *presenter)
231 IMFMediaType *media_type;
232 UINT64 frame_size = 0;
234 memset(&presenter->native_size, 0, sizeof(presenter->native_size));
235 memset(&presenter->native_ratio, 0, sizeof(presenter->native_ratio));
237 if (!presenter->mixer)
238 return;
240 if (FAILED(IMFTransform_GetInputCurrentType(presenter->mixer, 0, &media_type)))
241 return;
243 if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
245 unsigned int gcd;
247 presenter->native_size.cx = frame_size >> 32;
248 presenter->native_size.cy = frame_size;
250 if ((gcd = get_gcd(presenter->native_size.cx, presenter->native_size.cy)))
252 presenter->native_ratio.cx = presenter->native_size.cx / gcd;
253 presenter->native_ratio.cy = presenter->native_size.cy / gcd;
257 IMFMediaType_Release(media_type);
260 /* It is important this is called to reset callback too to break circular referencing,
261 when allocator keeps a reference of its container, that created it. */
262 static void video_presenter_set_allocator_callback(struct video_presenter *presenter,
263 IMFVideoSampleAllocatorNotify *notify_cb)
265 IMFVideoSampleAllocatorCallback *cb;
267 IMFVideoSampleAllocator_QueryInterface(presenter->allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&cb);
268 IMFVideoSampleAllocatorCallback_SetCallback(cb, notify_cb);
269 IMFVideoSampleAllocatorCallback_Release(cb);
272 static void video_presenter_reset_media_type(struct video_presenter *presenter)
274 if (presenter->media_type)
275 IMFMediaType_Release(presenter->media_type);
276 presenter->media_type = NULL;
278 if (presenter->allocator)
280 IMFVideoSampleAllocator_UninitializeSampleAllocator(presenter->allocator);
281 video_presenter_set_allocator_callback(presenter, NULL);
285 static HRESULT video_presenter_set_media_type(struct video_presenter *presenter, IMFMediaType *media_type)
287 DWORD flags;
288 HRESULT hr;
290 if (!media_type)
292 video_presenter_reset_media_type(presenter);
293 return S_OK;
296 if (presenter->media_type && IMFMediaType_IsEqual(presenter->media_type, media_type, &flags) == S_OK)
297 return S_OK;
299 video_presenter_reset_media_type(presenter);
301 if (SUCCEEDED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(presenter->allocator,
302 presenter->allocator_capacity, media_type)))
304 MFRatio ratio;
305 UINT64 rate, frametime;
307 presenter->media_type = media_type;
308 IMFMediaType_AddRef(presenter->media_type);
310 if (SUCCEEDED(IMFMediaType_GetUINT64(presenter->media_type, &MF_MT_FRAME_RATE, &rate)))
312 ratio.Denominator = rate;
313 ratio.Numerator = rate >> 32;
315 else
317 ratio.Denominator = 1;
318 ratio.Numerator = 30;
321 MFFrameRateToAverageTimePerFrame(ratio.Numerator, ratio.Denominator, &frametime);
322 presenter->frame_time_threshold = frametime / 4;
324 else
325 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr);
327 return hr;
330 static HRESULT video_presenter_configure_output_type(struct video_presenter *presenter, const MFVideoArea *aperture,
331 IMFMediaType *media_type)
333 GUID subtype;
334 LONG stride;
335 DWORD size;
336 HRESULT hr;
338 hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)aperture->Area.cx << 32 | aperture->Area.cy);
339 if (SUCCEEDED(hr))
340 hr = IMFMediaType_SetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)aperture, sizeof(*aperture));
341 if (SUCCEEDED(hr))
342 hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 *)aperture, sizeof(*aperture));
344 if (SUCCEEDED(hr))
345 hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
347 if (SUCCEEDED(hr))
349 hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, aperture->Area.cx, &stride);
350 if (SUCCEEDED(hr))
351 hr = MFGetPlaneSize(subtype.Data1, aperture->Area.cx, aperture->Area.cy, &size);
352 if (SUCCEEDED(hr))
353 hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, abs(stride));
354 if (SUCCEEDED(hr))
355 hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, size);
358 return hr;
361 static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter)
363 IMFMediaType *media_type, *candidate_type;
364 MFVideoArea aperture = {{ 0 }};
365 unsigned int idx = 0;
366 RECT rect;
367 HRESULT hr;
369 if (!presenter->mixer)
370 return MF_E_TRANSFORM_TYPE_NOT_SET;
372 if (FAILED(hr = MFCreateMediaType(&media_type)))
373 return hr;
375 video_presenter_get_native_video_size(presenter);
377 rect = presenter->dst_rect;
378 if (rect.left == 0 && rect.right == 0 && rect.bottom == 0 && rect.top == 0)
380 rect.right = presenter->native_size.cx;
381 rect.bottom = presenter->native_size.cy;
384 aperture.Area.cx = rect.right - rect.left;
385 aperture.Area.cy = rect.bottom - rect.top;
387 while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &candidate_type)))
389 /* FIXME: check that d3d device supports this format */
391 if (FAILED(hr = IMFMediaType_CopyAllItems(candidate_type, (IMFAttributes *)media_type)))
392 WARN("Failed to clone a media type, hr %#lx.\n", hr);
393 IMFMediaType_Release(candidate_type);
395 hr = video_presenter_configure_output_type(presenter, &aperture, media_type);
397 if (SUCCEEDED(hr))
398 hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
400 if (SUCCEEDED(hr))
401 hr = video_presenter_set_media_type(presenter, media_type);
403 if (SUCCEEDED(hr))
404 hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0);
406 if (SUCCEEDED(hr))
407 break;
410 IMFMediaType_Release(media_type);
412 return hr;
415 static HRESULT video_presenter_sample_queue_init(struct video_presenter *presenter)
417 struct sample_queue *queue = &presenter->thread.queue;
419 if (queue->size)
420 return S_OK;
422 memset(queue, 0, sizeof(*queue));
423 if (!(queue->samples = calloc(presenter->allocator_capacity, sizeof(*queue->samples))))
424 return E_OUTOFMEMORY;
426 queue->size = presenter->allocator_capacity;
427 queue->back = queue->size - 1;
429 return S_OK;
432 static void video_presenter_sample_queue_push(struct video_presenter *presenter, IMFSample *sample,
433 BOOL at_front)
435 struct sample_queue *queue = &presenter->thread.queue;
436 unsigned int idx;
438 EnterCriticalSection(&presenter->cs);
439 if (queue->used != queue->size)
441 if (at_front)
442 idx = queue->front = (queue->size + queue->front - 1) % queue->size;
443 else
444 idx = queue->back = (queue->back + 1) % queue->size;
445 queue->samples[idx] = sample;
446 queue->used++;
447 IMFSample_AddRef(sample);
449 LeaveCriticalSection(&presenter->cs);
452 static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, IMFSample **sample)
454 struct sample_queue *queue = &presenter->thread.queue;
456 EnterCriticalSection(&presenter->cs);
457 if (queue->used)
459 *sample = queue->samples[queue->front];
460 queue->front = (queue->front + 1) % queue->size;
461 queue->used--;
463 else
464 *sample = NULL;
465 LeaveCriticalSection(&presenter->cs);
467 return *sample != NULL;
470 static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface)
472 IMFMediaBuffer *buffer;
473 IMFGetService *gs;
474 HRESULT hr;
476 if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer)))
477 return hr;
479 hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&gs);
480 IMFMediaBuffer_Release(buffer);
481 if (FAILED(hr))
482 return hr;
484 hr = IMFGetService_GetService(gs, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)surface);
485 IMFGetService_Release(gs);
486 return hr;
489 static void video_presenter_sample_present(struct video_presenter *presenter, IMFSample *sample)
491 IDirect3DSurface9 *surface, *backbuffer;
492 IDirect3DDevice9 *device;
493 HRESULT hr;
495 if (FAILED(hr = video_presenter_get_sample_surface(sample, &surface)))
497 WARN("Failed to get sample surface, hr %#lx.\n", hr);
498 return;
501 if (presenter->swapchain)
503 if (SUCCEEDED(hr = IDirect3DSwapChain9_GetBackBuffer(presenter->swapchain, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer)))
505 IDirect3DSwapChain9_GetDevice(presenter->swapchain, &device);
506 IDirect3DDevice9_StretchRect(device, surface, NULL, backbuffer, NULL, D3DTEXF_POINT);
508 IDirect3DSwapChain9_Present(presenter->swapchain, NULL, NULL, NULL, NULL, 0);
509 presenter->frame_stats.presented++;
511 IDirect3DDevice9_Release(device);
512 IDirect3DSurface9_Release(backbuffer);
514 else
515 WARN("Failed to get a backbuffer, hr %#lx.\n", hr);
518 EnterCriticalSection(&presenter->cs);
519 if (presenter->thread.queue.last_presented)
520 IMFSample_Release(presenter->thread.queue.last_presented);
521 presenter->thread.queue.last_presented = sample;
522 IMFSample_AddRef(presenter->thread.queue.last_presented);
523 LeaveCriticalSection(&presenter->cs);
525 IDirect3DSurface9_Release(surface);
528 static void video_presenter_check_queue(struct video_presenter *presenter,
529 unsigned int *next_wait)
531 LONGLONG pts, clocktime, delta;
532 unsigned int wait = 0;
533 IMFSample *sample;
534 MFTIME systime;
535 BOOL present;
536 HRESULT hr;
538 while (video_presenter_sample_queue_pop(presenter, &sample))
540 present = TRUE;
541 wait = 0;
543 if (presenter->clock)
545 pts = clocktime = 0;
547 hr = IMFSample_GetSampleTime(sample, &pts);
548 if (SUCCEEDED(hr))
549 hr = IMFClock_GetCorrelatedTime(presenter->clock, 0, &clocktime, &systime);
551 delta = pts - clocktime;
552 if (delta > 3 * presenter->frame_time_threshold)
554 /* Convert 100ns -> msec */
555 wait = (delta - 3 * presenter->frame_time_threshold) / 10000;
556 present = FALSE;
560 if (present)
561 video_presenter_sample_present(presenter, sample);
562 else
563 video_presenter_sample_queue_push(presenter, sample, TRUE);
565 IMFSample_Release(sample);
567 if (wait > 0)
568 break;
571 if (!wait)
572 wait = INFINITE;
574 *next_wait = wait;
577 static void video_presenter_schedule_sample(struct video_presenter *presenter, IMFSample *sample)
579 if (!presenter->thread.tid)
581 WARN("Streaming thread hasn't been started.\n");
582 return;
585 if (presenter->clock)
587 video_presenter_sample_queue_push(presenter, sample, FALSE);
588 PostThreadMessageW(presenter->thread.tid, EVRM_PRESENT, 0, 0);
590 else
592 video_presenter_sample_present(presenter, sample);
596 static HRESULT video_presenter_process_input(struct video_presenter *presenter)
598 MFT_OUTPUT_DATA_BUFFER buffer;
599 HRESULT hr = S_OK;
600 IMFSample *sample;
601 DWORD status;
603 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
604 return MF_E_SHUTDOWN;
606 if (!presenter->media_type)
607 return S_OK;
609 while (hr == S_OK)
611 LONGLONG mixing_started, mixing_finished;
612 MFTIME systime;
614 if (!(presenter->flags & PRESENTER_MIXER_HAS_INPUT))
615 break;
617 if (FAILED(hr = IMFVideoSampleAllocator_AllocateSample(presenter->allocator, &sample)))
619 WARN("Failed to allocate a sample, hr %#lx.\n", hr);
620 break;
623 memset(&buffer, 0, sizeof(buffer));
624 buffer.pSample = sample;
626 if (presenter->clock)
627 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_started, &systime);
629 if (FAILED(hr = IMFTransform_ProcessOutput(presenter->mixer, 0, 1, &buffer, &status)))
631 /* FIXME: failure path probably needs to handle some errors specifically */
632 presenter->flags &= ~PRESENTER_MIXER_HAS_INPUT;
633 IMFSample_Release(sample);
634 break;
636 else
638 if (presenter->clock)
640 LONGLONG latency;
642 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_finished, &systime);
643 latency = mixing_finished - mixing_started;
644 video_presenter_notify_renderer(presenter, EC_PROCESSING_LATENCY, (LONG_PTR)&latency, 0);
647 if (buffer.pEvents)
648 IMFCollection_Release(buffer.pEvents);
650 video_presenter_schedule_sample(presenter, sample);
652 IMFSample_Release(sample);
656 return S_OK;
659 static DWORD CALLBACK video_presenter_streaming_thread(void *arg)
661 struct video_presenter *presenter = arg;
662 unsigned int wait = INFINITE;
663 BOOL stop_thread = FALSE;
664 MSG msg;
666 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
668 SetEvent(presenter->thread.ready_event);
670 while (!stop_thread)
672 if (MsgWaitForMultipleObjects(0, NULL, FALSE, wait, QS_POSTMESSAGE) == WAIT_TIMEOUT)
673 video_presenter_check_queue(presenter, &wait);
675 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
677 BOOL peek = TRUE;
679 switch (msg.message)
681 case EVRM_STOP:
682 stop_thread = TRUE;
683 break;
685 case EVRM_PRESENT:
686 if (peek)
688 video_presenter_check_queue(presenter, &wait);
689 peek = wait != INFINITE;
691 break;
693 case EVRM_PROCESS_INPUT:
694 EnterCriticalSection(&presenter->cs);
695 video_presenter_process_input(presenter);
696 LeaveCriticalSection(&presenter->cs);
697 break;
698 default:
704 return 0;
707 static HRESULT video_presenter_start_streaming(struct video_presenter *presenter)
709 HRESULT hr;
711 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
712 return MF_E_SHUTDOWN;
714 if (presenter->thread.hthread)
715 return S_OK;
717 if (FAILED(hr = video_presenter_sample_queue_init(presenter)))
718 return hr;
720 if (!(presenter->thread.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
721 return HRESULT_FROM_WIN32(GetLastError());
723 if (!(presenter->thread.hthread = CreateThread(NULL, 0, video_presenter_streaming_thread,
724 presenter, 0, &presenter->thread.tid)))
726 WARN("Failed to create streaming thread.\n");
727 CloseHandle(presenter->thread.ready_event);
728 presenter->thread.ready_event = NULL;
729 return E_FAIL;
732 video_presenter_set_allocator_callback(presenter, &presenter->allocator_cb);
734 WaitForSingleObject(presenter->thread.ready_event, INFINITE);
735 CloseHandle(presenter->thread.ready_event);
736 presenter->thread.ready_event = NULL;
738 TRACE("Started streaming thread, tid %#lx.\n", presenter->thread.tid);
740 return S_OK;
743 static HRESULT video_presenter_end_streaming(struct video_presenter *presenter)
745 if (!presenter->thread.hthread)
746 return S_OK;
748 PostThreadMessageW(presenter->thread.tid, EVRM_STOP, 0, 0);
750 WaitForSingleObject(presenter->thread.hthread, INFINITE);
751 CloseHandle(presenter->thread.hthread);
753 TRACE("Terminated streaming thread tid %#lx.\n", presenter->thread.tid);
755 if (presenter->thread.queue.last_presented)
756 IMFSample_Release(presenter->thread.queue.last_presented);
757 memset(&presenter->thread, 0, sizeof(presenter->thread));
758 video_presenter_set_allocator_callback(presenter, NULL);
760 return S_OK;
763 static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
765 struct video_presenter *presenter = impl_from_IUnknown(iface);
767 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
769 if (IsEqualIID(riid, &IID_IUnknown))
771 *obj = iface;
773 else if (IsEqualIID(riid, &IID_IMFClockStateSink)
774 || IsEqualIID(riid, &IID_IMFVideoPresenter))
776 *obj = &presenter->IMFVideoPresenter_iface;
778 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
780 *obj = &presenter->IMFVideoDeviceID_iface;
782 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
784 *obj = &presenter->IMFTopologyServiceLookupClient_iface;
786 else if (IsEqualIID(riid, &IID_IMFVideoDisplayControl))
788 *obj = &presenter->IMFVideoDisplayControl_iface;
790 else if (IsEqualIID(riid, &IID_IMFRateSupport))
792 *obj = &presenter->IMFRateSupport_iface;
794 else if (IsEqualIID(riid, &IID_IMFGetService))
796 *obj = &presenter->IMFGetService_iface;
798 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
800 *obj = &presenter->IMFVideoPositionMapper_iface;
802 else if (IsEqualIID(riid, &IID_IQualProp))
804 *obj = &presenter->IQualProp_iface;
806 else if (IsEqualIID(riid, &IID_IMFQualityAdvise))
808 *obj = &presenter->IMFQualityAdvise_iface;
810 else if (IsEqualIID(riid, &IID_IMFQualityAdviseLimits))
812 *obj = &presenter->IMFQualityAdviseLimits_iface;
814 else if (IsEqualIID(riid, &IID_IDirect3DDeviceManager9))
816 *obj = &presenter->IDirect3DDeviceManager9_iface;
818 else
820 WARN("Unimplemented interface %s.\n", debugstr_guid(riid));
821 *obj = NULL;
822 return E_NOINTERFACE;
825 IUnknown_AddRef((IUnknown *)*obj);
826 return S_OK;
829 static ULONG WINAPI video_presenter_inner_AddRef(IUnknown *iface)
831 struct video_presenter *presenter = impl_from_IUnknown(iface);
832 ULONG refcount = InterlockedIncrement(&presenter->refcount);
834 TRACE("%p, refcount %lu.\n", iface, refcount);
836 return refcount;
839 static void video_presenter_clear_container(struct video_presenter *presenter)
841 if (presenter->clock)
842 IMFClock_Release(presenter->clock);
843 if (presenter->mixer)
844 IMFTransform_Release(presenter->mixer);
845 if (presenter->event_sink)
846 IMediaEventSink_Release(presenter->event_sink);
847 presenter->clock = NULL;
848 presenter->mixer = NULL;
849 presenter->event_sink = NULL;
852 static ULONG WINAPI video_presenter_inner_Release(IUnknown *iface)
854 struct video_presenter *presenter = impl_from_IUnknown(iface);
855 ULONG refcount = InterlockedDecrement(&presenter->refcount);
857 TRACE("%p, refcount %lu.\n", iface, refcount);
859 if (!refcount)
861 video_presenter_end_streaming(presenter);
862 video_presenter_clear_container(presenter);
863 video_presenter_reset_media_type(presenter);
864 DeleteCriticalSection(&presenter->cs);
865 if (presenter->swapchain)
866 IDirect3DSwapChain9_Release(presenter->swapchain);
867 if (presenter->device_manager)
869 IDirect3DDeviceManager9_CloseDeviceHandle(presenter->device_manager, presenter->hdevice);
870 IDirect3DDeviceManager9_Release(presenter->device_manager);
872 if (presenter->allocator)
873 IMFVideoSampleAllocator_Release(presenter->allocator);
874 free(presenter);
877 return refcount;
880 static const IUnknownVtbl video_presenter_inner_vtbl =
882 video_presenter_inner_QueryInterface,
883 video_presenter_inner_AddRef,
884 video_presenter_inner_Release,
887 static HRESULT WINAPI video_presenter_QueryInterface(IMFVideoPresenter *iface, REFIID riid, void **obj)
889 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
890 return IUnknown_QueryInterface(presenter->outer_unk, riid, obj);
893 static ULONG WINAPI video_presenter_AddRef(IMFVideoPresenter *iface)
895 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
896 return IUnknown_AddRef(presenter->outer_unk);
899 static ULONG WINAPI video_presenter_Release(IMFVideoPresenter *iface)
901 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
902 return IUnknown_Release(presenter->outer_unk);
905 static HRESULT WINAPI video_presenter_OnClockStart(IMFVideoPresenter *iface, MFTIME systime, LONGLONG offset)
907 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
909 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), wine_dbgstr_longlong(offset));
911 EnterCriticalSection(&presenter->cs);
912 presenter->state = PRESENTER_STATE_STARTED;
913 LeaveCriticalSection(&presenter->cs);
915 return S_OK;
918 static HRESULT WINAPI video_presenter_OnClockStop(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_STOPPED;
926 presenter->frame_stats.presented = 0;
927 LeaveCriticalSection(&presenter->cs);
929 return S_OK;
932 static HRESULT WINAPI video_presenter_OnClockPause(IMFVideoPresenter *iface, MFTIME systime)
934 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
936 TRACE("%p, %s.\n", iface, debugstr_time(systime));
938 EnterCriticalSection(&presenter->cs);
939 presenter->state = PRESENTER_STATE_PAUSED;
940 LeaveCriticalSection(&presenter->cs);
942 return S_OK;
945 static HRESULT WINAPI video_presenter_OnClockRestart(IMFVideoPresenter *iface, MFTIME systime)
947 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
949 TRACE("%p, %s.\n", iface, debugstr_time(systime));
951 EnterCriticalSection(&presenter->cs);
952 presenter->state = PRESENTER_STATE_STARTED;
953 LeaveCriticalSection(&presenter->cs);
955 return S_OK;
958 static HRESULT WINAPI video_presenter_OnClockSetRate(IMFVideoPresenter *iface, MFTIME systime, float rate)
960 FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
962 return E_NOTIMPL;
965 static HRESULT WINAPI video_presenter_ProcessMessage(IMFVideoPresenter *iface, MFVP_MESSAGE_TYPE message, ULONG_PTR param)
967 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
968 HRESULT hr;
970 TRACE("%p, %d, %Iu.\n", iface, message, param);
972 EnterCriticalSection(&presenter->cs);
974 switch (message)
976 case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
977 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
978 hr = MF_E_SHUTDOWN;
979 else if (!presenter->mixer)
980 hr = MF_E_INVALIDREQUEST;
981 else
982 hr = video_presenter_invalidate_media_type(presenter);
983 break;
984 case MFVP_MESSAGE_BEGINSTREAMING:
985 hr = video_presenter_start_streaming(presenter);
986 break;
987 case MFVP_MESSAGE_ENDSTREAMING:
988 hr = video_presenter_end_streaming(presenter);
989 break;
990 case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
991 presenter->flags |= PRESENTER_MIXER_HAS_INPUT;
992 hr = video_presenter_process_input(presenter);
993 break;
994 default:
995 FIXME("Unsupported message %u.\n", message);
996 hr = E_NOTIMPL;
999 LeaveCriticalSection(&presenter->cs);
1001 return hr;
1004 static HRESULT WINAPI video_presenter_GetCurrentMediaType(IMFVideoPresenter *iface,
1005 IMFVideoMediaType **media_type)
1007 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
1008 HRESULT hr;
1010 TRACE("%p, %p.\n", iface, media_type);
1012 EnterCriticalSection(&presenter->cs);
1014 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1015 hr = MF_E_SHUTDOWN;
1016 else if (!presenter->media_type)
1017 hr = MF_E_NOT_INITIALIZED;
1018 else
1020 hr = IMFMediaType_QueryInterface(presenter->media_type, &IID_IMFVideoMediaType,
1021 (void **)media_type);
1024 LeaveCriticalSection(&presenter->cs);
1026 return hr;
1029 static const IMFVideoPresenterVtbl video_presenter_vtbl =
1031 video_presenter_QueryInterface,
1032 video_presenter_AddRef,
1033 video_presenter_Release,
1034 video_presenter_OnClockStart,
1035 video_presenter_OnClockStop,
1036 video_presenter_OnClockPause,
1037 video_presenter_OnClockRestart,
1038 video_presenter_OnClockSetRate,
1039 video_presenter_ProcessMessage,
1040 video_presenter_GetCurrentMediaType,
1043 static HRESULT WINAPI video_presenter_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
1045 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1046 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1049 static ULONG WINAPI video_presenter_device_id_AddRef(IMFVideoDeviceID *iface)
1051 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1052 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1055 static ULONG WINAPI video_presenter_device_id_Release(IMFVideoDeviceID *iface)
1057 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1058 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1061 static HRESULT WINAPI video_presenter_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
1063 TRACE("%p, %p.\n", iface, device_id);
1065 if (!device_id)
1066 return E_POINTER;
1068 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
1070 return S_OK;
1073 static const IMFVideoDeviceIDVtbl video_presenter_device_id_vtbl =
1075 video_presenter_device_id_QueryInterface,
1076 video_presenter_device_id_AddRef,
1077 video_presenter_device_id_Release,
1078 video_presenter_device_id_GetDeviceID,
1081 static HRESULT WINAPI video_presenter_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
1082 REFIID riid, void **obj)
1084 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1085 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1088 static ULONG WINAPI video_presenter_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
1090 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1091 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1094 static ULONG WINAPI video_presenter_service_client_Release(IMFTopologyServiceLookupClient *iface)
1096 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1097 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1100 static void video_presenter_set_mixer_rect(struct video_presenter *presenter)
1102 IMFAttributes *attributes;
1103 HRESULT hr;
1105 if (!presenter->mixer)
1106 return;
1108 if (SUCCEEDED(IMFTransform_GetAttributes(presenter->mixer, &attributes)))
1110 if (FAILED(hr = IMFAttributes_SetBlob(attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&presenter->src_rect,
1111 sizeof(presenter->src_rect))))
1113 WARN("Failed to set zoom rectangle attribute, hr %#lx.\n", hr);
1115 IMFAttributes_Release(attributes);
1119 static HRESULT video_presenter_attach_mixer(struct video_presenter *presenter, IMFTopologyServiceLookup *service_lookup)
1121 IMFVideoDeviceID *device_id;
1122 GUID id = { 0 };
1123 DWORD count;
1124 HRESULT hr;
1126 count = 1;
1127 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1128 &MR_VIDEO_MIXER_SERVICE, &IID_IMFTransform, (void **)&presenter->mixer, &count)))
1130 WARN("Failed to get mixer interface, hr %#lx.\n", hr);
1131 return hr;
1134 if (SUCCEEDED(hr = IMFTransform_QueryInterface(presenter->mixer, &IID_IMFVideoDeviceID, (void **)&device_id)))
1136 if (SUCCEEDED(hr = IMFVideoDeviceID_GetDeviceID(device_id, &id)))
1138 if (!IsEqualGUID(&id, &IID_IDirect3DDevice9))
1139 hr = MF_E_INVALIDREQUEST;
1142 IMFVideoDeviceID_Release(device_id);
1145 if (FAILED(hr))
1147 IMFTransform_Release(presenter->mixer);
1148 presenter->mixer = NULL;
1151 video_presenter_set_mixer_rect(presenter);
1152 video_presenter_get_native_video_size(presenter);
1154 return hr;
1157 static HRESULT WINAPI video_presenter_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
1158 IMFTopologyServiceLookup *service_lookup)
1160 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1161 HRESULT hr = S_OK;
1162 DWORD count;
1164 TRACE("%p, %p.\n", iface, service_lookup);
1166 if (!service_lookup)
1167 return E_POINTER;
1169 EnterCriticalSection(&presenter->cs);
1171 if (presenter->state == PRESENTER_STATE_STARTED ||
1172 presenter->state == PRESENTER_STATE_PAUSED)
1174 hr = MF_E_INVALIDREQUEST;
1176 else
1178 video_presenter_clear_container(presenter);
1180 count = 1;
1181 IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1182 &MR_VIDEO_RENDER_SERVICE, &IID_IMFClock, (void **)&presenter->clock, &count);
1184 hr = video_presenter_attach_mixer(presenter, service_lookup);
1186 if (SUCCEEDED(hr))
1188 count = 1;
1189 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1190 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&presenter->event_sink, &count)))
1192 WARN("Failed to get renderer event sink, hr %#lx.\n", hr);
1196 if (SUCCEEDED(hr))
1197 presenter->state = PRESENTER_STATE_STOPPED;
1200 LeaveCriticalSection(&presenter->cs);
1202 return hr;
1205 static HRESULT WINAPI video_presenter_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
1207 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1209 TRACE("%p.\n", iface);
1211 EnterCriticalSection(&presenter->cs);
1213 presenter->state = PRESENTER_STATE_SHUT_DOWN;
1214 video_presenter_clear_container(presenter);
1216 LeaveCriticalSection(&presenter->cs);
1218 return S_OK;
1221 static const IMFTopologyServiceLookupClientVtbl video_presenter_service_client_vtbl =
1223 video_presenter_service_client_QueryInterface,
1224 video_presenter_service_client_AddRef,
1225 video_presenter_service_client_Release,
1226 video_presenter_service_client_InitServicePointers,
1227 video_presenter_service_client_ReleaseServicePointers,
1230 static HRESULT WINAPI video_presenter_control_QueryInterface(IMFVideoDisplayControl *iface, REFIID riid, void **obj)
1232 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1233 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1236 static ULONG WINAPI video_presenter_control_AddRef(IMFVideoDisplayControl *iface)
1238 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1239 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1242 static ULONG WINAPI video_presenter_control_Release(IMFVideoDisplayControl *iface)
1244 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1245 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1248 static HRESULT WINAPI video_presenter_control_GetNativeVideoSize(IMFVideoDisplayControl *iface, SIZE *video_size,
1249 SIZE *aspect_ratio)
1251 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1252 HRESULT hr = S_OK;
1254 TRACE("%p, %p, %p.\n", iface, video_size, aspect_ratio);
1256 if (!video_size && !aspect_ratio)
1257 return E_POINTER;
1259 EnterCriticalSection(&presenter->cs);
1261 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1262 hr = MF_E_SHUTDOWN;
1263 else
1265 if (video_size)
1266 *video_size = presenter->native_size;
1267 if (aspect_ratio)
1268 *aspect_ratio = presenter->native_ratio;
1271 LeaveCriticalSection(&presenter->cs);
1273 return hr;
1276 static HRESULT WINAPI video_presenter_control_GetIdealVideoSize(IMFVideoDisplayControl *iface, SIZE *min_size,
1277 SIZE *max_size)
1279 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1280 HRESULT hr;
1282 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
1284 EnterCriticalSection(&presenter->cs);
1286 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1287 hr = MF_E_SHUTDOWN;
1288 else
1289 hr = E_NOTIMPL;
1291 LeaveCriticalSection(&presenter->cs);
1293 return hr;
1296 static HRESULT WINAPI video_presenter_control_SetVideoPosition(IMFVideoDisplayControl *iface,
1297 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect)
1299 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1300 HRESULT hr = S_OK;
1302 TRACE("%p, %s, %s.\n", iface, debugstr_normalized_rect(src_rect), wine_dbgstr_rect(dst_rect));
1304 if (!src_rect && !dst_rect)
1305 return E_POINTER;
1307 if (src_rect && (src_rect->left < 0.0f || src_rect->top < 0.0f ||
1308 src_rect->right > 1.0f || src_rect->bottom > 1.0f ||
1309 src_rect->left > src_rect->right ||
1310 src_rect->top > src_rect->bottom))
1312 return E_INVALIDARG;
1315 if (dst_rect && (dst_rect->left > dst_rect->right ||
1316 dst_rect->top > dst_rect->bottom))
1317 return E_INVALIDARG;
1319 EnterCriticalSection(&presenter->cs);
1320 if (!presenter->video_window)
1321 hr = E_POINTER;
1322 else
1324 if (src_rect)
1326 if (memcmp(&presenter->src_rect, src_rect, sizeof(*src_rect)))
1328 presenter->src_rect = *src_rect;
1329 video_presenter_set_mixer_rect(presenter);
1332 if (dst_rect && !EqualRect(dst_rect, &presenter->dst_rect))
1334 presenter->dst_rect = *dst_rect;
1335 hr = video_presenter_invalidate_media_type(presenter);
1336 /* Mixer's input type hasn't been configured yet, this is not an error. */
1337 if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) hr = S_OK;
1338 /* FIXME: trigger repaint */
1341 LeaveCriticalSection(&presenter->cs);
1343 return hr;
1346 static HRESULT WINAPI video_presenter_control_GetVideoPosition(IMFVideoDisplayControl *iface, MFVideoNormalizedRect *src_rect,
1347 RECT *dst_rect)
1349 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1351 TRACE("%p, %p, %p.\n", iface, src_rect, dst_rect);
1353 if (!src_rect || !dst_rect)
1354 return E_POINTER;
1356 EnterCriticalSection(&presenter->cs);
1357 *src_rect = presenter->src_rect;
1358 *dst_rect = presenter->dst_rect;
1359 LeaveCriticalSection(&presenter->cs);
1361 return S_OK;
1364 static HRESULT WINAPI video_presenter_control_SetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD mode)
1366 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1368 TRACE("%p, %#lx.\n", iface, mode);
1370 if (mode & ~MFVideoARMode_Mask)
1371 return E_INVALIDARG;
1373 EnterCriticalSection(&presenter->cs);
1374 presenter->ar_mode = mode;
1375 LeaveCriticalSection(&presenter->cs);
1377 return S_OK;
1380 static HRESULT WINAPI video_presenter_control_GetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD *mode)
1382 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1384 TRACE("%p, %p.\n", iface, mode);
1386 if (!mode)
1387 return E_POINTER;
1389 EnterCriticalSection(&presenter->cs);
1390 *mode = presenter->ar_mode;
1391 LeaveCriticalSection(&presenter->cs);
1393 return S_OK;
1396 static HRESULT video_presenter_create_swapchain(struct video_presenter *presenter)
1398 D3DPRESENT_PARAMETERS present_params = { 0 };
1399 IDirect3DDevice9 *d3d_device;
1400 HRESULT hr;
1402 if (SUCCEEDED(hr = video_presenter_get_device(presenter, &d3d_device)))
1404 present_params.hDeviceWindow = presenter->video_window;
1405 present_params.Windowed = TRUE;
1406 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
1407 present_params.Flags = D3DPRESENTFLAG_VIDEO;
1408 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1409 hr = IDirect3DDevice9_CreateAdditionalSwapChain(d3d_device, &present_params, &presenter->swapchain);
1411 IDirect3DDevice9_Release(d3d_device);
1412 IDirect3DDeviceManager9_UnlockDevice(presenter->device_manager, presenter->hdevice, FALSE);
1415 return hr;
1418 static HRESULT WINAPI video_presenter_control_SetVideoWindow(IMFVideoDisplayControl *iface, HWND window)
1420 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1421 HRESULT hr = S_OK;
1423 TRACE("%p, %p.\n", iface, window);
1425 if (!IsWindow(window))
1426 return E_INVALIDARG;
1428 EnterCriticalSection(&presenter->cs);
1429 if (presenter->video_window != window)
1431 if (presenter->swapchain)
1432 IDirect3DSwapChain9_Release(presenter->swapchain);
1433 presenter->video_window = window;
1434 hr = video_presenter_create_swapchain(presenter);
1436 LeaveCriticalSection(&presenter->cs);
1438 return hr;
1441 static HRESULT WINAPI video_presenter_control_GetVideoWindow(IMFVideoDisplayControl *iface, HWND *window)
1443 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1445 TRACE("%p, %p.\n", iface, window);
1447 if (!window)
1448 return E_POINTER;
1450 EnterCriticalSection(&presenter->cs);
1451 *window = presenter->video_window;
1452 LeaveCriticalSection(&presenter->cs);
1454 return S_OK;
1457 static HRESULT WINAPI video_presenter_control_RepaintVideo(IMFVideoDisplayControl *iface)
1459 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1460 HRESULT hr;
1462 FIXME("%p.\n", iface);
1464 EnterCriticalSection(&presenter->cs);
1466 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1467 hr = MF_E_SHUTDOWN;
1468 else
1469 hr = E_NOTIMPL;
1471 LeaveCriticalSection(&presenter->cs);
1473 return hr;
1476 static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayControl *iface, BITMAPINFOHEADER *header,
1477 BYTE **dib, DWORD *dib_size, LONGLONG *timestamp)
1479 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1480 IDirect3DSurface9 *readback = NULL, *surface;
1481 D3DSURFACE_DESC surface_desc;
1482 D3DLOCKED_RECT mapped_rect;
1483 IDirect3DDevice9 *device;
1484 IMFSample *sample;
1485 LONG stride;
1486 HRESULT hr;
1488 TRACE("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp);
1490 EnterCriticalSection(&presenter->cs);
1492 sample = presenter->thread.queue.last_presented;
1493 presenter->thread.queue.last_presented = NULL;
1495 if (!sample)
1497 hr = MF_E_INVALIDREQUEST;
1499 else if (SUCCEEDED(hr = video_presenter_get_sample_surface(sample, &surface)))
1501 IDirect3DSurface9_GetDevice(surface, &device);
1502 IDirect3DSurface9_GetDesc(surface, &surface_desc);
1504 if (surface_desc.Format != D3DFMT_X8R8G8B8)
1506 FIXME("Unexpected surface format %d.\n", surface_desc.Format);
1507 hr = E_FAIL;
1510 if (SUCCEEDED(hr))
1512 if (FAILED(hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, surface_desc.Width,
1513 surface_desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &readback, NULL)))
1515 WARN("Failed to create readback surface, hr %#lx.\n", hr);
1519 if (SUCCEEDED(hr))
1520 hr = IDirect3DDevice9_GetRenderTargetData(device, surface, readback);
1522 if (SUCCEEDED(hr))
1524 MFGetStrideForBitmapInfoHeader(D3DFMT_X8R8G8B8, surface_desc.Width, &stride);
1525 *dib_size = abs(stride) * surface_desc.Height;
1526 if (!(*dib = CoTaskMemAlloc(*dib_size)))
1527 hr = E_OUTOFMEMORY;
1530 if (SUCCEEDED(hr))
1532 if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(readback, &mapped_rect, NULL, D3DLOCK_READONLY)))
1534 memcpy(*dib, mapped_rect.pBits, *dib_size);
1535 IDirect3DSurface9_UnlockRect(readback);
1539 memset(header, 0, sizeof(*header));
1540 header->biSize = sizeof(*header);
1541 header->biWidth = surface_desc.Width;
1542 header->biHeight = surface_desc.Height;
1543 header->biPlanes = 1;
1544 header->biBitCount = 32;
1545 header->biSizeImage = *dib_size;
1546 IMFSample_GetSampleTime(sample, timestamp);
1548 if (readback)
1549 IDirect3DSurface9_Release(readback);
1550 IDirect3DSurface9_Release(surface);
1552 IDirect3DDevice9_Release(device);
1555 if (sample)
1556 IMFSample_Release(sample);
1558 LeaveCriticalSection(&presenter->cs);
1560 return hr;
1563 static HRESULT WINAPI video_presenter_control_SetBorderColor(IMFVideoDisplayControl *iface, COLORREF color)
1565 FIXME("%p, %#lx.\n", iface, color);
1567 return E_NOTIMPL;
1570 static HRESULT WINAPI video_presenter_control_GetBorderColor(IMFVideoDisplayControl *iface, COLORREF *color)
1572 FIXME("%p, %p.\n", iface, color);
1574 return E_NOTIMPL;
1577 static HRESULT WINAPI video_presenter_control_SetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD flags)
1579 FIXME("%p, %#lx.\n", iface, flags);
1581 return E_NOTIMPL;
1584 static HRESULT WINAPI video_presenter_control_GetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD *flags)
1586 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1588 TRACE("%p, %p.\n", iface, flags);
1590 if (!flags)
1591 return E_POINTER;
1593 EnterCriticalSection(&presenter->cs);
1594 *flags = presenter->rendering_prefs;
1595 LeaveCriticalSection(&presenter->cs);
1597 return S_OK;
1600 static HRESULT WINAPI video_presenter_control_SetFullscreen(IMFVideoDisplayControl *iface, BOOL fullscreen)
1602 FIXME("%p, %d.\n", iface, fullscreen);
1604 return E_NOTIMPL;
1607 static HRESULT WINAPI video_presenter_control_GetFullscreen(IMFVideoDisplayControl *iface, BOOL *fullscreen)
1609 FIXME("%p, %p.\n", iface, fullscreen);
1611 return E_NOTIMPL;
1614 static const IMFVideoDisplayControlVtbl video_presenter_control_vtbl =
1616 video_presenter_control_QueryInterface,
1617 video_presenter_control_AddRef,
1618 video_presenter_control_Release,
1619 video_presenter_control_GetNativeVideoSize,
1620 video_presenter_control_GetIdealVideoSize,
1621 video_presenter_control_SetVideoPosition,
1622 video_presenter_control_GetVideoPosition,
1623 video_presenter_control_SetAspectRatioMode,
1624 video_presenter_control_GetAspectRatioMode,
1625 video_presenter_control_SetVideoWindow,
1626 video_presenter_control_GetVideoWindow,
1627 video_presenter_control_RepaintVideo,
1628 video_presenter_control_GetCurrentImage,
1629 video_presenter_control_SetBorderColor,
1630 video_presenter_control_GetBorderColor,
1631 video_presenter_control_SetRenderingPrefs,
1632 video_presenter_control_GetRenderingPrefs,
1633 video_presenter_control_SetFullscreen,
1634 video_presenter_control_GetFullscreen,
1637 static HRESULT WINAPI video_presenter_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1639 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1640 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1643 static ULONG WINAPI video_presenter_rate_support_AddRef(IMFRateSupport *iface)
1645 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1646 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1649 static ULONG WINAPI video_presenter_rate_support_Release(IMFRateSupport *iface)
1651 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1652 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1655 static HRESULT WINAPI video_presenter_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1656 BOOL thin, float *rate)
1658 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1660 *rate = 0.0f;
1662 return S_OK;
1665 static HRESULT WINAPI video_presenter_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1666 BOOL thin, float *rate)
1668 return E_NOTIMPL;
1671 static HRESULT WINAPI video_presenter_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1672 float *nearest_supported_rate)
1674 return E_NOTIMPL;
1677 static const IMFRateSupportVtbl video_presenter_rate_support_vtbl =
1679 video_presenter_rate_support_QueryInterface,
1680 video_presenter_rate_support_AddRef,
1681 video_presenter_rate_support_Release,
1682 video_presenter_rate_support_GetSlowestRate,
1683 video_presenter_rate_support_GetFastestRate,
1684 video_presenter_rate_support_IsRateSupported,
1687 static HRESULT WINAPI video_presenter_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1689 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1690 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1693 static ULONG WINAPI video_presenter_getservice_AddRef(IMFGetService *iface)
1695 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1696 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1699 static ULONG WINAPI video_presenter_getservice_Release(IMFGetService *iface)
1701 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1702 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1705 static HRESULT WINAPI video_presenter_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1707 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1709 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1711 if (IsEqualGUID(&MR_VIDEO_ACCELERATION_SERVICE, service))
1712 return IDirect3DDeviceManager9_QueryInterface(presenter->device_manager, riid, obj);
1714 if (IsEqualGUID(&MR_VIDEO_RENDER_SERVICE, service))
1715 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1717 FIXME("Unimplemented service %s.\n", debugstr_guid(service));
1719 return MF_E_UNSUPPORTED_SERVICE;
1722 static const IMFGetServiceVtbl video_presenter_getservice_vtbl =
1724 video_presenter_getservice_QueryInterface,
1725 video_presenter_getservice_AddRef,
1726 video_presenter_getservice_Release,
1727 video_presenter_getservice_GetService,
1730 static HRESULT WINAPI video_presenter_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1732 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1733 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1736 static ULONG WINAPI video_presenter_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1738 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1739 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1742 static ULONG WINAPI video_presenter_position_mapper_Release(IMFVideoPositionMapper *iface)
1744 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1745 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1748 static HRESULT WINAPI video_presenter_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1749 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1751 FIXME("%p, %f, %f, %lu, %lu, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1753 return E_NOTIMPL;
1756 static const IMFVideoPositionMapperVtbl video_presenter_position_mapper_vtbl =
1758 video_presenter_position_mapper_QueryInterface,
1759 video_presenter_position_mapper_AddRef,
1760 video_presenter_position_mapper_Release,
1761 video_presenter_position_mapper_MapOutputCoordinateToInputStream,
1764 static HRESULT WINAPI video_presenter_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1765 REFIID riid, void **obj)
1767 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1768 IsEqualIID(riid, &IID_IUnknown))
1770 *obj = iface;
1771 IMFVideoSampleAllocatorNotify_AddRef(iface);
1772 return S_OK;
1775 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1776 *obj = NULL;
1777 return E_NOINTERFACE;
1780 static ULONG WINAPI video_presenter_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1782 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1783 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1786 static ULONG WINAPI video_presenter_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1788 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1789 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1792 static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1794 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1796 /* Release notification is executed under allocator lock, instead of processing samples here
1797 notify streaming thread. */
1798 PostThreadMessageW(presenter->thread.tid, EVRM_PROCESS_INPUT, 0, 0);
1800 return S_OK;
1803 static const IMFVideoSampleAllocatorNotifyVtbl video_presenter_allocator_cb_vtbl =
1805 video_presenter_allocator_cb_QueryInterface,
1806 video_presenter_allocator_cb_AddRef,
1807 video_presenter_allocator_cb_Release,
1808 video_presenter_allocator_cb_NotifyRelease,
1811 static HRESULT WINAPI video_presenter_qualprop_QueryInterface(IQualProp *iface, REFIID riid, void **obj)
1813 struct video_presenter *presenter = impl_from_IQualProp(iface);
1814 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1817 static ULONG WINAPI video_presenter_qualprop_AddRef(IQualProp *iface)
1819 struct video_presenter *presenter = impl_from_IQualProp(iface);
1820 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1823 static ULONG WINAPI video_presenter_qualprop_Release(IQualProp *iface)
1825 struct video_presenter *presenter = impl_from_IQualProp(iface);
1826 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1829 static HRESULT WINAPI video_presenter_qualprop_get_FramesDroppedInRenderer(IQualProp *iface, int *frames)
1831 FIXME("%p, %p stub.\n", iface, frames);
1833 return E_NOTIMPL;
1836 static HRESULT WINAPI video_presenter_qualprop_get_FramesDrawn(IQualProp *iface, int *frames)
1838 struct video_presenter *presenter = impl_from_IQualProp(iface);
1839 HRESULT hr = S_OK;
1841 TRACE("%p, %p.\n", iface, frames);
1843 EnterCriticalSection(&presenter->cs);
1845 switch (presenter->state)
1847 case PRESENTER_STATE_STARTED:
1848 case PRESENTER_STATE_PAUSED:
1849 if (frames) *frames = presenter->frame_stats.presented;
1850 else hr = E_POINTER;
1851 break;
1852 default:
1853 hr = E_NOTIMPL;
1856 LeaveCriticalSection(&presenter->cs);
1858 return hr;
1861 static HRESULT WINAPI video_presenter_qualprop_get_AvgFrameRate(IQualProp *iface, int *avg_frame_rate)
1863 FIXME("%p, %p stub.\n", iface, avg_frame_rate);
1865 return E_NOTIMPL;
1868 static HRESULT WINAPI video_presenter_qualprop_get_Jitter(IQualProp *iface, int *jitter)
1870 FIXME("%p, %p stub.\n", iface, jitter);
1872 return E_NOTIMPL;
1875 static HRESULT WINAPI video_presenter_qualprop_get_AvgSyncOffset(IQualProp *iface, int *offset)
1877 FIXME("%p, %p stub.\n", iface, offset);
1879 return E_NOTIMPL;
1882 static HRESULT WINAPI video_presenter_qualprop_get_DevSyncOffset(IQualProp *iface, int *devoffset)
1884 FIXME("%p, %p stub.\n", iface, devoffset);
1886 return E_NOTIMPL;
1889 static const IQualPropVtbl video_presenter_qualprop_vtbl =
1891 video_presenter_qualprop_QueryInterface,
1892 video_presenter_qualprop_AddRef,
1893 video_presenter_qualprop_Release,
1894 video_presenter_qualprop_get_FramesDroppedInRenderer,
1895 video_presenter_qualprop_get_FramesDrawn,
1896 video_presenter_qualprop_get_AvgFrameRate,
1897 video_presenter_qualprop_get_Jitter,
1898 video_presenter_qualprop_get_AvgSyncOffset,
1899 video_presenter_qualprop_get_DevSyncOffset,
1902 static HRESULT WINAPI video_presenter_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
1904 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1905 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, out);
1908 static ULONG WINAPI video_presenter_quality_advise_AddRef(IMFQualityAdvise *iface)
1910 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1911 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1914 static ULONG WINAPI video_presenter_quality_advise_Release(IMFQualityAdvise *iface)
1916 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1917 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1920 static HRESULT WINAPI video_presenter_quality_advise_SetDropMode(IMFQualityAdvise *iface,
1921 MF_QUALITY_DROP_MODE mode)
1923 FIXME("%p, %u.\n", iface, mode);
1925 return E_NOTIMPL;
1928 static HRESULT WINAPI video_presenter_quality_advise_SetQualityLevel(IMFQualityAdvise *iface,
1929 MF_QUALITY_LEVEL level)
1931 FIXME("%p, %u.\n", iface, level);
1933 return E_NOTIMPL;
1936 static HRESULT WINAPI video_presenter_quality_advise_GetDropMode(IMFQualityAdvise *iface,
1937 MF_QUALITY_DROP_MODE *mode)
1939 FIXME("%p, %p.\n", iface, mode);
1941 return E_NOTIMPL;
1944 static HRESULT WINAPI video_presenter_quality_advise_GetQualityLevel(IMFQualityAdvise *iface,
1945 MF_QUALITY_LEVEL *level)
1947 FIXME("%p, %p.\n", iface, level);
1949 return E_NOTIMPL;
1952 static HRESULT WINAPI video_presenter_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
1954 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
1956 return E_NOTIMPL;
1959 static const IMFQualityAdviseVtbl video_presenter_quality_advise_vtbl =
1961 video_presenter_quality_advise_QueryInterface,
1962 video_presenter_quality_advise_AddRef,
1963 video_presenter_quality_advise_Release,
1964 video_presenter_quality_advise_SetDropMode,
1965 video_presenter_quality_advise_SetQualityLevel,
1966 video_presenter_quality_advise_GetDropMode,
1967 video_presenter_quality_advise_GetQualityLevel,
1968 video_presenter_quality_advise_DropTime,
1971 static HRESULT WINAPI video_presenter_device_manager_QueryInterface(IDirect3DDeviceManager9 *iface,
1972 REFIID riid, void **obj)
1974 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1975 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1978 static ULONG WINAPI video_presenter_device_manager_AddRef(IDirect3DDeviceManager9 *iface)
1980 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1981 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1984 static ULONG WINAPI video_presenter_device_manager_Release(IDirect3DDeviceManager9 *iface)
1986 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1987 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1990 static HRESULT WINAPI video_presenter_device_manager_ResetDevice(IDirect3DDeviceManager9 *iface,
1991 IDirect3DDevice9 *device, UINT token)
1993 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1994 return IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, token);
1997 static HRESULT WINAPI video_presenter_device_manager_OpenDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE *hdevice)
1999 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2000 return IDirect3DDeviceManager9_OpenDeviceHandle(presenter->device_manager, hdevice);
2003 static HRESULT WINAPI video_presenter_device_manager_CloseDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
2005 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2006 return IDirect3DDeviceManager9_CloseDeviceHandle(presenter->device_manager, hdevice);
2009 static HRESULT WINAPI video_presenter_device_manager_TestDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
2011 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2012 return IDirect3DDeviceManager9_TestDevice(presenter->device_manager, hdevice);
2015 static HRESULT WINAPI video_presenter_device_manager_LockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
2016 IDirect3DDevice9 **device, BOOL block)
2018 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2019 return IDirect3DDeviceManager9_LockDevice(presenter->device_manager, hdevice, device, block);
2022 static HRESULT WINAPI video_presenter_device_manager_UnlockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
2023 BOOL savestate)
2025 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2026 return IDirect3DDeviceManager9_UnlockDevice(presenter->device_manager, hdevice, savestate);
2029 static HRESULT WINAPI video_presenter_device_manager_GetVideoService(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
2030 REFIID riid, void **service)
2032 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2033 return IDirect3DDeviceManager9_GetVideoService(presenter->device_manager, hdevice, riid, service);
2036 static const IDirect3DDeviceManager9Vtbl video_presenter_device_manager_vtbl =
2038 video_presenter_device_manager_QueryInterface,
2039 video_presenter_device_manager_AddRef,
2040 video_presenter_device_manager_Release,
2041 video_presenter_device_manager_ResetDevice,
2042 video_presenter_device_manager_OpenDeviceHandle,
2043 video_presenter_device_manager_CloseDeviceHandle,
2044 video_presenter_device_manager_TestDevice,
2045 video_presenter_device_manager_LockDevice,
2046 video_presenter_device_manager_UnlockDevice,
2047 video_presenter_device_manager_GetVideoService,
2050 static HRESULT WINAPI video_presenter_qa_limits_QueryInterface(IMFQualityAdviseLimits *iface, REFIID riid, void **obj)
2052 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
2053 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
2056 static ULONG WINAPI video_presenter_qa_limits_AddRef(IMFQualityAdviseLimits *iface)
2058 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
2059 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
2062 static ULONG WINAPI video_presenter_qa_limits_Release(IMFQualityAdviseLimits *iface)
2064 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
2065 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
2068 static HRESULT WINAPI video_presenter_qa_limits_GetMaximumDropMode(IMFQualityAdviseLimits *iface, MF_QUALITY_DROP_MODE *mode)
2070 FIXME("%p, %p.\n", iface, mode);
2072 return E_NOTIMPL;
2075 static HRESULT WINAPI video_presenter_qa_limits_GetMinimumQualityLevel(IMFQualityAdviseLimits *iface, MF_QUALITY_LEVEL *level)
2077 FIXME("%p, %p.\n", iface, level);
2079 return E_NOTIMPL;
2082 static const IMFQualityAdviseLimitsVtbl video_presenter_qa_limits_vtbl =
2084 video_presenter_qa_limits_QueryInterface,
2085 video_presenter_qa_limits_AddRef,
2086 video_presenter_qa_limits_Release,
2087 video_presenter_qa_limits_GetMaximumDropMode,
2088 video_presenter_qa_limits_GetMinimumQualityLevel,
2091 HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
2093 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
2095 *obj = NULL;
2097 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
2098 return E_INVALIDARG;
2100 return CoCreateInstance(&CLSID_MFVideoPresenter9, owner, CLSCTX_INPROC_SERVER, riid, obj);
2103 static HRESULT video_presenter_init_d3d(struct video_presenter *presenter)
2105 D3DPRESENT_PARAMETERS present_params = { 0 };
2106 IDirect3DDevice9 *device;
2107 IDirect3D9 *d3d;
2108 HRESULT hr;
2110 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2112 present_params.BackBufferCount = 1;
2113 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
2114 present_params.hDeviceWindow = GetDesktopWindow();
2115 present_params.Windowed = TRUE;
2116 present_params.Flags = D3DPRESENTFLAG_VIDEO;
2117 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
2118 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
2119 D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_params, &device);
2121 IDirect3D9_Release(d3d);
2123 if (FAILED(hr))
2125 WARN("Failed to create d3d device, hr %#lx.\n", hr);
2126 return hr;
2129 hr = IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, presenter->reset_token);
2130 IDirect3DDevice9_Release(device);
2131 if (FAILED(hr))
2132 WARN("Failed to set new device for the manager, hr %#lx.\n", hr);
2134 if (SUCCEEDED(hr = MFCreateVideoSampleAllocator(&IID_IMFVideoSampleAllocator, (void **)&presenter->allocator)))
2136 hr = IMFVideoSampleAllocator_SetDirectXManager(presenter->allocator, (IUnknown *)presenter->device_manager);
2139 return hr;
2142 HRESULT evr_presenter_create(IUnknown *outer, void **out)
2144 struct video_presenter *object;
2145 HRESULT hr;
2147 *out = NULL;
2149 if (!(object = calloc(1, sizeof(*object))))
2150 return E_OUTOFMEMORY;
2152 object->IMFVideoPresenter_iface.lpVtbl = &video_presenter_vtbl;
2153 object->IMFVideoDeviceID_iface.lpVtbl = &video_presenter_device_id_vtbl;
2154 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_presenter_service_client_vtbl;
2155 object->IMFVideoDisplayControl_iface.lpVtbl = &video_presenter_control_vtbl;
2156 object->IMFRateSupport_iface.lpVtbl = &video_presenter_rate_support_vtbl;
2157 object->IMFGetService_iface.lpVtbl = &video_presenter_getservice_vtbl;
2158 object->IMFVideoPositionMapper_iface.lpVtbl = &video_presenter_position_mapper_vtbl;
2159 object->IQualProp_iface.lpVtbl = &video_presenter_qualprop_vtbl;
2160 object->IMFQualityAdvise_iface.lpVtbl = &video_presenter_quality_advise_vtbl;
2161 object->IMFQualityAdviseLimits_iface.lpVtbl = &video_presenter_qa_limits_vtbl;
2162 object->allocator_cb.lpVtbl = &video_presenter_allocator_cb_vtbl;
2163 object->IUnknown_inner.lpVtbl = &video_presenter_inner_vtbl;
2164 object->IDirect3DDeviceManager9_iface.lpVtbl = &video_presenter_device_manager_vtbl;
2165 object->outer_unk = outer ? outer : &object->IUnknown_inner;
2166 object->refcount = 1;
2167 object->src_rect.right = object->src_rect.bottom = 1.0f;
2168 object->ar_mode = MFVideoARMode_PreservePicture | MFVideoARMode_PreservePixel;
2169 object->allocator_capacity = 3;
2170 InitializeCriticalSection(&object->cs);
2172 if (FAILED(hr = DXVA2CreateDirect3DDeviceManager9(&object->reset_token, &object->device_manager)))
2173 goto failed;
2175 if (FAILED(hr = video_presenter_init_d3d(object)))
2177 WARN("Failed to initialize d3d device, hr %#lx.\n", hr);
2178 goto failed;
2181 *out = &object->IUnknown_inner;
2183 return S_OK;
2185 failed:
2187 IUnknown_Release(&object->IUnknown_inner);
2189 return hr;