mfplat/sample: Optimize copying to 2d buffer.
[wine.git] / dlls / evr / presenter.c
blob2dc01608caf5728381d3b78483267e89457ad889
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,
60 struct sample_queue
62 IMFSample **samples;
63 unsigned int size;
64 unsigned int used;
65 unsigned int front;
66 unsigned int back;
67 IMFSample *last_presented;
68 CRITICAL_SECTION cs;
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;
428 InitializeCriticalSection(&queue->cs);
430 return S_OK;
433 static void video_presenter_sample_queue_push(struct video_presenter *presenter, IMFSample *sample,
434 BOOL at_front)
436 struct sample_queue *queue = &presenter->thread.queue;
437 unsigned int idx;
439 EnterCriticalSection(&queue->cs);
440 if (queue->used != queue->size)
442 if (at_front)
443 idx = queue->front = (queue->size + queue->front - 1) % queue->size;
444 else
445 idx = queue->back = (queue->back + 1) % queue->size;
446 queue->samples[idx] = sample;
447 queue->used++;
448 IMFSample_AddRef(sample);
450 LeaveCriticalSection(&queue->cs);
453 static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, IMFSample **sample)
455 struct sample_queue *queue = &presenter->thread.queue;
457 EnterCriticalSection(&queue->cs);
458 if (queue->used)
460 *sample = queue->samples[queue->front];
461 queue->front = (queue->front + 1) % queue->size;
462 queue->used--;
464 else
465 *sample = NULL;
466 LeaveCriticalSection(&queue->cs);
468 return *sample != NULL;
472 static void video_presenter_sample_queue_free(struct video_presenter *presenter)
474 struct sample_queue *queue = &presenter->thread.queue;
475 IMFSample *sample;
477 while (video_presenter_sample_queue_pop(presenter, &sample))
478 IMFSample_Release(sample);
480 free(queue->samples);
481 DeleteCriticalSection(&queue->cs);
484 static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface)
486 IMFMediaBuffer *buffer;
487 IMFGetService *gs;
488 HRESULT hr;
490 if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer)))
491 return hr;
493 hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&gs);
494 IMFMediaBuffer_Release(buffer);
495 if (FAILED(hr))
496 return hr;
498 hr = IMFGetService_GetService(gs, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)surface);
499 IMFGetService_Release(gs);
500 return hr;
503 static void video_presenter_sample_present(struct video_presenter *presenter, IMFSample *sample)
505 IDirect3DSurface9 *surface, *backbuffer;
506 IDirect3DDevice9 *device;
507 struct sample_queue *queue = &presenter->thread.queue;
508 HRESULT hr;
510 if (FAILED(hr = video_presenter_get_sample_surface(sample, &surface)))
512 WARN("Failed to get sample surface, hr %#lx.\n", hr);
513 return;
516 if (presenter->swapchain)
518 if (SUCCEEDED(hr = IDirect3DSwapChain9_GetBackBuffer(presenter->swapchain, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer)))
520 IDirect3DSwapChain9_GetDevice(presenter->swapchain, &device);
521 IDirect3DDevice9_StretchRect(device, surface, NULL, backbuffer, NULL, D3DTEXF_POINT);
523 IDirect3DSwapChain9_Present(presenter->swapchain, NULL, NULL, NULL, NULL, 0);
524 presenter->frame_stats.presented++;
526 IDirect3DDevice9_Release(device);
527 IDirect3DSurface9_Release(backbuffer);
529 else
530 WARN("Failed to get a backbuffer, hr %#lx.\n", hr);
533 EnterCriticalSection(&queue->cs);
534 if (queue->last_presented)
535 IMFSample_Release(queue->last_presented);
536 queue->last_presented = sample;
537 IMFSample_AddRef(queue->last_presented);
538 LeaveCriticalSection(&queue->cs);
540 IDirect3DSurface9_Release(surface);
543 static void video_presenter_check_queue(struct video_presenter *presenter,
544 unsigned int *next_wait)
546 LONGLONG pts, clocktime, delta;
547 unsigned int wait = 0;
548 IMFSample *sample;
549 MFTIME systime;
550 BOOL present;
551 HRESULT hr;
553 while (video_presenter_sample_queue_pop(presenter, &sample))
555 present = TRUE;
556 wait = 0;
558 if (presenter->clock)
560 pts = clocktime = 0;
562 hr = IMFSample_GetSampleTime(sample, &pts);
563 if (SUCCEEDED(hr))
564 hr = IMFClock_GetCorrelatedTime(presenter->clock, 0, &clocktime, &systime);
566 delta = pts - clocktime;
567 if (delta > 3 * presenter->frame_time_threshold)
569 /* Convert 100ns -> msec */
570 wait = (delta - 3 * presenter->frame_time_threshold) / 10000;
571 present = FALSE;
575 if (present)
576 video_presenter_sample_present(presenter, sample);
577 else
578 video_presenter_sample_queue_push(presenter, sample, TRUE);
580 IMFSample_Release(sample);
582 if (wait > 0)
583 break;
586 if (!wait)
587 wait = INFINITE;
589 *next_wait = wait;
592 static void video_presenter_schedule_sample(struct video_presenter *presenter, IMFSample *sample)
594 if (!presenter->thread.tid)
596 WARN("Streaming thread hasn't been started.\n");
597 return;
600 if (presenter->clock)
602 video_presenter_sample_queue_push(presenter, sample, FALSE);
603 PostThreadMessageW(presenter->thread.tid, EVRM_PRESENT, 0, 0);
605 else
607 video_presenter_sample_present(presenter, sample);
611 static HRESULT video_presenter_process_input(struct video_presenter *presenter)
613 MFT_OUTPUT_DATA_BUFFER buffer;
614 HRESULT hr = S_OK;
615 IMFSample *sample;
616 DWORD status;
618 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
619 return MF_E_SHUTDOWN;
621 if (!presenter->media_type)
622 return S_OK;
624 while (hr == S_OK)
626 LONGLONG mixing_started, mixing_finished;
627 MFTIME systime;
629 if (!(presenter->flags & PRESENTER_MIXER_HAS_INPUT))
630 break;
632 if (FAILED(hr = IMFVideoSampleAllocator_AllocateSample(presenter->allocator, &sample)))
634 WARN("Failed to allocate a sample, hr %#lx.\n", hr);
635 break;
638 memset(&buffer, 0, sizeof(buffer));
639 buffer.pSample = sample;
641 if (presenter->clock)
642 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_started, &systime);
644 if (FAILED(hr = IMFTransform_ProcessOutput(presenter->mixer, 0, 1, &buffer, &status)))
646 /* FIXME: failure path probably needs to handle some errors specifically */
647 presenter->flags &= ~PRESENTER_MIXER_HAS_INPUT;
648 IMFSample_Release(sample);
649 break;
651 else
653 if (presenter->clock)
655 LONGLONG latency;
657 IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_finished, &systime);
658 latency = mixing_finished - mixing_started;
659 video_presenter_notify_renderer(presenter, EC_PROCESSING_LATENCY, (LONG_PTR)&latency, 0);
662 if (buffer.pEvents)
663 IMFCollection_Release(buffer.pEvents);
665 video_presenter_schedule_sample(presenter, sample);
667 IMFSample_Release(sample);
671 return S_OK;
674 static DWORD CALLBACK video_presenter_streaming_thread(void *arg)
676 struct video_presenter *presenter = arg;
677 unsigned int wait = INFINITE;
678 BOOL stop_thread = FALSE;
679 MSG msg;
681 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
683 SetEvent(presenter->thread.ready_event);
685 while (!stop_thread)
687 if (MsgWaitForMultipleObjects(0, NULL, FALSE, wait, QS_POSTMESSAGE) == WAIT_TIMEOUT)
688 video_presenter_check_queue(presenter, &wait);
690 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
692 BOOL peek = TRUE;
694 switch (msg.message)
696 case EVRM_STOP:
697 stop_thread = TRUE;
698 break;
700 case EVRM_PRESENT:
701 if (peek)
703 video_presenter_check_queue(presenter, &wait);
704 peek = wait != INFINITE;
706 break;
708 default:
714 return 0;
717 static HRESULT video_presenter_start_streaming(struct video_presenter *presenter)
719 HRESULT hr;
721 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
722 return MF_E_SHUTDOWN;
724 if (presenter->thread.hthread)
725 return S_OK;
727 if (FAILED(hr = video_presenter_sample_queue_init(presenter)))
728 return hr;
730 if (!(presenter->thread.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
731 return HRESULT_FROM_WIN32(GetLastError());
733 if (!(presenter->thread.hthread = CreateThread(NULL, 0, video_presenter_streaming_thread,
734 presenter, 0, &presenter->thread.tid)))
736 WARN("Failed to create streaming thread.\n");
737 CloseHandle(presenter->thread.ready_event);
738 presenter->thread.ready_event = NULL;
739 return E_FAIL;
742 video_presenter_set_allocator_callback(presenter, &presenter->allocator_cb);
744 WaitForSingleObject(presenter->thread.ready_event, INFINITE);
745 CloseHandle(presenter->thread.ready_event);
746 presenter->thread.ready_event = NULL;
748 TRACE("Started streaming thread, tid %#lx.\n", presenter->thread.tid);
750 return S_OK;
753 static HRESULT video_presenter_end_streaming(struct video_presenter *presenter)
755 if (!presenter->thread.hthread)
756 return S_OK;
758 PostThreadMessageW(presenter->thread.tid, EVRM_STOP, 0, 0);
760 WaitForSingleObject(presenter->thread.hthread, INFINITE);
761 CloseHandle(presenter->thread.hthread);
763 TRACE("Terminated streaming thread tid %#lx.\n", presenter->thread.tid);
765 if (presenter->thread.queue.last_presented)
766 IMFSample_Release(presenter->thread.queue.last_presented);
767 video_presenter_sample_queue_free(presenter);
768 memset(&presenter->thread, 0, sizeof(presenter->thread));
769 video_presenter_set_allocator_callback(presenter, NULL);
771 return S_OK;
774 static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
776 struct video_presenter *presenter = impl_from_IUnknown(iface);
778 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
780 if (IsEqualIID(riid, &IID_IUnknown))
782 *obj = iface;
784 else if (IsEqualIID(riid, &IID_IMFClockStateSink)
785 || IsEqualIID(riid, &IID_IMFVideoPresenter))
787 *obj = &presenter->IMFVideoPresenter_iface;
789 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
791 *obj = &presenter->IMFVideoDeviceID_iface;
793 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
795 *obj = &presenter->IMFTopologyServiceLookupClient_iface;
797 else if (IsEqualIID(riid, &IID_IMFVideoDisplayControl))
799 *obj = &presenter->IMFVideoDisplayControl_iface;
801 else if (IsEqualIID(riid, &IID_IMFRateSupport))
803 *obj = &presenter->IMFRateSupport_iface;
805 else if (IsEqualIID(riid, &IID_IMFGetService))
807 *obj = &presenter->IMFGetService_iface;
809 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
811 *obj = &presenter->IMFVideoPositionMapper_iface;
813 else if (IsEqualIID(riid, &IID_IQualProp))
815 *obj = &presenter->IQualProp_iface;
817 else if (IsEqualIID(riid, &IID_IMFQualityAdvise))
819 *obj = &presenter->IMFQualityAdvise_iface;
821 else if (IsEqualIID(riid, &IID_IMFQualityAdviseLimits))
823 *obj = &presenter->IMFQualityAdviseLimits_iface;
825 else if (IsEqualIID(riid, &IID_IDirect3DDeviceManager9))
827 *obj = &presenter->IDirect3DDeviceManager9_iface;
829 else
831 WARN("Unimplemented interface %s.\n", debugstr_guid(riid));
832 *obj = NULL;
833 return E_NOINTERFACE;
836 IUnknown_AddRef((IUnknown *)*obj);
837 return S_OK;
840 static ULONG WINAPI video_presenter_inner_AddRef(IUnknown *iface)
842 struct video_presenter *presenter = impl_from_IUnknown(iface);
843 ULONG refcount = InterlockedIncrement(&presenter->refcount);
845 TRACE("%p, refcount %lu.\n", iface, refcount);
847 return refcount;
850 static void video_presenter_clear_container(struct video_presenter *presenter)
852 if (presenter->clock)
853 IMFClock_Release(presenter->clock);
854 if (presenter->mixer)
855 IMFTransform_Release(presenter->mixer);
856 if (presenter->event_sink)
857 IMediaEventSink_Release(presenter->event_sink);
858 presenter->clock = NULL;
859 presenter->mixer = NULL;
860 presenter->event_sink = NULL;
863 static ULONG WINAPI video_presenter_inner_Release(IUnknown *iface)
865 struct video_presenter *presenter = impl_from_IUnknown(iface);
866 ULONG refcount = InterlockedDecrement(&presenter->refcount);
868 TRACE("%p, refcount %lu.\n", iface, refcount);
870 if (!refcount)
872 video_presenter_end_streaming(presenter);
873 video_presenter_clear_container(presenter);
874 video_presenter_reset_media_type(presenter);
875 DeleteCriticalSection(&presenter->cs);
876 if (presenter->swapchain)
877 IDirect3DSwapChain9_Release(presenter->swapchain);
878 if (presenter->device_manager)
880 IDirect3DDeviceManager9_CloseDeviceHandle(presenter->device_manager, presenter->hdevice);
881 IDirect3DDeviceManager9_Release(presenter->device_manager);
883 if (presenter->allocator)
884 IMFVideoSampleAllocator_Release(presenter->allocator);
885 free(presenter);
888 return refcount;
891 static const IUnknownVtbl video_presenter_inner_vtbl =
893 video_presenter_inner_QueryInterface,
894 video_presenter_inner_AddRef,
895 video_presenter_inner_Release,
898 static HRESULT WINAPI video_presenter_QueryInterface(IMFVideoPresenter *iface, REFIID riid, void **obj)
900 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
901 return IUnknown_QueryInterface(presenter->outer_unk, riid, obj);
904 static ULONG WINAPI video_presenter_AddRef(IMFVideoPresenter *iface)
906 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
907 return IUnknown_AddRef(presenter->outer_unk);
910 static ULONG WINAPI video_presenter_Release(IMFVideoPresenter *iface)
912 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
913 return IUnknown_Release(presenter->outer_unk);
916 static HRESULT WINAPI video_presenter_OnClockStart(IMFVideoPresenter *iface, MFTIME systime, LONGLONG offset)
918 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
920 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), wine_dbgstr_longlong(offset));
922 EnterCriticalSection(&presenter->cs);
923 presenter->state = PRESENTER_STATE_STARTED;
924 LeaveCriticalSection(&presenter->cs);
926 return S_OK;
929 static HRESULT WINAPI video_presenter_OnClockStop(IMFVideoPresenter *iface, MFTIME systime)
931 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
933 TRACE("%p, %s.\n", iface, debugstr_time(systime));
935 EnterCriticalSection(&presenter->cs);
936 presenter->state = PRESENTER_STATE_STOPPED;
937 presenter->frame_stats.presented = 0;
938 LeaveCriticalSection(&presenter->cs);
940 return S_OK;
943 static HRESULT WINAPI video_presenter_OnClockPause(IMFVideoPresenter *iface, MFTIME systime)
945 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
947 TRACE("%p, %s.\n", iface, debugstr_time(systime));
949 EnterCriticalSection(&presenter->cs);
950 presenter->state = PRESENTER_STATE_PAUSED;
951 LeaveCriticalSection(&presenter->cs);
953 return S_OK;
956 static HRESULT WINAPI video_presenter_OnClockRestart(IMFVideoPresenter *iface, MFTIME systime)
958 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
960 TRACE("%p, %s.\n", iface, debugstr_time(systime));
962 EnterCriticalSection(&presenter->cs);
963 presenter->state = PRESENTER_STATE_STARTED;
964 LeaveCriticalSection(&presenter->cs);
966 return S_OK;
969 static HRESULT WINAPI video_presenter_OnClockSetRate(IMFVideoPresenter *iface, MFTIME systime, float rate)
971 FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
973 return E_NOTIMPL;
976 static HRESULT WINAPI video_presenter_ProcessMessage(IMFVideoPresenter *iface, MFVP_MESSAGE_TYPE message, ULONG_PTR param)
978 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
979 HRESULT hr;
981 TRACE("%p, %d, %Iu.\n", iface, message, param);
983 EnterCriticalSection(&presenter->cs);
985 switch (message)
987 case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
988 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
989 hr = MF_E_SHUTDOWN;
990 else if (!presenter->mixer)
991 hr = MF_E_INVALIDREQUEST;
992 else
993 hr = video_presenter_invalidate_media_type(presenter);
994 break;
995 case MFVP_MESSAGE_BEGINSTREAMING:
996 hr = video_presenter_start_streaming(presenter);
997 break;
998 case MFVP_MESSAGE_ENDSTREAMING:
999 hr = video_presenter_end_streaming(presenter);
1000 break;
1001 case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
1002 presenter->flags |= PRESENTER_MIXER_HAS_INPUT;
1003 hr = video_presenter_process_input(presenter);
1004 break;
1005 default:
1006 FIXME("Unsupported message %u.\n", message);
1007 hr = E_NOTIMPL;
1010 LeaveCriticalSection(&presenter->cs);
1012 return hr;
1015 static HRESULT WINAPI video_presenter_GetCurrentMediaType(IMFVideoPresenter *iface,
1016 IMFVideoMediaType **media_type)
1018 struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface);
1019 HRESULT hr;
1021 TRACE("%p, %p.\n", iface, media_type);
1023 EnterCriticalSection(&presenter->cs);
1025 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1026 hr = MF_E_SHUTDOWN;
1027 else if (!presenter->media_type)
1028 hr = MF_E_NOT_INITIALIZED;
1029 else
1031 hr = IMFMediaType_QueryInterface(presenter->media_type, &IID_IMFVideoMediaType,
1032 (void **)media_type);
1035 LeaveCriticalSection(&presenter->cs);
1037 return hr;
1040 static const IMFVideoPresenterVtbl video_presenter_vtbl =
1042 video_presenter_QueryInterface,
1043 video_presenter_AddRef,
1044 video_presenter_Release,
1045 video_presenter_OnClockStart,
1046 video_presenter_OnClockStop,
1047 video_presenter_OnClockPause,
1048 video_presenter_OnClockRestart,
1049 video_presenter_OnClockSetRate,
1050 video_presenter_ProcessMessage,
1051 video_presenter_GetCurrentMediaType,
1054 static HRESULT WINAPI video_presenter_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
1056 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1057 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1060 static ULONG WINAPI video_presenter_device_id_AddRef(IMFVideoDeviceID *iface)
1062 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1063 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1066 static ULONG WINAPI video_presenter_device_id_Release(IMFVideoDeviceID *iface)
1068 struct video_presenter *presenter = impl_from_IMFVideoDeviceID(iface);
1069 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1072 static HRESULT WINAPI video_presenter_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
1074 TRACE("%p, %p.\n", iface, device_id);
1076 if (!device_id)
1077 return E_POINTER;
1079 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
1081 return S_OK;
1084 static const IMFVideoDeviceIDVtbl video_presenter_device_id_vtbl =
1086 video_presenter_device_id_QueryInterface,
1087 video_presenter_device_id_AddRef,
1088 video_presenter_device_id_Release,
1089 video_presenter_device_id_GetDeviceID,
1092 static HRESULT WINAPI video_presenter_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
1093 REFIID riid, void **obj)
1095 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1096 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1099 static ULONG WINAPI video_presenter_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
1101 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1102 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1105 static ULONG WINAPI video_presenter_service_client_Release(IMFTopologyServiceLookupClient *iface)
1107 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1108 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1111 static void video_presenter_set_mixer_rect(struct video_presenter *presenter)
1113 IMFAttributes *attributes;
1114 HRESULT hr;
1116 if (!presenter->mixer)
1117 return;
1119 if (SUCCEEDED(IMFTransform_GetAttributes(presenter->mixer, &attributes)))
1121 if (FAILED(hr = IMFAttributes_SetBlob(attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&presenter->src_rect,
1122 sizeof(presenter->src_rect))))
1124 WARN("Failed to set zoom rectangle attribute, hr %#lx.\n", hr);
1126 IMFAttributes_Release(attributes);
1130 static HRESULT video_presenter_attach_mixer(struct video_presenter *presenter, IMFTopologyServiceLookup *service_lookup)
1132 IMFVideoDeviceID *device_id;
1133 GUID id = { 0 };
1134 DWORD count;
1135 HRESULT hr;
1137 count = 1;
1138 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1139 &MR_VIDEO_MIXER_SERVICE, &IID_IMFTransform, (void **)&presenter->mixer, &count)))
1141 WARN("Failed to get mixer interface, hr %#lx.\n", hr);
1142 return hr;
1145 if (SUCCEEDED(hr = IMFTransform_QueryInterface(presenter->mixer, &IID_IMFVideoDeviceID, (void **)&device_id)))
1147 if (SUCCEEDED(hr = IMFVideoDeviceID_GetDeviceID(device_id, &id)))
1149 if (!IsEqualGUID(&id, &IID_IDirect3DDevice9))
1150 hr = MF_E_INVALIDREQUEST;
1153 IMFVideoDeviceID_Release(device_id);
1156 if (FAILED(hr))
1158 IMFTransform_Release(presenter->mixer);
1159 presenter->mixer = NULL;
1162 video_presenter_set_mixer_rect(presenter);
1163 video_presenter_get_native_video_size(presenter);
1165 return hr;
1168 static HRESULT WINAPI video_presenter_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
1169 IMFTopologyServiceLookup *service_lookup)
1171 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1172 HRESULT hr = S_OK;
1173 DWORD count;
1175 TRACE("%p, %p.\n", iface, service_lookup);
1177 if (!service_lookup)
1178 return E_POINTER;
1180 EnterCriticalSection(&presenter->cs);
1182 if (presenter->state == PRESENTER_STATE_STARTED ||
1183 presenter->state == PRESENTER_STATE_PAUSED)
1185 hr = MF_E_INVALIDREQUEST;
1187 else
1189 video_presenter_clear_container(presenter);
1191 count = 1;
1192 IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1193 &MR_VIDEO_RENDER_SERVICE, &IID_IMFClock, (void **)&presenter->clock, &count);
1195 hr = video_presenter_attach_mixer(presenter, service_lookup);
1197 if (SUCCEEDED(hr))
1199 count = 1;
1200 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1201 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&presenter->event_sink, &count)))
1203 WARN("Failed to get renderer event sink, hr %#lx.\n", hr);
1207 if (SUCCEEDED(hr))
1208 presenter->state = PRESENTER_STATE_STOPPED;
1211 LeaveCriticalSection(&presenter->cs);
1213 return hr;
1216 static HRESULT WINAPI video_presenter_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
1218 struct video_presenter *presenter = impl_from_IMFTopologyServiceLookupClient(iface);
1220 TRACE("%p.\n", iface);
1222 EnterCriticalSection(&presenter->cs);
1224 presenter->state = PRESENTER_STATE_SHUT_DOWN;
1225 video_presenter_clear_container(presenter);
1227 LeaveCriticalSection(&presenter->cs);
1229 return S_OK;
1232 static const IMFTopologyServiceLookupClientVtbl video_presenter_service_client_vtbl =
1234 video_presenter_service_client_QueryInterface,
1235 video_presenter_service_client_AddRef,
1236 video_presenter_service_client_Release,
1237 video_presenter_service_client_InitServicePointers,
1238 video_presenter_service_client_ReleaseServicePointers,
1241 static HRESULT WINAPI video_presenter_control_QueryInterface(IMFVideoDisplayControl *iface, REFIID riid, void **obj)
1243 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1244 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1247 static ULONG WINAPI video_presenter_control_AddRef(IMFVideoDisplayControl *iface)
1249 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1250 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1253 static ULONG WINAPI video_presenter_control_Release(IMFVideoDisplayControl *iface)
1255 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1256 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1259 static HRESULT WINAPI video_presenter_control_GetNativeVideoSize(IMFVideoDisplayControl *iface, SIZE *video_size,
1260 SIZE *aspect_ratio)
1262 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1263 HRESULT hr = S_OK;
1265 TRACE("%p, %p, %p.\n", iface, video_size, aspect_ratio);
1267 if (!video_size && !aspect_ratio)
1268 return E_POINTER;
1270 EnterCriticalSection(&presenter->cs);
1272 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1273 hr = MF_E_SHUTDOWN;
1274 else
1276 if (video_size)
1277 *video_size = presenter->native_size;
1278 if (aspect_ratio)
1279 *aspect_ratio = presenter->native_ratio;
1282 LeaveCriticalSection(&presenter->cs);
1284 return hr;
1287 static HRESULT WINAPI video_presenter_control_GetIdealVideoSize(IMFVideoDisplayControl *iface, SIZE *min_size,
1288 SIZE *max_size)
1290 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1291 HRESULT hr;
1293 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
1295 EnterCriticalSection(&presenter->cs);
1297 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1298 hr = MF_E_SHUTDOWN;
1299 else
1300 hr = E_NOTIMPL;
1302 LeaveCriticalSection(&presenter->cs);
1304 return hr;
1307 static HRESULT WINAPI video_presenter_control_SetVideoPosition(IMFVideoDisplayControl *iface,
1308 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect)
1310 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1311 HRESULT hr = S_OK;
1313 TRACE("%p, %s, %s.\n", iface, debugstr_normalized_rect(src_rect), wine_dbgstr_rect(dst_rect));
1315 if (!src_rect && !dst_rect)
1316 return E_POINTER;
1318 if (src_rect && (src_rect->left < 0.0f || src_rect->top < 0.0f ||
1319 src_rect->right > 1.0f || src_rect->bottom > 1.0f ||
1320 src_rect->left > src_rect->right ||
1321 src_rect->top > src_rect->bottom))
1323 return E_INVALIDARG;
1326 if (dst_rect && (dst_rect->left > dst_rect->right ||
1327 dst_rect->top > dst_rect->bottom))
1328 return E_INVALIDARG;
1330 EnterCriticalSection(&presenter->cs);
1331 if (!presenter->video_window)
1332 hr = E_POINTER;
1333 else
1335 if (src_rect)
1337 if (memcmp(&presenter->src_rect, src_rect, sizeof(*src_rect)))
1339 presenter->src_rect = *src_rect;
1340 video_presenter_set_mixer_rect(presenter);
1343 if (dst_rect && !EqualRect(dst_rect, &presenter->dst_rect))
1345 presenter->dst_rect = *dst_rect;
1346 hr = video_presenter_invalidate_media_type(presenter);
1347 /* Mixer's input type hasn't been configured yet, this is not an error. */
1348 if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) hr = S_OK;
1349 /* FIXME: trigger repaint */
1352 LeaveCriticalSection(&presenter->cs);
1354 return hr;
1357 static HRESULT WINAPI video_presenter_control_GetVideoPosition(IMFVideoDisplayControl *iface, MFVideoNormalizedRect *src_rect,
1358 RECT *dst_rect)
1360 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1362 TRACE("%p, %p, %p.\n", iface, src_rect, dst_rect);
1364 if (!src_rect || !dst_rect)
1365 return E_POINTER;
1367 EnterCriticalSection(&presenter->cs);
1368 *src_rect = presenter->src_rect;
1369 *dst_rect = presenter->dst_rect;
1370 LeaveCriticalSection(&presenter->cs);
1372 return S_OK;
1375 static HRESULT WINAPI video_presenter_control_SetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD mode)
1377 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1379 TRACE("%p, %#lx.\n", iface, mode);
1381 if (mode & ~MFVideoARMode_Mask)
1382 return E_INVALIDARG;
1384 EnterCriticalSection(&presenter->cs);
1385 presenter->ar_mode = mode;
1386 LeaveCriticalSection(&presenter->cs);
1388 return S_OK;
1391 static HRESULT WINAPI video_presenter_control_GetAspectRatioMode(IMFVideoDisplayControl *iface, DWORD *mode)
1393 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1395 TRACE("%p, %p.\n", iface, mode);
1397 if (!mode)
1398 return E_POINTER;
1400 EnterCriticalSection(&presenter->cs);
1401 *mode = presenter->ar_mode;
1402 LeaveCriticalSection(&presenter->cs);
1404 return S_OK;
1407 static HRESULT video_presenter_create_swapchain(struct video_presenter *presenter)
1409 D3DPRESENT_PARAMETERS present_params = { 0 };
1410 IDirect3DDevice9 *d3d_device;
1411 HRESULT hr;
1413 if (SUCCEEDED(hr = video_presenter_get_device(presenter, &d3d_device)))
1415 present_params.hDeviceWindow = presenter->video_window;
1416 present_params.Windowed = TRUE;
1417 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
1418 present_params.Flags = D3DPRESENTFLAG_VIDEO;
1419 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1420 hr = IDirect3DDevice9_CreateAdditionalSwapChain(d3d_device, &present_params, &presenter->swapchain);
1422 IDirect3DDevice9_Release(d3d_device);
1423 IDirect3DDeviceManager9_UnlockDevice(presenter->device_manager, presenter->hdevice, FALSE);
1426 return hr;
1429 static HRESULT WINAPI video_presenter_control_SetVideoWindow(IMFVideoDisplayControl *iface, HWND window)
1431 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1432 HRESULT hr = S_OK;
1434 TRACE("%p, %p.\n", iface, window);
1436 if (!IsWindow(window))
1437 return E_INVALIDARG;
1439 EnterCriticalSection(&presenter->cs);
1440 if (presenter->video_window != window)
1442 if (presenter->swapchain)
1443 IDirect3DSwapChain9_Release(presenter->swapchain);
1444 presenter->video_window = window;
1445 hr = video_presenter_create_swapchain(presenter);
1447 LeaveCriticalSection(&presenter->cs);
1449 return hr;
1452 static HRESULT WINAPI video_presenter_control_GetVideoWindow(IMFVideoDisplayControl *iface, HWND *window)
1454 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1456 TRACE("%p, %p.\n", iface, window);
1458 if (!window)
1459 return E_POINTER;
1461 EnterCriticalSection(&presenter->cs);
1462 *window = presenter->video_window;
1463 LeaveCriticalSection(&presenter->cs);
1465 return S_OK;
1468 static HRESULT WINAPI video_presenter_control_RepaintVideo(IMFVideoDisplayControl *iface)
1470 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1471 HRESULT hr;
1473 FIXME("%p.\n", iface);
1475 EnterCriticalSection(&presenter->cs);
1477 if (presenter->state == PRESENTER_STATE_SHUT_DOWN)
1478 hr = MF_E_SHUTDOWN;
1479 else
1480 hr = E_NOTIMPL;
1482 LeaveCriticalSection(&presenter->cs);
1484 return hr;
1487 static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayControl *iface, BITMAPINFOHEADER *header,
1488 BYTE **dib, DWORD *dib_size, LONGLONG *timestamp)
1490 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1491 IDirect3DSurface9 *readback = NULL, *surface;
1492 D3DSURFACE_DESC surface_desc;
1493 D3DLOCKED_RECT mapped_rect;
1494 IDirect3DDevice9 *device;
1495 IMFSample *sample;
1496 LONG stride;
1497 HRESULT hr;
1499 TRACE("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp);
1501 EnterCriticalSection(&presenter->cs);
1503 sample = presenter->thread.queue.last_presented;
1504 presenter->thread.queue.last_presented = NULL;
1506 if (!sample)
1508 hr = MF_E_INVALIDREQUEST;
1510 else if (SUCCEEDED(hr = video_presenter_get_sample_surface(sample, &surface)))
1512 IDirect3DSurface9_GetDevice(surface, &device);
1513 IDirect3DSurface9_GetDesc(surface, &surface_desc);
1515 if (surface_desc.Format != D3DFMT_X8R8G8B8)
1517 FIXME("Unexpected surface format %d.\n", surface_desc.Format);
1518 hr = E_FAIL;
1521 if (SUCCEEDED(hr))
1523 if (FAILED(hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, surface_desc.Width,
1524 surface_desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &readback, NULL)))
1526 WARN("Failed to create readback surface, hr %#lx.\n", hr);
1530 if (SUCCEEDED(hr))
1531 hr = IDirect3DDevice9_GetRenderTargetData(device, surface, readback);
1533 if (SUCCEEDED(hr))
1535 MFGetStrideForBitmapInfoHeader(D3DFMT_X8R8G8B8, surface_desc.Width, &stride);
1536 *dib_size = abs(stride) * surface_desc.Height;
1537 if (!(*dib = CoTaskMemAlloc(*dib_size)))
1538 hr = E_OUTOFMEMORY;
1541 if (SUCCEEDED(hr))
1543 if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(readback, &mapped_rect, NULL, D3DLOCK_READONLY)))
1545 hr = MFCopyImage(stride < 0 ? *dib + *dib_size + stride : *dib, stride,
1546 mapped_rect.pBits, mapped_rect.Pitch, abs(stride), surface_desc.Height);
1547 IDirect3DSurface9_UnlockRect(readback);
1551 memset(header, 0, sizeof(*header));
1552 header->biSize = sizeof(*header);
1553 header->biWidth = surface_desc.Width;
1554 header->biHeight = surface_desc.Height;
1555 header->biPlanes = 1;
1556 header->biBitCount = 32;
1557 header->biSizeImage = *dib_size;
1558 IMFSample_GetSampleTime(sample, timestamp);
1560 if (readback)
1561 IDirect3DSurface9_Release(readback);
1562 IDirect3DSurface9_Release(surface);
1564 IDirect3DDevice9_Release(device);
1567 if (sample)
1568 IMFSample_Release(sample);
1570 LeaveCriticalSection(&presenter->cs);
1572 return hr;
1575 static HRESULT WINAPI video_presenter_control_SetBorderColor(IMFVideoDisplayControl *iface, COLORREF color)
1577 FIXME("%p, %#lx.\n", iface, color);
1579 return E_NOTIMPL;
1582 static HRESULT WINAPI video_presenter_control_GetBorderColor(IMFVideoDisplayControl *iface, COLORREF *color)
1584 FIXME("%p, %p.\n", iface, color);
1586 return E_NOTIMPL;
1589 static HRESULT WINAPI video_presenter_control_SetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD flags)
1591 FIXME("%p, %#lx.\n", iface, flags);
1593 return E_NOTIMPL;
1596 static HRESULT WINAPI video_presenter_control_GetRenderingPrefs(IMFVideoDisplayControl *iface, DWORD *flags)
1598 struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
1600 TRACE("%p, %p.\n", iface, flags);
1602 if (!flags)
1603 return E_POINTER;
1605 EnterCriticalSection(&presenter->cs);
1606 *flags = presenter->rendering_prefs;
1607 LeaveCriticalSection(&presenter->cs);
1609 return S_OK;
1612 static HRESULT WINAPI video_presenter_control_SetFullscreen(IMFVideoDisplayControl *iface, BOOL fullscreen)
1614 FIXME("%p, %d.\n", iface, fullscreen);
1616 return E_NOTIMPL;
1619 static HRESULT WINAPI video_presenter_control_GetFullscreen(IMFVideoDisplayControl *iface, BOOL *fullscreen)
1621 FIXME("%p, %p.\n", iface, fullscreen);
1623 return E_NOTIMPL;
1626 static const IMFVideoDisplayControlVtbl video_presenter_control_vtbl =
1628 video_presenter_control_QueryInterface,
1629 video_presenter_control_AddRef,
1630 video_presenter_control_Release,
1631 video_presenter_control_GetNativeVideoSize,
1632 video_presenter_control_GetIdealVideoSize,
1633 video_presenter_control_SetVideoPosition,
1634 video_presenter_control_GetVideoPosition,
1635 video_presenter_control_SetAspectRatioMode,
1636 video_presenter_control_GetAspectRatioMode,
1637 video_presenter_control_SetVideoWindow,
1638 video_presenter_control_GetVideoWindow,
1639 video_presenter_control_RepaintVideo,
1640 video_presenter_control_GetCurrentImage,
1641 video_presenter_control_SetBorderColor,
1642 video_presenter_control_GetBorderColor,
1643 video_presenter_control_SetRenderingPrefs,
1644 video_presenter_control_GetRenderingPrefs,
1645 video_presenter_control_SetFullscreen,
1646 video_presenter_control_GetFullscreen,
1649 static HRESULT WINAPI video_presenter_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1651 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1652 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1655 static ULONG WINAPI video_presenter_rate_support_AddRef(IMFRateSupport *iface)
1657 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1658 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1661 static ULONG WINAPI video_presenter_rate_support_Release(IMFRateSupport *iface)
1663 struct video_presenter *presenter = impl_from_IMFRateSupport(iface);
1664 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1667 static HRESULT WINAPI video_presenter_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1668 BOOL thin, float *rate)
1670 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1672 *rate = 0.0f;
1674 return S_OK;
1677 static HRESULT WINAPI video_presenter_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1678 BOOL thin, float *rate)
1680 return E_NOTIMPL;
1683 static HRESULT WINAPI video_presenter_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1684 float *nearest_supported_rate)
1686 return E_NOTIMPL;
1689 static const IMFRateSupportVtbl video_presenter_rate_support_vtbl =
1691 video_presenter_rate_support_QueryInterface,
1692 video_presenter_rate_support_AddRef,
1693 video_presenter_rate_support_Release,
1694 video_presenter_rate_support_GetSlowestRate,
1695 video_presenter_rate_support_GetFastestRate,
1696 video_presenter_rate_support_IsRateSupported,
1699 static HRESULT WINAPI video_presenter_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1701 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1702 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1705 static ULONG WINAPI video_presenter_getservice_AddRef(IMFGetService *iface)
1707 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1708 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1711 static ULONG WINAPI video_presenter_getservice_Release(IMFGetService *iface)
1713 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1714 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1717 static HRESULT WINAPI video_presenter_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1719 struct video_presenter *presenter = impl_from_IMFGetService(iface);
1721 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1723 if (IsEqualGUID(&MR_VIDEO_ACCELERATION_SERVICE, service))
1724 return IDirect3DDeviceManager9_QueryInterface(presenter->device_manager, riid, obj);
1726 if (IsEqualGUID(&MR_VIDEO_RENDER_SERVICE, service))
1727 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1729 FIXME("Unimplemented service %s.\n", debugstr_guid(service));
1731 return MF_E_UNSUPPORTED_SERVICE;
1734 static const IMFGetServiceVtbl video_presenter_getservice_vtbl =
1736 video_presenter_getservice_QueryInterface,
1737 video_presenter_getservice_AddRef,
1738 video_presenter_getservice_Release,
1739 video_presenter_getservice_GetService,
1742 static HRESULT WINAPI video_presenter_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1744 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1745 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1748 static ULONG WINAPI video_presenter_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1750 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1751 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1754 static ULONG WINAPI video_presenter_position_mapper_Release(IMFVideoPositionMapper *iface)
1756 struct video_presenter *presenter = impl_from_IMFVideoPositionMapper(iface);
1757 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1760 static HRESULT WINAPI video_presenter_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1761 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1763 FIXME("%p, %f, %f, %lu, %lu, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1765 return E_NOTIMPL;
1768 static const IMFVideoPositionMapperVtbl video_presenter_position_mapper_vtbl =
1770 video_presenter_position_mapper_QueryInterface,
1771 video_presenter_position_mapper_AddRef,
1772 video_presenter_position_mapper_Release,
1773 video_presenter_position_mapper_MapOutputCoordinateToInputStream,
1776 static HRESULT WINAPI video_presenter_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1777 REFIID riid, void **obj)
1779 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1780 IsEqualIID(riid, &IID_IUnknown))
1782 *obj = iface;
1783 IMFVideoSampleAllocatorNotify_AddRef(iface);
1784 return S_OK;
1787 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1788 *obj = NULL;
1789 return E_NOINTERFACE;
1792 static ULONG WINAPI video_presenter_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1794 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1795 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1798 static ULONG WINAPI video_presenter_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1800 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1801 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1804 static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1806 struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
1808 EnterCriticalSection(&presenter->cs);
1809 video_presenter_process_input(presenter);
1810 LeaveCriticalSection(&presenter->cs);
1812 return S_OK;
1815 static const IMFVideoSampleAllocatorNotifyVtbl video_presenter_allocator_cb_vtbl =
1817 video_presenter_allocator_cb_QueryInterface,
1818 video_presenter_allocator_cb_AddRef,
1819 video_presenter_allocator_cb_Release,
1820 video_presenter_allocator_cb_NotifyRelease,
1823 static HRESULT WINAPI video_presenter_qualprop_QueryInterface(IQualProp *iface, REFIID riid, void **obj)
1825 struct video_presenter *presenter = impl_from_IQualProp(iface);
1826 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1829 static ULONG WINAPI video_presenter_qualprop_AddRef(IQualProp *iface)
1831 struct video_presenter *presenter = impl_from_IQualProp(iface);
1832 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1835 static ULONG WINAPI video_presenter_qualprop_Release(IQualProp *iface)
1837 struct video_presenter *presenter = impl_from_IQualProp(iface);
1838 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1841 static HRESULT WINAPI video_presenter_qualprop_get_FramesDroppedInRenderer(IQualProp *iface, int *frames)
1843 FIXME("%p, %p stub.\n", iface, frames);
1845 return E_NOTIMPL;
1848 static HRESULT WINAPI video_presenter_qualprop_get_FramesDrawn(IQualProp *iface, int *frames)
1850 struct video_presenter *presenter = impl_from_IQualProp(iface);
1851 HRESULT hr = S_OK;
1853 TRACE("%p, %p.\n", iface, frames);
1855 EnterCriticalSection(&presenter->cs);
1857 switch (presenter->state)
1859 case PRESENTER_STATE_STARTED:
1860 case PRESENTER_STATE_PAUSED:
1861 if (frames) *frames = presenter->frame_stats.presented;
1862 else hr = E_POINTER;
1863 break;
1864 default:
1865 hr = E_NOTIMPL;
1868 LeaveCriticalSection(&presenter->cs);
1870 return hr;
1873 static HRESULT WINAPI video_presenter_qualprop_get_AvgFrameRate(IQualProp *iface, int *avg_frame_rate)
1875 FIXME("%p, %p stub.\n", iface, avg_frame_rate);
1877 return E_NOTIMPL;
1880 static HRESULT WINAPI video_presenter_qualprop_get_Jitter(IQualProp *iface, int *jitter)
1882 FIXME("%p, %p stub.\n", iface, jitter);
1884 return E_NOTIMPL;
1887 static HRESULT WINAPI video_presenter_qualprop_get_AvgSyncOffset(IQualProp *iface, int *offset)
1889 FIXME("%p, %p stub.\n", iface, offset);
1891 return E_NOTIMPL;
1894 static HRESULT WINAPI video_presenter_qualprop_get_DevSyncOffset(IQualProp *iface, int *devoffset)
1896 FIXME("%p, %p stub.\n", iface, devoffset);
1898 return E_NOTIMPL;
1901 static const IQualPropVtbl video_presenter_qualprop_vtbl =
1903 video_presenter_qualprop_QueryInterface,
1904 video_presenter_qualprop_AddRef,
1905 video_presenter_qualprop_Release,
1906 video_presenter_qualprop_get_FramesDroppedInRenderer,
1907 video_presenter_qualprop_get_FramesDrawn,
1908 video_presenter_qualprop_get_AvgFrameRate,
1909 video_presenter_qualprop_get_Jitter,
1910 video_presenter_qualprop_get_AvgSyncOffset,
1911 video_presenter_qualprop_get_DevSyncOffset,
1914 static HRESULT WINAPI video_presenter_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
1916 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1917 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, out);
1920 static ULONG WINAPI video_presenter_quality_advise_AddRef(IMFQualityAdvise *iface)
1922 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1923 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1926 static ULONG WINAPI video_presenter_quality_advise_Release(IMFQualityAdvise *iface)
1928 struct video_presenter *presenter = impl_from_IMFQualityAdvise(iface);
1929 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
1932 static HRESULT WINAPI video_presenter_quality_advise_SetDropMode(IMFQualityAdvise *iface,
1933 MF_QUALITY_DROP_MODE mode)
1935 FIXME("%p, %u.\n", iface, mode);
1937 return E_NOTIMPL;
1940 static HRESULT WINAPI video_presenter_quality_advise_SetQualityLevel(IMFQualityAdvise *iface,
1941 MF_QUALITY_LEVEL level)
1943 FIXME("%p, %u.\n", iface, level);
1945 return E_NOTIMPL;
1948 static HRESULT WINAPI video_presenter_quality_advise_GetDropMode(IMFQualityAdvise *iface,
1949 MF_QUALITY_DROP_MODE *mode)
1951 FIXME("%p, %p.\n", iface, mode);
1953 return E_NOTIMPL;
1956 static HRESULT WINAPI video_presenter_quality_advise_GetQualityLevel(IMFQualityAdvise *iface,
1957 MF_QUALITY_LEVEL *level)
1959 FIXME("%p, %p.\n", iface, level);
1961 return E_NOTIMPL;
1964 static HRESULT WINAPI video_presenter_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
1966 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
1968 return E_NOTIMPL;
1971 static const IMFQualityAdviseVtbl video_presenter_quality_advise_vtbl =
1973 video_presenter_quality_advise_QueryInterface,
1974 video_presenter_quality_advise_AddRef,
1975 video_presenter_quality_advise_Release,
1976 video_presenter_quality_advise_SetDropMode,
1977 video_presenter_quality_advise_SetQualityLevel,
1978 video_presenter_quality_advise_GetDropMode,
1979 video_presenter_quality_advise_GetQualityLevel,
1980 video_presenter_quality_advise_DropTime,
1983 static HRESULT WINAPI video_presenter_device_manager_QueryInterface(IDirect3DDeviceManager9 *iface,
1984 REFIID riid, void **obj)
1986 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1987 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
1990 static ULONG WINAPI video_presenter_device_manager_AddRef(IDirect3DDeviceManager9 *iface)
1992 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1993 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
1996 static ULONG WINAPI video_presenter_device_manager_Release(IDirect3DDeviceManager9 *iface)
1998 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
1999 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
2002 static HRESULT WINAPI video_presenter_device_manager_ResetDevice(IDirect3DDeviceManager9 *iface,
2003 IDirect3DDevice9 *device, UINT token)
2005 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2006 return IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, token);
2009 static HRESULT WINAPI video_presenter_device_manager_OpenDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE *hdevice)
2011 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2012 return IDirect3DDeviceManager9_OpenDeviceHandle(presenter->device_manager, hdevice);
2015 static HRESULT WINAPI video_presenter_device_manager_CloseDeviceHandle(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
2017 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2018 return IDirect3DDeviceManager9_CloseDeviceHandle(presenter->device_manager, hdevice);
2021 static HRESULT WINAPI video_presenter_device_manager_TestDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice)
2023 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2024 return IDirect3DDeviceManager9_TestDevice(presenter->device_manager, hdevice);
2027 static HRESULT WINAPI video_presenter_device_manager_LockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
2028 IDirect3DDevice9 **device, BOOL block)
2030 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2031 return IDirect3DDeviceManager9_LockDevice(presenter->device_manager, hdevice, device, block);
2034 static HRESULT WINAPI video_presenter_device_manager_UnlockDevice(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
2035 BOOL savestate)
2037 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2038 return IDirect3DDeviceManager9_UnlockDevice(presenter->device_manager, hdevice, savestate);
2041 static HRESULT WINAPI video_presenter_device_manager_GetVideoService(IDirect3DDeviceManager9 *iface, HANDLE hdevice,
2042 REFIID riid, void **service)
2044 struct video_presenter *presenter = impl_from_IDirect3DDeviceManager9(iface);
2045 return IDirect3DDeviceManager9_GetVideoService(presenter->device_manager, hdevice, riid, service);
2048 static const IDirect3DDeviceManager9Vtbl video_presenter_device_manager_vtbl =
2050 video_presenter_device_manager_QueryInterface,
2051 video_presenter_device_manager_AddRef,
2052 video_presenter_device_manager_Release,
2053 video_presenter_device_manager_ResetDevice,
2054 video_presenter_device_manager_OpenDeviceHandle,
2055 video_presenter_device_manager_CloseDeviceHandle,
2056 video_presenter_device_manager_TestDevice,
2057 video_presenter_device_manager_LockDevice,
2058 video_presenter_device_manager_UnlockDevice,
2059 video_presenter_device_manager_GetVideoService,
2062 static HRESULT WINAPI video_presenter_qa_limits_QueryInterface(IMFQualityAdviseLimits *iface, REFIID riid, void **obj)
2064 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
2065 return IMFVideoPresenter_QueryInterface(&presenter->IMFVideoPresenter_iface, riid, obj);
2068 static ULONG WINAPI video_presenter_qa_limits_AddRef(IMFQualityAdviseLimits *iface)
2070 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
2071 return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface);
2074 static ULONG WINAPI video_presenter_qa_limits_Release(IMFQualityAdviseLimits *iface)
2076 struct video_presenter *presenter = impl_from_IMFQualityAdviseLimits(iface);
2077 return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface);
2080 static HRESULT WINAPI video_presenter_qa_limits_GetMaximumDropMode(IMFQualityAdviseLimits *iface, MF_QUALITY_DROP_MODE *mode)
2082 FIXME("%p, %p.\n", iface, mode);
2084 return E_NOTIMPL;
2087 static HRESULT WINAPI video_presenter_qa_limits_GetMinimumQualityLevel(IMFQualityAdviseLimits *iface, MF_QUALITY_LEVEL *level)
2089 FIXME("%p, %p.\n", iface, level);
2091 return E_NOTIMPL;
2094 static const IMFQualityAdviseLimitsVtbl video_presenter_qa_limits_vtbl =
2096 video_presenter_qa_limits_QueryInterface,
2097 video_presenter_qa_limits_AddRef,
2098 video_presenter_qa_limits_Release,
2099 video_presenter_qa_limits_GetMaximumDropMode,
2100 video_presenter_qa_limits_GetMinimumQualityLevel,
2103 HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
2105 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
2107 *obj = NULL;
2109 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
2110 return E_INVALIDARG;
2112 return CoCreateInstance(&CLSID_MFVideoPresenter9, owner, CLSCTX_INPROC_SERVER, riid, obj);
2115 static HRESULT video_presenter_init_d3d(struct video_presenter *presenter)
2117 D3DPRESENT_PARAMETERS present_params = { 0 };
2118 IDirect3DDevice9 *device;
2119 IDirect3D9 *d3d;
2120 HRESULT hr;
2122 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2124 present_params.BackBufferCount = 1;
2125 present_params.SwapEffect = D3DSWAPEFFECT_COPY;
2126 present_params.hDeviceWindow = GetDesktopWindow();
2127 present_params.Windowed = TRUE;
2128 present_params.Flags = D3DPRESENTFLAG_VIDEO;
2129 present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
2130 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
2131 D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_params, &device);
2133 IDirect3D9_Release(d3d);
2135 if (FAILED(hr))
2137 WARN("Failed to create d3d device, hr %#lx.\n", hr);
2138 return hr;
2141 hr = IDirect3DDeviceManager9_ResetDevice(presenter->device_manager, device, presenter->reset_token);
2142 IDirect3DDevice9_Release(device);
2143 if (FAILED(hr))
2144 WARN("Failed to set new device for the manager, hr %#lx.\n", hr);
2146 if (SUCCEEDED(hr = create_video_sample_allocator(FALSE, &IID_IMFVideoSampleAllocator, (void **)&presenter->allocator)))
2148 hr = IMFVideoSampleAllocator_SetDirectXManager(presenter->allocator, (IUnknown *)presenter->device_manager);
2151 return hr;
2154 HRESULT evr_presenter_create(IUnknown *outer, void **out)
2156 struct video_presenter *object;
2157 HRESULT hr;
2159 *out = NULL;
2161 if (!(object = calloc(1, sizeof(*object))))
2162 return E_OUTOFMEMORY;
2164 object->IMFVideoPresenter_iface.lpVtbl = &video_presenter_vtbl;
2165 object->IMFVideoDeviceID_iface.lpVtbl = &video_presenter_device_id_vtbl;
2166 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_presenter_service_client_vtbl;
2167 object->IMFVideoDisplayControl_iface.lpVtbl = &video_presenter_control_vtbl;
2168 object->IMFRateSupport_iface.lpVtbl = &video_presenter_rate_support_vtbl;
2169 object->IMFGetService_iface.lpVtbl = &video_presenter_getservice_vtbl;
2170 object->IMFVideoPositionMapper_iface.lpVtbl = &video_presenter_position_mapper_vtbl;
2171 object->IQualProp_iface.lpVtbl = &video_presenter_qualprop_vtbl;
2172 object->IMFQualityAdvise_iface.lpVtbl = &video_presenter_quality_advise_vtbl;
2173 object->IMFQualityAdviseLimits_iface.lpVtbl = &video_presenter_qa_limits_vtbl;
2174 object->allocator_cb.lpVtbl = &video_presenter_allocator_cb_vtbl;
2175 object->IUnknown_inner.lpVtbl = &video_presenter_inner_vtbl;
2176 object->IDirect3DDeviceManager9_iface.lpVtbl = &video_presenter_device_manager_vtbl;
2177 object->outer_unk = outer ? outer : &object->IUnknown_inner;
2178 object->refcount = 1;
2179 object->src_rect.right = object->src_rect.bottom = 1.0f;
2180 object->ar_mode = MFVideoARMode_PreservePicture | MFVideoARMode_PreservePixel;
2181 object->allocator_capacity = 3;
2182 InitializeCriticalSection(&object->cs);
2184 if (FAILED(hr = DXVA2CreateDirect3DDeviceManager9(&object->reset_token, &object->device_manager)))
2185 goto failed;
2187 if (FAILED(hr = video_presenter_init_d3d(object)))
2189 WARN("Failed to initialize d3d device, hr %#lx.\n", hr);
2190 goto failed;
2193 *out = &object->IUnknown_inner;
2195 return S_OK;
2197 failed:
2199 IUnknown_Release(&object->IUnknown_inner);
2201 return hr;