wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / evr / mixer.c
blobc59ec00234032967aacf4dbc3d67bce6acc7d935
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 "dxva2api.h"
24 #include "mfapi.h"
25 #include "mferror.h"
27 #include "evr_classes.h"
29 #include "initguid.h"
30 #include "evr9.h"
31 #include "evcode.h"
33 #include "wine/debug.h"
34 #include "wine/heap.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(evr);
38 #define MAX_MIXER_INPUT_STREAMS 16
40 struct input_stream
42 unsigned int id;
43 IMFAttributes *attributes;
44 IMFMediaType *media_type;
45 MFVideoNormalizedRect rect;
46 unsigned int zorder;
47 IMFSample *sample;
48 unsigned int sample_requested : 1;
51 struct rt_format
53 GUID device;
54 D3DFORMAT format;
55 IMFMediaType *media_type;
58 struct output_stream
60 IMFMediaType *media_type;
61 struct rt_format *rt_formats;
62 unsigned int rt_formats_count;
65 struct video_mixer
67 IMFTransform IMFTransform_iface;
68 IMFVideoDeviceID IMFVideoDeviceID_iface;
69 IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
70 IMFVideoMixerControl2 IMFVideoMixerControl2_iface;
71 IMFGetService IMFGetService_iface;
72 IMFVideoMixerBitmap IMFVideoMixerBitmap_iface;
73 IMFVideoPositionMapper IMFVideoPositionMapper_iface;
74 IMFVideoProcessor IMFVideoProcessor_iface;
75 IMFAttributes IMFAttributes_iface;
76 IMFQualityAdvise IMFQualityAdvise_iface;
77 IMFClockStateSink IMFClockStateSink_iface;
78 IUnknown IUnknown_inner;
79 IUnknown *outer_unk;
80 LONG refcount;
82 struct input_stream inputs[MAX_MIXER_INPUT_STREAMS];
83 unsigned int input_ids[MAX_MIXER_INPUT_STREAMS];
84 unsigned int input_count;
85 struct output_stream output;
87 IDirect3DDeviceManager9 *device_manager;
88 IDirectXVideoProcessor *processor;
89 HANDLE device_handle;
91 IMediaEventSink *event_sink;
92 IMFAttributes *attributes;
93 IMFAttributes *internal_attributes;
94 unsigned int mixing_flags;
95 unsigned int is_streaming;
96 COLORREF bkgnd_color;
97 LONGLONG lower_bound;
98 LONGLONG upper_bound;
99 CRITICAL_SECTION cs;
102 static struct video_mixer *impl_from_IUnknown(IUnknown *iface)
104 return CONTAINING_RECORD(iface, struct video_mixer, IUnknown_inner);
107 static struct video_mixer *impl_from_IMFTransform(IMFTransform *iface)
109 return CONTAINING_RECORD(iface, struct video_mixer, IMFTransform_iface);
112 static struct video_mixer *impl_from_IMFVideoDeviceID(IMFVideoDeviceID *iface)
114 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoDeviceID_iface);
117 static struct video_mixer *impl_from_IMFTopologyServiceLookupClient(IMFTopologyServiceLookupClient *iface)
119 return CONTAINING_RECORD(iface, struct video_mixer, IMFTopologyServiceLookupClient_iface);
122 static struct video_mixer *impl_from_IMFVideoMixerControl2(IMFVideoMixerControl2 *iface)
124 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoMixerControl2_iface);
127 static struct video_mixer *impl_from_IMFGetService(IMFGetService *iface)
129 return CONTAINING_RECORD(iface, struct video_mixer, IMFGetService_iface);
132 static struct video_mixer *impl_from_IMFVideoMixerBitmap(IMFVideoMixerBitmap *iface)
134 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoMixerBitmap_iface);
137 static struct video_mixer *impl_from_IMFVideoPositionMapper(IMFVideoPositionMapper *iface)
139 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoPositionMapper_iface);
142 static struct video_mixer *impl_from_IMFVideoProcessor(IMFVideoProcessor *iface)
144 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoProcessor_iface);
147 static struct video_mixer *impl_from_IMFAttributes(IMFAttributes *iface)
149 return CONTAINING_RECORD(iface, struct video_mixer, IMFAttributes_iface);
152 static struct video_mixer *impl_from_IMFQualityAdvise(IMFQualityAdvise *iface)
154 return CONTAINING_RECORD(iface, struct video_mixer, IMFQualityAdvise_iface);
157 static struct video_mixer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
159 return CONTAINING_RECORD(iface, struct video_mixer, IMFClockStateSink_iface);
162 static int __cdecl video_mixer_compare_input_id(const void *a, const void *b)
164 const unsigned int *key = a;
165 const struct input_stream *input = b;
167 if (*key > input->id) return 1;
168 if (*key < input->id) return -1;
169 return 0;
172 static HRESULT video_mixer_get_input(const struct video_mixer *mixer, unsigned int id, struct input_stream **stream)
174 *stream = bsearch(&id, mixer->inputs, mixer->input_count, sizeof(*mixer->inputs), video_mixer_compare_input_id);
175 return *stream ? S_OK : MF_E_INVALIDSTREAMNUMBER;
178 static void video_mixer_init_input(struct input_stream *stream)
180 if (SUCCEEDED(MFCreateAttributes(&stream->attributes, 1)))
181 IMFAttributes_SetUINT32(stream->attributes, &MF_SA_REQUIRED_SAMPLE_COUNT, 1);
182 stream->rect.left = stream->rect.top = 0.0f;
183 stream->rect.right = stream->rect.bottom = 1.0f;
186 static void video_mixer_clear_types(struct video_mixer *mixer)
188 unsigned int i;
190 for (i = 0; i < mixer->input_count; ++i)
192 if (mixer->inputs[i].media_type)
193 IMFMediaType_Release(mixer->inputs[i].media_type);
194 mixer->inputs[i].media_type = NULL;
195 if (mixer->inputs[i].sample)
196 IMFSample_Release(mixer->inputs[i].sample);
197 mixer->inputs[i].sample = NULL;
199 for (i = 0; i < mixer->output.rt_formats_count; ++i)
201 IMFMediaType_Release(mixer->output.rt_formats[i].media_type);
203 heap_free(mixer->output.rt_formats);
204 if (mixer->output.media_type)
205 IMFMediaType_Release(mixer->output.media_type);
206 mixer->output.media_type = NULL;
209 static HRESULT WINAPI video_mixer_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
211 struct video_mixer *mixer = impl_from_IUnknown(iface);
213 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
215 if (IsEqualIID(riid, &IID_IUnknown))
217 *obj = iface;
219 else if (IsEqualIID(riid, &IID_IMFTransform))
221 *obj = &mixer->IMFTransform_iface;
223 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
225 *obj = &mixer->IMFVideoDeviceID_iface;
227 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
229 *obj = &mixer->IMFTopologyServiceLookupClient_iface;
231 else if (IsEqualIID(riid, &IID_IMFVideoMixerControl2) ||
232 IsEqualIID(riid, &IID_IMFVideoMixerControl))
234 *obj = &mixer->IMFVideoMixerControl2_iface;
236 else if (IsEqualIID(riid, &IID_IMFGetService))
238 *obj = &mixer->IMFGetService_iface;
240 else if (IsEqualIID(riid, &IID_IMFVideoMixerBitmap))
242 *obj = &mixer->IMFVideoMixerBitmap_iface;
244 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
246 *obj = &mixer->IMFVideoPositionMapper_iface;
248 else if (IsEqualIID(riid, &IID_IMFVideoProcessor))
250 *obj = &mixer->IMFVideoProcessor_iface;
252 else if (IsEqualIID(riid, &IID_IMFAttributes))
254 *obj = &mixer->IMFAttributes_iface;
256 else if (IsEqualIID(riid, &IID_IMFQualityAdvise))
258 *obj = &mixer->IMFQualityAdvise_iface;
260 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
262 *obj = &mixer->IMFClockStateSink_iface;
264 else
266 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
267 *obj = NULL;
268 return E_NOINTERFACE;
271 IUnknown_AddRef((IUnknown *)*obj);
272 return S_OK;
275 static ULONG WINAPI video_mixer_inner_AddRef(IUnknown *iface)
277 struct video_mixer *mixer = impl_from_IUnknown(iface);
278 ULONG refcount = InterlockedIncrement(&mixer->refcount);
280 TRACE("%p, refcount %u.\n", iface, refcount);
282 return refcount;
285 static void video_mixer_release_device_manager(struct video_mixer *mixer)
287 if (mixer->processor)
288 IDirectXVideoProcessor_Release(mixer->processor);
289 if (mixer->device_manager)
291 IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, mixer->device_handle);
292 IDirect3DDeviceManager9_Release(mixer->device_manager);
294 mixer->device_handle = NULL;
295 mixer->device_manager = NULL;
296 mixer->processor = NULL;
299 static ULONG WINAPI video_mixer_inner_Release(IUnknown *iface)
301 struct video_mixer *mixer = impl_from_IUnknown(iface);
302 ULONG refcount = InterlockedDecrement(&mixer->refcount);
303 unsigned int i;
305 TRACE("%p, refcount %u.\n", iface, refcount);
307 if (!refcount)
309 for (i = 0; i < mixer->input_count; ++i)
311 if (mixer->inputs[i].attributes)
312 IMFAttributes_Release(mixer->inputs[i].attributes);
314 video_mixer_clear_types(mixer);
315 video_mixer_release_device_manager(mixer);
316 if (mixer->attributes)
317 IMFAttributes_Release(mixer->attributes);
318 if (mixer->internal_attributes)
319 IMFAttributes_Release(mixer->internal_attributes);
320 DeleteCriticalSection(&mixer->cs);
321 free(mixer);
324 return refcount;
327 static const IUnknownVtbl video_mixer_inner_vtbl =
329 video_mixer_inner_QueryInterface,
330 video_mixer_inner_AddRef,
331 video_mixer_inner_Release,
334 static HRESULT WINAPI video_mixer_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
336 struct video_mixer *mixer = impl_from_IMFTransform(iface);
337 return IUnknown_QueryInterface(mixer->outer_unk, riid, obj);
340 static ULONG WINAPI video_mixer_transform_AddRef(IMFTransform *iface)
342 struct video_mixer *mixer = impl_from_IMFTransform(iface);
343 return IUnknown_AddRef(mixer->outer_unk);
346 static ULONG WINAPI video_mixer_transform_Release(IMFTransform *iface)
348 struct video_mixer *mixer = impl_from_IMFTransform(iface);
349 return IUnknown_Release(mixer->outer_unk);
352 static HRESULT WINAPI video_mixer_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
353 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
355 TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
357 *input_minimum = 1;
358 *input_maximum = MAX_MIXER_INPUT_STREAMS;
359 *output_minimum = 1;
360 *output_maximum = 1;
362 return S_OK;
365 static HRESULT WINAPI video_mixer_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
367 struct video_mixer *mixer = impl_from_IMFTransform(iface);
369 TRACE("%p, %p, %p.\n", iface, inputs, outputs);
371 EnterCriticalSection(&mixer->cs);
372 if (inputs) *inputs = mixer->input_count;
373 if (outputs) *outputs = 1;
374 LeaveCriticalSection(&mixer->cs);
376 return S_OK;
379 static HRESULT WINAPI video_mixer_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
380 DWORD output_size, DWORD *outputs)
382 struct video_mixer *mixer = impl_from_IMFTransform(iface);
383 HRESULT hr = S_OK;
385 TRACE("%p, %u, %p, %u, %p.\n", iface, input_size, inputs, output_size, outputs);
387 EnterCriticalSection(&mixer->cs);
388 if (mixer->input_count > input_size || !output_size)
389 hr = MF_E_BUFFERTOOSMALL;
390 else if (inputs)
391 memcpy(inputs, mixer->input_ids, mixer->input_count * sizeof(*inputs));
392 if (outputs) *outputs = 0;
393 LeaveCriticalSection(&mixer->cs);
395 return hr;
398 static HRESULT WINAPI video_mixer_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
400 struct video_mixer *mixer = impl_from_IMFTransform(iface);
401 struct input_stream *input;
402 HRESULT hr;
404 TRACE("%p, %u, %p.\n", iface, id, info);
406 EnterCriticalSection(&mixer->cs);
408 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
410 memset(info, 0, sizeof(*info));
411 if (id)
412 info->dwFlags |= MFT_INPUT_STREAM_REMOVABLE | MFT_INPUT_STREAM_OPTIONAL;
415 LeaveCriticalSection(&mixer->cs);
417 return hr;
420 static HRESULT WINAPI video_mixer_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
422 TRACE("%p, %u, %p.\n", iface, id, info);
424 if (id)
425 return MF_E_INVALIDSTREAMNUMBER;
427 memset(info, 0, sizeof(*info));
429 return S_OK;
432 static HRESULT WINAPI video_mixer_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
434 struct video_mixer *mixer = impl_from_IMFTransform(iface);
436 TRACE("%p, %p.\n", iface, attributes);
438 if (!attributes)
439 return E_POINTER;
441 *attributes = mixer->attributes;
442 IMFAttributes_AddRef(*attributes);
444 return S_OK;
447 static HRESULT WINAPI video_mixer_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
448 IMFAttributes **attributes)
450 struct video_mixer *mixer = impl_from_IMFTransform(iface);
451 struct input_stream *input;
452 HRESULT hr;
454 TRACE("%p, %u, %p.\n", iface, id, attributes);
456 EnterCriticalSection(&mixer->cs);
458 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
460 *attributes = input->attributes;
461 if (*attributes)
462 IMFAttributes_AddRef(*attributes);
465 LeaveCriticalSection(&mixer->cs);
467 return hr;
470 static HRESULT WINAPI video_mixer_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
471 IMFAttributes **attributes)
473 TRACE("%p, %u, %p.\n", iface, id, attributes);
475 return E_NOTIMPL;
478 static HRESULT WINAPI video_mixer_transform_DeleteInputStream(IMFTransform *iface, DWORD id)
480 struct video_mixer *mixer = impl_from_IMFTransform(iface);
481 struct input_stream *input;
482 unsigned int idx;
483 HRESULT hr;
485 TRACE("%p, %u.\n", iface, id);
487 if (!id)
488 return MF_E_INVALIDSTREAMNUMBER;
490 EnterCriticalSection(&mixer->cs);
492 /* Can't delete reference stream. */
493 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
495 mixer->input_count--;
496 idx = input - mixer->inputs;
497 if (idx < mixer->input_count)
499 if (mixer->inputs[idx].attributes)
500 IMFAttributes_Release(mixer->inputs[idx].attributes);
501 memmove(&mixer->inputs[idx], &mixer->inputs[idx + 1], (mixer->input_count - idx) * sizeof(*mixer->inputs));
502 memmove(&mixer->input_ids[idx], &mixer->input_ids[idx + 1], (mixer->input_count - idx) *
503 sizeof(*mixer->input_ids));
507 LeaveCriticalSection(&mixer->cs);
509 return hr;
512 static int __cdecl video_mixer_add_input_sort_compare(const void *a, const void *b)
514 const struct input_stream *left = a, *right = b;
515 return left->id != right->id ? (left->id < right->id ? -1 : 1) : 0;
518 static HRESULT WINAPI video_mixer_transform_AddInputStreams(IMFTransform *iface, DWORD count, DWORD *ids)
520 struct video_mixer *mixer = impl_from_IMFTransform(iface);
521 struct input_stream inputs[MAX_MIXER_INPUT_STREAMS] = { {0} };
522 struct input_stream *input;
523 unsigned int i, len;
524 HRESULT hr = S_OK;
526 TRACE("%p, %u, %p.\n", iface, count, ids);
528 if (!ids)
529 return E_POINTER;
531 EnterCriticalSection(&mixer->cs);
532 if (count > ARRAY_SIZE(mixer->inputs) - mixer->input_count)
533 hr = E_INVALIDARG;
534 else
536 /* Test for collisions. */
537 memcpy(inputs, mixer->inputs, mixer->input_count * sizeof(*inputs));
538 for (i = 0; i < count; ++i)
539 inputs[i + mixer->input_count].id = ids[i];
541 len = mixer->input_count + count;
543 qsort(inputs, len, sizeof(*inputs), video_mixer_add_input_sort_compare);
545 for (i = 1; i < len; ++i)
547 if (inputs[i - 1].id == inputs[i].id)
549 hr = E_INVALIDARG;
550 break;
554 if (SUCCEEDED(hr))
556 unsigned int zorder = mixer->input_count;
558 for (i = 0; i < count; ++i)
560 if ((input = bsearch(&ids[i], inputs, len, sizeof(*inputs), video_mixer_compare_input_id)))
561 video_mixer_init_input(input);
563 memcpy(&mixer->input_ids[mixer->input_count], ids, count * sizeof(*ids));
564 memcpy(mixer->inputs, inputs, len * sizeof(*inputs));
565 mixer->input_count += count;
567 for (i = 0; i < count; ++i)
569 if (SUCCEEDED(video_mixer_get_input(mixer, ids[i], &input)))
570 input->zorder = zorder;
571 zorder++;
575 LeaveCriticalSection(&mixer->cs);
577 return hr;
580 static HRESULT WINAPI video_mixer_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
581 IMFMediaType **type)
583 TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
585 return E_NOTIMPL;
588 static HRESULT WINAPI video_mixer_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
589 IMFMediaType **type)
591 struct video_mixer *mixer = impl_from_IMFTransform(iface);
592 HRESULT hr = S_OK;
594 TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
596 if (id)
597 return MF_E_INVALIDSTREAMNUMBER;
599 EnterCriticalSection(&mixer->cs);
601 if (!mixer->inputs[0].media_type)
602 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
603 else if (index >= mixer->output.rt_formats_count)
604 hr = MF_E_NO_MORE_TYPES;
605 else
607 *type = mixer->output.rt_formats[index].media_type;
608 IMFMediaType_AddRef(*type);
611 LeaveCriticalSection(&mixer->cs);
613 return hr;
616 static HRESULT video_mixer_init_dxva_videodesc(IMFMediaType *media_type, DXVA2_VideoDesc *video_desc)
618 const MFVIDEOFORMAT *video_format;
619 IMFVideoMediaType *video_type;
620 BOOL is_compressed = TRUE;
621 HRESULT hr = S_OK;
623 if (FAILED(IMFMediaType_QueryInterface(media_type, &IID_IMFVideoMediaType, (void **)&video_type)))
624 return MF_E_INVALIDMEDIATYPE;
626 video_format = IMFVideoMediaType_GetVideoFormat(video_type);
627 IMFVideoMediaType_IsCompressedFormat(video_type, &is_compressed);
629 if (!video_format || !video_format->videoInfo.dwWidth || !video_format->videoInfo.dwHeight || is_compressed)
631 hr = MF_E_INVALIDMEDIATYPE;
632 goto done;
635 memset(video_desc, 0, sizeof(*video_desc));
636 video_desc->SampleWidth = video_format->videoInfo.dwWidth;
637 video_desc->SampleHeight = video_format->videoInfo.dwHeight;
638 video_desc->Format = video_format->surfaceInfo.Format;
640 done:
641 IMFVideoMediaType_Release(video_type);
643 return hr;
646 static int __cdecl rt_formats_sort_compare(const void *left, const void *right)
648 const struct rt_format *format1 = left, *format2 = right;
650 if (format1->format < format2->format) return -1;
651 if (format1->format > format2->format) return 1;
652 return 0;
655 static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const DXVA2_VideoDesc *video_desc,
656 IMFMediaType *media_type, IDirectXVideoProcessorService *service, unsigned int device_count,
657 const GUID *devices, unsigned int flags)
659 unsigned int i, j, format_count, count;
660 struct rt_format *rt_formats = NULL, *ptr;
661 HRESULT hr = MF_E_INVALIDMEDIATYPE;
662 D3DFORMAT *formats;
663 GUID subtype;
665 count = 0;
666 for (i = 0; i < device_count; ++i)
668 if (SUCCEEDED(IDirectXVideoProcessorService_GetVideoProcessorRenderTargets(service, &devices[i], video_desc,
669 &format_count, &formats)))
671 if (!(ptr = heap_realloc(rt_formats, (count + format_count) * sizeof(*rt_formats))))
673 hr = E_OUTOFMEMORY;
674 count = 0;
675 CoTaskMemFree(formats);
676 break;
678 rt_formats = ptr;
680 for (j = 0; j < format_count; ++j)
682 rt_formats[count + j].format = formats[j];
683 rt_formats[count + j].device = devices[i];
685 count += format_count;
687 CoTaskMemFree(formats);
691 if (count && !(flags & MFT_SET_TYPE_TEST_ONLY))
693 qsort(rt_formats, count, sizeof(*rt_formats), rt_formats_sort_compare);
695 j = 0;
696 for (i = j + 1; i < count; ++i)
698 if (rt_formats[i].format != rt_formats[j].format)
700 rt_formats[++j] = rt_formats[i];
703 count = j + 1;
705 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
706 if ((mixer->output.rt_formats = heap_calloc(count, sizeof(*mixer->output.rt_formats))))
708 for (i = 0; i < count; ++i)
710 IMFMediaType *rt_media_type;
712 subtype.Data1 = rt_formats[i].format;
713 mixer->output.rt_formats[i] = rt_formats[i];
715 MFCreateMediaType(&rt_media_type);
716 IMFMediaType_CopyAllItems(media_type, (IMFAttributes *)rt_media_type);
717 IMFMediaType_SetGUID(rt_media_type, &MF_MT_SUBTYPE, &subtype);
719 mixer->output.rt_formats[i].media_type = rt_media_type;
721 mixer->output.rt_formats_count = count;
723 else
725 hr = E_OUTOFMEMORY;
726 count = 0;
730 heap_free(rt_formats);
732 return count ? S_OK : hr;
735 static HRESULT video_mixer_open_device_handle(struct video_mixer *mixer)
737 IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, mixer->device_handle);
738 mixer->device_handle = NULL;
739 return IDirect3DDeviceManager9_OpenDeviceHandle(mixer->device_manager, &mixer->device_handle);
742 static HRESULT video_mixer_get_processor_service(struct video_mixer *mixer, IDirectXVideoProcessorService **service)
744 HRESULT hr;
746 if (!mixer->device_handle)
748 if (FAILED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(mixer->device_manager, &mixer->device_handle)))
749 return hr;
752 for (;;)
754 hr = IDirect3DDeviceManager9_GetVideoService(mixer->device_manager, mixer->device_handle,
755 &IID_IDirectXVideoProcessorService, (void **)service);
756 if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
758 if (SUCCEEDED(hr = video_mixer_open_device_handle(mixer)))
759 continue;
761 break;
764 return hr;
767 static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *media_type, DWORD flags)
769 struct video_mixer *mixer = impl_from_IMFTransform(iface);
770 IDirectXVideoProcessorService *service;
771 DXVA2_VideoDesc video_desc;
772 HRESULT hr = E_NOTIMPL;
773 unsigned int count;
774 GUID *guids;
776 TRACE("%p, %u, %p, %#x.\n", iface, id, media_type, flags);
778 EnterCriticalSection(&mixer->cs);
780 if (!(flags & MFT_SET_TYPE_TEST_ONLY))
781 video_mixer_clear_types(mixer);
783 if (!mixer->device_manager)
784 hr = MF_E_NOT_INITIALIZED;
785 else
787 if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
789 if (SUCCEEDED(hr = video_mixer_init_dxva_videodesc(media_type, &video_desc)))
791 if (!id)
793 if (SUCCEEDED(hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc,
794 &count, &guids)))
796 if (SUCCEEDED(hr = video_mixer_collect_output_types(mixer, &video_desc, media_type,
797 service, count, guids, flags)) && !(flags & MFT_SET_TYPE_TEST_ONLY))
799 if (mixer->inputs[0].media_type)
800 IMFMediaType_Release(mixer->inputs[0].media_type);
801 mixer->inputs[0].media_type = media_type;
802 IMFMediaType_AddRef(mixer->inputs[0].media_type);
804 CoTaskMemFree(guids);
807 else
809 FIXME("Unimplemented for substreams.\n");
810 hr = E_NOTIMPL;
813 IDirectXVideoProcessorService_Release(service);
817 LeaveCriticalSection(&mixer->cs);
819 return hr;
822 static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
824 const unsigned int equality_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES |
825 MF_MEDIATYPE_EQUAL_FORMAT_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA;
826 struct video_mixer *mixer = impl_from_IMFTransform(iface);
827 HRESULT hr = MF_E_INVALIDMEDIATYPE;
828 unsigned int i, compare_flags;
830 TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
832 if (id)
833 return MF_E_INVALIDSTREAMNUMBER;
835 EnterCriticalSection(&mixer->cs);
837 for (i = 0; i < mixer->output.rt_formats_count; ++i)
839 compare_flags = 0;
840 if (FAILED(IMFMediaType_IsEqual(type, mixer->output.rt_formats[i].media_type, &compare_flags)))
841 continue;
843 if ((compare_flags & equality_flags) == equality_flags)
845 hr = S_OK;
846 break;
850 if (SUCCEEDED(hr) && !(flags & MFT_SET_TYPE_TEST_ONLY))
852 IDirectXVideoProcessorService *service;
854 if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
856 DXVA2_VideoDesc video_desc;
857 GUID subtype = { 0 };
858 D3DFORMAT rt_format;
860 if (mixer->processor)
861 IDirectXVideoProcessor_Release(mixer->processor);
862 mixer->processor = NULL;
864 video_mixer_init_dxva_videodesc(mixer->inputs[0].media_type, &video_desc);
865 IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype);
866 rt_format = subtype.Data1;
868 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &mixer->output.rt_formats[i].device,
869 &video_desc, rt_format, MAX_MIXER_INPUT_STREAMS, &mixer->processor)))
871 if (mixer->output.media_type)
872 IMFMediaType_Release(mixer->output.media_type);
873 mixer->output.media_type = type;
874 IMFMediaType_AddRef(mixer->output.media_type);
877 IDirectXVideoProcessorService_Release(service);
881 LeaveCriticalSection(&mixer->cs);
883 return hr;
886 static HRESULT WINAPI video_mixer_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
888 struct video_mixer *mixer = impl_from_IMFTransform(iface);
889 struct input_stream *stream;
890 HRESULT hr;
892 TRACE("%p, %u, %p.\n", iface, id, type);
894 EnterCriticalSection(&mixer->cs);
896 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
898 if (!stream->media_type)
899 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
900 else
902 *type = stream->media_type;
903 IMFMediaType_AddRef(*type);
907 LeaveCriticalSection(&mixer->cs);
909 return hr;
912 static HRESULT WINAPI video_mixer_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
914 struct video_mixer *mixer = impl_from_IMFTransform(iface);
915 HRESULT hr = S_OK;
917 TRACE("%p, %u, %p.\n", iface, id, type);
919 if (id)
920 return MF_E_INVALIDSTREAMNUMBER;
922 EnterCriticalSection(&mixer->cs);
924 if (!mixer->output.media_type)
925 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
926 else
928 *type = mixer->output.media_type;
929 IMFMediaType_AddRef(*type);
932 LeaveCriticalSection(&mixer->cs);
934 return hr;
937 static HRESULT WINAPI video_mixer_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *status)
939 struct video_mixer *mixer = impl_from_IMFTransform(iface);
940 struct input_stream *stream;
941 HRESULT hr;
943 TRACE("%p, %u, %p.\n", iface, id, status);
945 if (!status)
946 return E_POINTER;
948 EnterCriticalSection(&mixer->cs);
950 if (!mixer->output.media_type)
951 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
952 else if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
954 *status = stream->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA;
957 LeaveCriticalSection(&mixer->cs);
959 return hr;
962 static HRESULT WINAPI video_mixer_transform_GetOutputStatus(IMFTransform *iface, DWORD *status)
964 struct video_mixer *mixer = impl_from_IMFTransform(iface);
965 HRESULT hr = S_OK;
966 unsigned int i;
968 TRACE("%p, %p.\n", iface, status);
970 if (!status)
971 return E_POINTER;
973 EnterCriticalSection(&mixer->cs);
975 if (!mixer->output.media_type)
976 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
977 else
979 *status = MFT_OUTPUT_STATUS_SAMPLE_READY;
980 for (i = 0; i < mixer->input_count; ++i)
982 if (!mixer->inputs[i].sample)
984 *status = 0;
985 break;
990 LeaveCriticalSection(&mixer->cs);
992 return hr;
995 static HRESULT WINAPI video_mixer_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
997 struct video_mixer *mixer = impl_from_IMFTransform(iface);
999 TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
1001 EnterCriticalSection(&mixer->cs);
1003 mixer->lower_bound = lower;
1004 mixer->upper_bound = upper;
1006 LeaveCriticalSection(&mixer->cs);
1008 return S_OK;
1011 static HRESULT WINAPI video_mixer_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
1013 FIXME("%p, %u, %p.\n", iface, id, event);
1015 return E_NOTIMPL;
1018 static void video_mixer_request_sample(struct video_mixer *mixer, unsigned int idx)
1020 if (!mixer->event_sink || mixer->inputs[idx].sample_requested)
1021 return;
1023 IMediaEventSink_Notify(mixer->event_sink, EC_SAMPLE_NEEDED, idx, 0);
1024 mixer->inputs[idx].sample_requested = 1;
1027 static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
1029 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1030 HRESULT hr = S_OK;
1031 unsigned int i;
1033 TRACE("%p, %u, %#lx.\n", iface, message, param);
1035 switch (message)
1037 case MFT_MESSAGE_SET_D3D_MANAGER:
1039 EnterCriticalSection(&mixer->cs);
1041 video_mixer_release_device_manager(mixer);
1042 if (param)
1043 hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&mixer->device_manager);
1045 LeaveCriticalSection(&mixer->cs);
1047 break;
1049 case MFT_MESSAGE_COMMAND_FLUSH:
1051 EnterCriticalSection(&mixer->cs);
1053 for (i = 0; i < mixer->input_count; ++i)
1055 if (mixer->inputs[i].sample)
1057 IMFSample_Release(mixer->inputs[i].sample);
1058 mixer->inputs[i].sample = NULL;
1059 mixer->inputs[i].sample_requested = 0;
1063 LeaveCriticalSection(&mixer->cs);
1065 break;
1067 case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
1068 case MFT_MESSAGE_NOTIFY_END_STREAMING:
1070 EnterCriticalSection(&mixer->cs);
1072 if (!mixer->is_streaming)
1074 for (i = 0; i < mixer->input_count; ++i)
1075 video_mixer_request_sample(mixer, i);
1078 mixer->is_streaming = message == MFT_MESSAGE_NOTIFY_BEGIN_STREAMING;
1080 LeaveCriticalSection(&mixer->cs);
1082 break;
1084 case MFT_MESSAGE_COMMAND_DRAIN:
1085 break;
1087 default:
1088 WARN("Message not handled %d.\n", message);
1089 hr = E_NOTIMPL;
1092 return hr;
1095 static HRESULT WINAPI video_mixer_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
1097 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1098 struct input_stream *input;
1099 HRESULT hr;
1101 TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags);
1103 if (!sample)
1104 return E_POINTER;
1106 EnterCriticalSection(&mixer->cs);
1108 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
1110 if (!input->media_type || !mixer->output.media_type)
1111 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1112 else if (input->sample)
1113 hr = MF_E_NOTACCEPTING;
1114 else
1116 mixer->is_streaming = 1;
1117 input->sample_requested = 0;
1118 input->sample = sample;
1119 IMFSample_AddRef(input->sample);
1123 LeaveCriticalSection(&mixer->cs);
1125 return hr;
1128 static HRESULT video_mixer_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface)
1130 IMFMediaBuffer *buffer;
1131 IMFGetService *gs;
1132 HRESULT hr;
1134 if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer)))
1135 return hr;
1137 hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&gs);
1138 IMFMediaBuffer_Release(buffer);
1139 if (FAILED(hr))
1140 return hr;
1142 hr = IMFGetService_GetService(gs, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)surface);
1143 IMFGetService_Release(gs);
1144 return hr;
1147 static HRESULT video_mixer_get_d3d_device(struct video_mixer *mixer, IDirect3DDevice9 **device)
1149 HRESULT hr;
1151 for (;;)
1153 hr = IDirect3DDeviceManager9_LockDevice(mixer->device_manager, mixer->device_handle,
1154 device, TRUE);
1155 if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
1157 if (SUCCEEDED(hr = video_mixer_open_device_handle(mixer)))
1158 continue;
1160 break;
1163 return hr;
1166 static void video_mixer_scale_rect(RECT *rect, unsigned int width, unsigned int height,
1167 const MFVideoNormalizedRect *scale)
1169 if (rect->left == 0.0f && rect->top == 0.0f && rect->right == 1.0f && rect->bottom == 1.0f)
1171 SetRect(rect, 0, 0, width, height);
1173 else
1175 rect->left = width * scale->left;
1176 rect->right = width * scale->right;
1177 rect->top = height * scale->top;
1178 rect->bottom = height * scale->bottom;
1182 static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt)
1184 DXVA2_VideoSample samples[1] = {{ 0 }};
1185 DXVA2_VideoProcessBltParams params = { 0 };
1186 MFVideoNormalizedRect zoom_rect;
1187 struct input_stream *stream;
1188 IDirect3DSurface9 *surface;
1189 D3DSURFACE_DESC desc;
1190 HRESULT hr;
1192 IDirect3DSurface9_GetDesc(rt, &desc);
1194 if (FAILED(IMFAttributes_GetBlob(mixer->attributes, &VIDEO_ZOOM_RECT, (UINT8 *)&zoom_rect,
1195 sizeof(zoom_rect), NULL)))
1197 zoom_rect.left = zoom_rect.top = 0.0f;
1198 zoom_rect.right = zoom_rect.bottom = 1.0f;
1201 video_mixer_scale_rect(&params.TargetRect, desc.Width, desc.Height, &zoom_rect);
1203 /* FIXME: for now only handle reference stream. */
1205 video_mixer_get_input(mixer, 0, &stream);
1207 if (FAILED(hr = video_mixer_get_sample_surface(stream->sample, &surface)))
1209 WARN("Failed to get source surface, hr %#x.\n", hr);
1210 return;
1213 IDirect3DSurface9_GetDesc(surface, &desc);
1215 samples[0].SrcSurface = surface;
1216 SetRect(&samples[0].SrcRect, 0, 0, desc.Width, desc.Height);
1217 video_mixer_scale_rect(&samples[0].DstRect, desc.Width, desc.Height, &stream->rect);
1219 if (FAILED(hr = IDirectXVideoProcessor_VideoProcessBlt(mixer->processor, rt, &params, samples, 1, NULL)))
1220 WARN("Failed to process samples, hr %#x.\n", hr);
1222 IDirect3DSurface9_Release(surface);
1225 static HRESULT video_mixer_get_sample_desired_time(IMFSample *sample, LONGLONG *timestamp, LONGLONG *duration)
1227 IMFDesiredSample *desired;
1228 HRESULT hr;
1230 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFDesiredSample, (void **)&desired)))
1232 hr = IMFDesiredSample_GetDesiredSampleTimeAndDuration(desired, timestamp, duration);
1233 IMFDesiredSample_Release(desired);
1236 return hr;
1239 static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
1240 MFT_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
1242 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1243 LONGLONG timestamp, duration;
1244 IDirect3DSurface9 *surface;
1245 IDirect3DDevice9 *device;
1246 unsigned int i;
1247 HRESULT hr;
1249 TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, buffers, status);
1251 if (!buffers || !count || count > 1 || !buffers->pSample)
1252 return E_INVALIDARG;
1254 if (buffers->dwStreamID)
1255 return MF_E_INVALIDSTREAMNUMBER;
1257 *status = 0;
1259 EnterCriticalSection(&mixer->cs);
1261 if (SUCCEEDED(hr = video_mixer_get_sample_surface(buffers->pSample, &surface)))
1263 if (mixer->is_streaming)
1265 for (i = 0; i < mixer->input_count; ++i)
1267 if (!mixer->inputs[i].sample)
1269 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1270 break;
1274 if (SUCCEEDED(hr))
1276 video_mixer_render(mixer, surface);
1278 timestamp = duration = 0;
1279 if (SUCCEEDED(IMFSample_GetSampleTime(mixer->inputs[0].sample, &timestamp)))
1281 IMFSample_SetSampleTime(buffers->pSample, timestamp);
1283 IMFSample_GetSampleDuration(mixer->inputs[0].sample, &duration);
1284 IMFSample_SetSampleDuration(buffers->pSample, duration);
1288 if (SUCCEEDED(hr))
1290 for (i = 0; i < mixer->input_count; ++i)
1292 if (mixer->inputs[i].sample)
1293 IMFSample_Release(mixer->inputs[i].sample);
1294 mixer->inputs[i].sample = NULL;
1295 video_mixer_request_sample(mixer, i);
1299 else
1301 if (SUCCEEDED(video_mixer_get_sample_desired_time(buffers->pSample, &timestamp, &duration)))
1303 if (SUCCEEDED(hr = video_mixer_get_d3d_device(mixer, &device)))
1305 IDirect3DDevice9_ColorFill(device, surface, NULL, 0);
1306 IDirect3DDeviceManager9_UnlockDevice(mixer->device_manager, mixer->device_handle, FALSE);
1307 IDirect3DDevice9_Release(device);
1310 else
1311 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1313 IDirect3DSurface9_Release(surface);
1316 LeaveCriticalSection(&mixer->cs);
1318 return hr;
1321 static const IMFTransformVtbl video_mixer_transform_vtbl =
1323 video_mixer_transform_QueryInterface,
1324 video_mixer_transform_AddRef,
1325 video_mixer_transform_Release,
1326 video_mixer_transform_GetStreamLimits,
1327 video_mixer_transform_GetStreamCount,
1328 video_mixer_transform_GetStreamIDs,
1329 video_mixer_transform_GetInputStreamInfo,
1330 video_mixer_transform_GetOutputStreamInfo,
1331 video_mixer_transform_GetAttributes,
1332 video_mixer_transform_GetInputStreamAttributes,
1333 video_mixer_transform_GetOutputStreamAttributes,
1334 video_mixer_transform_DeleteInputStream,
1335 video_mixer_transform_AddInputStreams,
1336 video_mixer_transform_GetInputAvailableType,
1337 video_mixer_transform_GetOutputAvailableType,
1338 video_mixer_transform_SetInputType,
1339 video_mixer_transform_SetOutputType,
1340 video_mixer_transform_GetInputCurrentType,
1341 video_mixer_transform_GetOutputCurrentType,
1342 video_mixer_transform_GetInputStatus,
1343 video_mixer_transform_GetOutputStatus,
1344 video_mixer_transform_SetOutputBounds,
1345 video_mixer_transform_ProcessEvent,
1346 video_mixer_transform_ProcessMessage,
1347 video_mixer_transform_ProcessInput,
1348 video_mixer_transform_ProcessOutput,
1351 static HRESULT WINAPI video_mixer_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
1353 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1354 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1357 static ULONG WINAPI video_mixer_device_id_AddRef(IMFVideoDeviceID *iface)
1359 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1360 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1363 static ULONG WINAPI video_mixer_device_id_Release(IMFVideoDeviceID *iface)
1365 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1366 return IMFTransform_Release(&mixer->IMFTransform_iface);
1369 static HRESULT WINAPI video_mixer_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
1371 TRACE("%p, %p.\n", iface, device_id);
1373 if (!device_id)
1374 return E_POINTER;
1376 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
1378 return S_OK;
1381 static const IMFVideoDeviceIDVtbl video_mixer_device_id_vtbl =
1383 video_mixer_device_id_QueryInterface,
1384 video_mixer_device_id_AddRef,
1385 video_mixer_device_id_Release,
1386 video_mixer_device_id_GetDeviceID,
1389 static HRESULT WINAPI video_mixer_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
1390 REFIID riid, void **obj)
1392 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1393 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1396 static ULONG WINAPI video_mixer_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
1398 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1399 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1402 static ULONG WINAPI video_mixer_service_client_Release(IMFTopologyServiceLookupClient *iface)
1404 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1405 return IMFTransform_Release(&mixer->IMFTransform_iface);
1408 static HRESULT WINAPI video_mixer_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
1409 IMFTopologyServiceLookup *service_lookup)
1411 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1412 unsigned int count;
1413 HRESULT hr;
1415 TRACE("%p, %p.\n", iface, service_lookup);
1417 if (!service_lookup)
1418 return E_POINTER;
1420 EnterCriticalSection(&mixer->cs);
1422 count = 1;
1423 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1424 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&mixer->event_sink, &count)))
1426 WARN("Failed to get renderer event sink, hr %#x.\n", hr);
1429 LeaveCriticalSection(&mixer->cs);
1431 return hr;
1434 static HRESULT WINAPI video_mixer_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
1436 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1438 TRACE("%p.\n", iface);
1440 EnterCriticalSection(&mixer->cs);
1442 if (mixer->event_sink)
1443 IMediaEventSink_Release(mixer->event_sink);
1444 mixer->event_sink = NULL;
1446 LeaveCriticalSection(&mixer->cs);
1448 return S_OK;
1451 static const IMFTopologyServiceLookupClientVtbl video_mixer_service_client_vtbl =
1453 video_mixer_service_client_QueryInterface,
1454 video_mixer_service_client_AddRef,
1455 video_mixer_service_client_Release,
1456 video_mixer_service_client_InitServicePointers,
1457 video_mixer_service_client_ReleaseServicePointers,
1460 static HRESULT WINAPI video_mixer_control_QueryInterface(IMFVideoMixerControl2 *iface, REFIID riid, void **obj)
1462 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1463 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1466 static ULONG WINAPI video_mixer_control_AddRef(IMFVideoMixerControl2 *iface)
1468 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1469 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1472 static ULONG WINAPI video_mixer_control_Release(IMFVideoMixerControl2 *iface)
1474 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1475 return IMFTransform_Release(&mixer->IMFTransform_iface);
1478 static HRESULT WINAPI video_mixer_control_SetStreamZOrder(IMFVideoMixerControl2 *iface, DWORD id, DWORD zorder)
1480 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1481 struct input_stream *stream;
1482 HRESULT hr;
1484 TRACE("%p, %u, %u.\n", iface, id, zorder);
1486 /* Can't change reference stream. */
1487 if (!id && zorder)
1488 return E_INVALIDARG;
1490 EnterCriticalSection(&mixer->cs);
1492 if (zorder >= mixer->input_count)
1493 hr = E_INVALIDARG;
1494 else if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1496 /* Lowest zorder only applies to reference stream. */
1497 if (id && !zorder)
1498 hr = MF_E_INVALIDREQUEST;
1499 else
1500 stream->zorder = zorder;
1503 LeaveCriticalSection(&mixer->cs);
1505 return hr;
1508 static HRESULT WINAPI video_mixer_control_GetStreamZOrder(IMFVideoMixerControl2 *iface, DWORD id, DWORD *zorder)
1510 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1511 struct input_stream *stream;
1512 HRESULT hr;
1514 TRACE("%p, %u, %p.\n", iface, id, zorder);
1516 if (!zorder)
1517 return E_POINTER;
1519 EnterCriticalSection(&mixer->cs);
1521 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1522 *zorder = stream->zorder;
1524 LeaveCriticalSection(&mixer->cs);
1526 return hr;
1529 static HRESULT WINAPI video_mixer_control_SetStreamOutputRect(IMFVideoMixerControl2 *iface, DWORD id,
1530 const MFVideoNormalizedRect *rect)
1532 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1533 struct input_stream *stream;
1534 HRESULT hr;
1536 TRACE("%p, %u, %p.\n", iface, id, rect);
1538 if (!rect)
1539 return E_POINTER;
1541 if (rect->left > rect->right || rect->top > rect->bottom ||
1542 rect->left < 0.0f || rect->top < 0.0f || rect->right > 1.0f || rect->bottom > 1.0f)
1544 return E_INVALIDARG;
1547 EnterCriticalSection(&mixer->cs);
1549 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1550 stream->rect = *rect;
1552 LeaveCriticalSection(&mixer->cs);
1554 return hr;
1557 static HRESULT WINAPI video_mixer_control_GetStreamOutputRect(IMFVideoMixerControl2 *iface, DWORD id,
1558 MFVideoNormalizedRect *rect)
1560 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1561 struct input_stream *stream;
1562 HRESULT hr;
1564 TRACE("%p, %u, %p.\n", iface, id, rect);
1566 if (!rect)
1567 return E_POINTER;
1569 EnterCriticalSection(&mixer->cs);
1571 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1572 *rect = stream->rect;
1574 LeaveCriticalSection(&mixer->cs);
1576 return hr;
1579 static HRESULT WINAPI video_mixer_control_SetMixingPrefs(IMFVideoMixerControl2 *iface, DWORD flags)
1581 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1583 TRACE("%p, %#x.\n", iface, flags);
1585 EnterCriticalSection(&mixer->cs);
1586 mixer->mixing_flags = flags;
1587 LeaveCriticalSection(&mixer->cs);
1589 return S_OK;
1592 static HRESULT WINAPI video_mixer_control_GetMixingPrefs(IMFVideoMixerControl2 *iface, DWORD *flags)
1594 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1596 TRACE("%p, %p.\n", iface, flags);
1598 if (!flags)
1599 return E_POINTER;
1601 EnterCriticalSection(&mixer->cs);
1602 *flags = mixer->mixing_flags;
1603 LeaveCriticalSection(&mixer->cs);
1605 return S_OK;
1608 static const IMFVideoMixerControl2Vtbl video_mixer_control_vtbl =
1610 video_mixer_control_QueryInterface,
1611 video_mixer_control_AddRef,
1612 video_mixer_control_Release,
1613 video_mixer_control_SetStreamZOrder,
1614 video_mixer_control_GetStreamZOrder,
1615 video_mixer_control_SetStreamOutputRect,
1616 video_mixer_control_GetStreamOutputRect,
1617 video_mixer_control_SetMixingPrefs,
1618 video_mixer_control_GetMixingPrefs,
1621 static HRESULT WINAPI video_mixer_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1623 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1624 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1627 static ULONG WINAPI video_mixer_getservice_AddRef(IMFGetService *iface)
1629 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1630 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1633 static ULONG WINAPI video_mixer_getservice_Release(IMFGetService *iface)
1635 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1636 return IMFTransform_Release(&mixer->IMFTransform_iface);
1639 static HRESULT WINAPI video_mixer_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1641 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1643 if (IsEqualGUID(service, &MR_VIDEO_MIXER_SERVICE))
1645 if (IsEqualIID(riid, &IID_IMFVideoMixerBitmap) ||
1646 IsEqualIID(riid, &IID_IMFVideoProcessor) ||
1647 IsEqualIID(riid, &IID_IMFVideoPositionMapper) ||
1648 IsEqualIID(riid, &IID_IMFVideoMixerControl) ||
1649 IsEqualIID(riid, &IID_IMFVideoMixerControl2))
1651 return IMFGetService_QueryInterface(iface, riid, obj);
1654 return E_NOINTERFACE;
1657 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1659 return MF_E_UNSUPPORTED_SERVICE;
1662 static const IMFGetServiceVtbl video_mixer_getservice_vtbl =
1664 video_mixer_getservice_QueryInterface,
1665 video_mixer_getservice_AddRef,
1666 video_mixer_getservice_Release,
1667 video_mixer_getservice_GetService,
1670 static HRESULT WINAPI video_mixer_bitmap_QueryInterface(IMFVideoMixerBitmap *iface, REFIID riid, void **obj)
1672 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1673 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1676 static ULONG WINAPI video_mixer_bitmap_AddRef(IMFVideoMixerBitmap *iface)
1678 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1679 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1682 static ULONG WINAPI video_mixer_bitmap_Release(IMFVideoMixerBitmap *iface)
1684 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1685 return IMFTransform_Release(&mixer->IMFTransform_iface);
1688 static HRESULT WINAPI video_mixer_bitmap_SetAlphaBitmap(IMFVideoMixerBitmap *iface, const MFVideoAlphaBitmap *bitmap)
1690 FIXME("%p, %p.\n", iface, bitmap);
1692 return E_NOTIMPL;
1695 static HRESULT WINAPI video_mixer_bitmap_ClearAlphaBitmap(IMFVideoMixerBitmap *iface)
1697 FIXME("%p.\n", iface);
1699 return E_NOTIMPL;
1702 static HRESULT WINAPI video_mixer_bitmap_UpdateAlphaBitmapParameters(IMFVideoMixerBitmap *iface,
1703 const MFVideoAlphaBitmapParams *params)
1705 FIXME("%p, %p.\n", iface, params);
1707 return E_NOTIMPL;
1710 static HRESULT WINAPI video_mixer_bitmap_GetAlphaBitmapParameters(IMFVideoMixerBitmap *iface, MFVideoAlphaBitmapParams *params)
1712 FIXME("%p, %p.\n", iface, params);
1714 return E_NOTIMPL;
1717 static const IMFVideoMixerBitmapVtbl video_mixer_bitmap_vtbl =
1719 video_mixer_bitmap_QueryInterface,
1720 video_mixer_bitmap_AddRef,
1721 video_mixer_bitmap_Release,
1722 video_mixer_bitmap_SetAlphaBitmap,
1723 video_mixer_bitmap_ClearAlphaBitmap,
1724 video_mixer_bitmap_UpdateAlphaBitmapParameters,
1725 video_mixer_bitmap_GetAlphaBitmapParameters,
1728 static HRESULT WINAPI video_mixer_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1730 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1731 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1734 static ULONG WINAPI video_mixer_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1736 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1737 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1740 static ULONG WINAPI video_mixer_position_mapper_Release(IMFVideoPositionMapper *iface)
1742 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1743 return IMFTransform_Release(&mixer->IMFTransform_iface);
1746 static HRESULT WINAPI video_mixer_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1747 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1749 FIXME("%p, %f, %f, %u, %u, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1751 return E_NOTIMPL;
1754 static const IMFVideoPositionMapperVtbl video_mixer_position_mapper_vtbl =
1756 video_mixer_position_mapper_QueryInterface,
1757 video_mixer_position_mapper_AddRef,
1758 video_mixer_position_mapper_Release,
1759 video_mixer_position_mapper_MapOutputCoordinateToInputStream,
1762 static HRESULT WINAPI video_mixer_processor_QueryInterface(IMFVideoProcessor *iface, REFIID riid, void **obj)
1764 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1765 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1768 static ULONG WINAPI video_mixer_processor_AddRef(IMFVideoProcessor *iface)
1770 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1771 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1774 static ULONG WINAPI video_mixer_processor_Release(IMFVideoProcessor *iface)
1776 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1777 return IMFTransform_Release(&mixer->IMFTransform_iface);
1780 static HRESULT WINAPI video_mixer_processor_GetAvailableVideoProcessorModes(IMFVideoProcessor *iface, UINT *count,
1781 GUID **modes)
1783 FIXME("%p, %p, %p.\n", iface, count, modes);
1785 return E_NOTIMPL;
1788 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorCaps(IMFVideoProcessor *iface, GUID *mode,
1789 DXVA2_VideoProcessorCaps *caps)
1791 FIXME("%p, %s, %p.\n", iface, debugstr_guid(mode), caps);
1793 return E_NOTIMPL;
1796 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1798 FIXME("%p, %p.\n", iface, mode);
1800 return E_NOTIMPL;
1803 static HRESULT WINAPI video_mixer_processor_SetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1805 FIXME("%p, %s.\n", iface, debugstr_guid(mode));
1807 return E_NOTIMPL;
1810 static HRESULT WINAPI video_mixer_processor_GetProcAmpRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
1812 FIXME("%p, %#x, %p.\n", iface, prop, range);
1814 return E_NOTIMPL;
1817 static HRESULT WINAPI video_mixer_processor_GetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
1819 FIXME("%p, %#x, %p.\n", iface, flags, values);
1821 return E_NOTIMPL;
1824 static HRESULT WINAPI video_mixer_processor_SetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
1826 FIXME("%p, %#x, %p.\n", iface, flags, values);
1828 return E_NOTIMPL;
1831 static HRESULT WINAPI video_mixer_processor_GetFilteringRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
1833 FIXME("%p, %#x, %p.\n", iface, prop, range);
1835 return E_NOTIMPL;
1838 static HRESULT WINAPI video_mixer_processor_GetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
1840 FIXME("%p, %#x, %p.\n", iface, prop, value);
1842 return E_NOTIMPL;
1845 static HRESULT WINAPI video_mixer_processor_SetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
1847 FIXME("%p, %#x, %p.\n", iface, prop, value);
1849 return E_NOTIMPL;
1852 static HRESULT WINAPI video_mixer_processor_GetBackgroundColor(IMFVideoProcessor *iface, COLORREF *color)
1854 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1856 TRACE("%p, %p.\n", iface, color);
1858 if (!color)
1859 return E_POINTER;
1861 EnterCriticalSection(&mixer->cs);
1862 *color = mixer->bkgnd_color;
1863 LeaveCriticalSection(&mixer->cs);
1865 return S_OK;
1868 static HRESULT WINAPI video_mixer_processor_SetBackgroundColor(IMFVideoProcessor *iface, COLORREF color)
1870 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1872 TRACE("%p, %#x.\n", iface, color);
1874 EnterCriticalSection(&mixer->cs);
1875 mixer->bkgnd_color = color;
1876 LeaveCriticalSection(&mixer->cs);
1878 return S_OK;
1881 static const IMFVideoProcessorVtbl video_mixer_processor_vtbl =
1883 video_mixer_processor_QueryInterface,
1884 video_mixer_processor_AddRef,
1885 video_mixer_processor_Release,
1886 video_mixer_processor_GetAvailableVideoProcessorModes,
1887 video_mixer_processor_GetVideoProcessorCaps,
1888 video_mixer_processor_GetVideoProcessorMode,
1889 video_mixer_processor_SetVideoProcessorMode,
1890 video_mixer_processor_GetProcAmpRange,
1891 video_mixer_processor_GetProcAmpValues,
1892 video_mixer_processor_SetProcAmpValues,
1893 video_mixer_processor_GetFilteringRange,
1894 video_mixer_processor_GetFilteringValue,
1895 video_mixer_processor_SetFilteringValue,
1896 video_mixer_processor_GetBackgroundColor,
1897 video_mixer_processor_SetBackgroundColor,
1900 static HRESULT WINAPI video_mixer_attributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out)
1902 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1903 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
1906 static ULONG WINAPI video_mixer_attributes_AddRef(IMFAttributes *iface)
1908 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1909 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1912 static ULONG WINAPI video_mixer_attributes_Release(IMFAttributes *iface)
1914 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1915 return IMFTransform_Release(&mixer->IMFTransform_iface);
1918 static HRESULT WINAPI video_mixer_attributes_GetItem(IMFAttributes *iface, REFGUID key, PROPVARIANT *value)
1920 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1922 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1924 return IMFAttributes_GetItem(mixer->internal_attributes, key, value);
1927 static HRESULT WINAPI video_mixer_attributes_GetItemType(IMFAttributes *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
1929 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1931 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
1933 return IMFAttributes_GetItemType(mixer->internal_attributes, key, type);
1936 static HRESULT WINAPI video_mixer_attributes_CompareItem(IMFAttributes *iface, REFGUID key,
1937 REFPROPVARIANT value, BOOL *result)
1939 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1941 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
1943 return IMFAttributes_CompareItem(mixer->internal_attributes, key, value, result);
1946 static HRESULT WINAPI video_mixer_attributes_Compare(IMFAttributes *iface, IMFAttributes *theirs,
1947 MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
1949 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1951 TRACE("%p, %p, %d, %p.\n", iface, theirs, match_type, ret);
1953 return IMFAttributes_Compare(mixer->internal_attributes, theirs, match_type, ret);
1956 static HRESULT WINAPI video_mixer_attributes_GetUINT32(IMFAttributes *iface, REFGUID key, UINT32 *value)
1958 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1960 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1962 return IMFAttributes_GetUINT32(mixer->internal_attributes, key, value);
1965 static HRESULT WINAPI video_mixer_attributes_GetUINT64(IMFAttributes *iface, REFGUID key, UINT64 *value)
1967 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1969 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1971 return IMFAttributes_GetUINT64(mixer->internal_attributes, key, value);
1974 static HRESULT WINAPI video_mixer_attributes_GetDouble(IMFAttributes *iface, REFGUID key, double *value)
1976 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1978 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1980 return IMFAttributes_GetDouble(mixer->internal_attributes, key, value);
1983 static HRESULT WINAPI video_mixer_attributes_GetGUID(IMFAttributes *iface, REFGUID key, GUID *value)
1985 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1987 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1989 return IMFAttributes_GetGUID(mixer->internal_attributes, key, value);
1992 static HRESULT WINAPI video_mixer_attributes_GetStringLength(IMFAttributes *iface, REFGUID key, UINT32 *length)
1994 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
1996 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
1998 return IMFAttributes_GetStringLength(mixer->internal_attributes, key, length);
2001 static HRESULT WINAPI video_mixer_attributes_GetString(IMFAttributes *iface, REFGUID key, WCHAR *value,
2002 UINT32 size, UINT32 *length)
2004 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2006 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), value, size, length);
2008 return IMFAttributes_GetString(mixer->internal_attributes, key, value, size, length);
2011 static HRESULT WINAPI video_mixer_attributes_GetAllocatedString(IMFAttributes *iface, REFGUID key,
2012 WCHAR **value, UINT32 *length)
2014 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2016 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
2018 return IMFAttributes_GetAllocatedString(mixer->internal_attributes, key, value, length);
2021 static HRESULT WINAPI video_mixer_attributes_GetBlobSize(IMFAttributes *iface, REFGUID key, UINT32 *size)
2023 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2025 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
2027 return IMFAttributes_GetBlobSize(mixer->internal_attributes, key, size);
2030 static HRESULT WINAPI video_mixer_attributes_GetBlob(IMFAttributes *iface, REFGUID key, UINT8 *buf,
2031 UINT32 bufsize, UINT32 *blobsize)
2033 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2035 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
2037 return IMFAttributes_GetBlob(mixer->internal_attributes, key, buf, bufsize, blobsize);
2040 static HRESULT WINAPI video_mixer_attributes_GetAllocatedBlob(IMFAttributes *iface, REFGUID key, UINT8 **buf, UINT32 *size)
2042 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2044 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
2046 return IMFAttributes_GetAllocatedBlob(mixer->internal_attributes, key, buf, size);
2049 static HRESULT WINAPI video_mixer_attributes_GetUnknown(IMFAttributes *iface, REFGUID key, REFIID riid, void **out)
2051 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2053 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
2055 return IMFAttributes_GetUnknown(mixer->internal_attributes, key, riid, out);
2058 static HRESULT WINAPI video_mixer_attributes_SetItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value)
2060 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2062 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2064 return IMFAttributes_SetItem(mixer->internal_attributes, key, value);
2067 static HRESULT WINAPI video_mixer_attributes_DeleteItem(IMFAttributes *iface, REFGUID key)
2069 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2071 TRACE("%p, %s.\n", iface, debugstr_guid(key));
2073 return IMFAttributes_DeleteItem(mixer->internal_attributes, key);
2076 static HRESULT WINAPI video_mixer_attributes_DeleteAllItems(IMFAttributes *iface)
2078 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2080 TRACE("%p.\n", iface);
2082 return IMFAttributes_DeleteAllItems(mixer->internal_attributes);
2085 static HRESULT WINAPI video_mixer_attributes_SetUINT32(IMFAttributes *iface, REFGUID key, UINT32 value)
2087 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2089 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
2091 return IMFAttributes_SetUINT32(mixer->internal_attributes, key, value);
2094 static HRESULT WINAPI video_mixer_attributes_SetUINT64(IMFAttributes *iface, REFGUID key, UINT64 value)
2096 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2098 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
2100 return IMFAttributes_SetUINT64(mixer->internal_attributes, key, value);
2103 static HRESULT WINAPI video_mixer_attributes_SetDouble(IMFAttributes *iface, REFGUID key, double value)
2105 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2107 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
2109 return IMFAttributes_SetDouble(mixer->internal_attributes, key, value);
2112 static HRESULT WINAPI video_mixer_attributes_SetGUID(IMFAttributes *iface, REFGUID key, REFGUID value)
2114 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2116 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
2118 return IMFAttributes_SetGUID(mixer->internal_attributes, key, value);
2121 static HRESULT WINAPI video_mixer_attributes_SetString(IMFAttributes *iface, REFGUID key, const WCHAR *value)
2123 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2125 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
2127 return IMFAttributes_SetString(mixer->internal_attributes, key, value);
2130 static HRESULT WINAPI video_mixer_attributes_SetBlob(IMFAttributes *iface, REFGUID key, const UINT8 *buf, UINT32 size)
2132 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2134 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
2136 return IMFAttributes_SetBlob(mixer->internal_attributes, key, buf, size);
2139 static HRESULT WINAPI video_mixer_attributes_SetUnknown(IMFAttributes *iface, REFGUID key, IUnknown *unknown)
2141 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2143 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
2145 return IMFAttributes_SetUnknown(mixer->internal_attributes, key, unknown);
2148 static HRESULT WINAPI video_mixer_attributes_LockStore(IMFAttributes *iface)
2150 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2152 TRACE("%p.\n", iface);
2154 return IMFAttributes_LockStore(mixer->internal_attributes);
2157 static HRESULT WINAPI video_mixer_attributes_UnlockStore(IMFAttributes *iface)
2159 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2161 TRACE("%p.\n", iface);
2163 return IMFAttributes_UnlockStore(mixer->internal_attributes);
2166 static HRESULT WINAPI video_mixer_attributes_GetCount(IMFAttributes *iface, UINT32 *count)
2168 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2170 TRACE("%p, %p.\n", iface, count);
2172 return IMFAttributes_GetCount(mixer->internal_attributes, count);
2175 static HRESULT WINAPI video_mixer_attributes_GetItemByIndex(IMFAttributes *iface, UINT32 index,
2176 GUID *key, PROPVARIANT *value)
2178 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2180 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
2182 return IMFAttributes_GetItemByIndex(mixer->internal_attributes, index, key, value);
2185 static HRESULT WINAPI video_mixer_attributes_CopyAllItems(IMFAttributes *iface, IMFAttributes *dest)
2187 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2189 TRACE("%p, %p.\n", iface, dest);
2191 return IMFAttributes_CopyAllItems(mixer->internal_attributes, dest);
2194 static const IMFAttributesVtbl video_mixer_attributes_vtbl =
2196 video_mixer_attributes_QueryInterface,
2197 video_mixer_attributes_AddRef,
2198 video_mixer_attributes_Release,
2199 video_mixer_attributes_GetItem,
2200 video_mixer_attributes_GetItemType,
2201 video_mixer_attributes_CompareItem,
2202 video_mixer_attributes_Compare,
2203 video_mixer_attributes_GetUINT32,
2204 video_mixer_attributes_GetUINT64,
2205 video_mixer_attributes_GetDouble,
2206 video_mixer_attributes_GetGUID,
2207 video_mixer_attributes_GetStringLength,
2208 video_mixer_attributes_GetString,
2209 video_mixer_attributes_GetAllocatedString,
2210 video_mixer_attributes_GetBlobSize,
2211 video_mixer_attributes_GetBlob,
2212 video_mixer_attributes_GetAllocatedBlob,
2213 video_mixer_attributes_GetUnknown,
2214 video_mixer_attributes_SetItem,
2215 video_mixer_attributes_DeleteItem,
2216 video_mixer_attributes_DeleteAllItems,
2217 video_mixer_attributes_SetUINT32,
2218 video_mixer_attributes_SetUINT64,
2219 video_mixer_attributes_SetDouble,
2220 video_mixer_attributes_SetGUID,
2221 video_mixer_attributes_SetString,
2222 video_mixer_attributes_SetBlob,
2223 video_mixer_attributes_SetUnknown,
2224 video_mixer_attributes_LockStore,
2225 video_mixer_attributes_UnlockStore,
2226 video_mixer_attributes_GetCount,
2227 video_mixer_attributes_GetItemByIndex,
2228 video_mixer_attributes_CopyAllItems
2231 static HRESULT WINAPI video_mixer_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
2233 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2234 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2237 static ULONG WINAPI video_mixer_quality_advise_AddRef(IMFQualityAdvise *iface)
2239 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2240 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2243 static ULONG WINAPI video_mixer_quality_advise_Release(IMFQualityAdvise *iface)
2245 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2246 return IMFTransform_Release(&mixer->IMFTransform_iface);
2249 static HRESULT WINAPI video_mixer_quality_advise_SetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE mode)
2251 FIXME("%p, %u.\n", iface, mode);
2253 return E_NOTIMPL;
2256 static HRESULT WINAPI video_mixer_quality_advise_SetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL level)
2258 FIXME("%p, %u.\n", iface, level);
2260 return E_NOTIMPL;
2263 static HRESULT WINAPI video_mixer_quality_advise_GetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE *mode)
2265 FIXME("%p, %p.\n", iface, mode);
2267 return E_NOTIMPL;
2270 static HRESULT WINAPI video_mixer_quality_advise_GetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL *level)
2272 FIXME("%p, %p.\n", iface, level);
2274 return E_NOTIMPL;
2277 static HRESULT WINAPI video_mixer_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
2279 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
2281 return E_NOTIMPL;
2284 static const IMFQualityAdviseVtbl video_mixer_quality_advise_vtbl =
2286 video_mixer_quality_advise_QueryInterface,
2287 video_mixer_quality_advise_AddRef,
2288 video_mixer_quality_advise_Release,
2289 video_mixer_quality_advise_SetDropMode,
2290 video_mixer_quality_advise_SetQualityLevel,
2291 video_mixer_quality_advise_GetDropMode,
2292 video_mixer_quality_advise_GetQualityLevel,
2293 video_mixer_quality_advise_DropTime,
2296 static HRESULT WINAPI video_mixer_clock_state_sink_QueryInterface(IMFClockStateSink *iface,
2297 REFIID riid, void **out)
2299 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2300 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2303 static ULONG WINAPI video_mixer_clock_state_sink_AddRef(IMFClockStateSink *iface)
2305 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2306 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2309 static ULONG WINAPI video_mixer_clock_state_sink_Release(IMFClockStateSink *iface)
2311 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2312 return IMFTransform_Release(&mixer->IMFTransform_iface);
2315 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStart(IMFClockStateSink *iface,
2316 MFTIME systime, LONGLONG offset)
2318 FIXME("%p.\n", iface);
2320 return E_NOTIMPL;
2323 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStop(IMFClockStateSink *iface,
2324 MFTIME systime)
2326 FIXME("%p.\n", iface);
2328 return E_NOTIMPL;
2331 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockPause(IMFClockStateSink *iface,
2332 MFTIME systime)
2334 FIXME("%p.\n", iface);
2336 return E_NOTIMPL;
2339 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockRestart(IMFClockStateSink *iface,
2340 MFTIME systime)
2342 FIXME("%p.\n", iface);
2344 return E_NOTIMPL;
2347 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockSetRate(IMFClockStateSink *iface,
2348 MFTIME systime, float rate)
2350 FIXME("%p, %f.\n", iface, rate);
2352 return E_NOTIMPL;
2355 static const IMFClockStateSinkVtbl video_mixer_clock_state_sink_vtbl =
2357 video_mixer_clock_state_sink_QueryInterface,
2358 video_mixer_clock_state_sink_AddRef,
2359 video_mixer_clock_state_sink_Release,
2360 video_mixer_clock_state_sink_OnClockStart,
2361 video_mixer_clock_state_sink_OnClockStop,
2362 video_mixer_clock_state_sink_OnClockPause,
2363 video_mixer_clock_state_sink_OnClockRestart,
2364 video_mixer_clock_state_sink_OnClockSetRate,
2367 HRESULT WINAPI MFCreateVideoMixer(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
2369 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
2371 *obj = NULL;
2373 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
2374 return E_INVALIDARG;
2376 return CoCreateInstance(&CLSID_MFVideoMixer9, owner, CLSCTX_INPROC_SERVER, riid, obj);
2379 HRESULT evr_mixer_create(IUnknown *outer, void **out)
2381 struct video_mixer *object;
2382 MFVideoNormalizedRect rect;
2383 HRESULT hr;
2385 if (!(object = calloc(1, sizeof(*object))))
2386 return E_OUTOFMEMORY;
2388 object->IMFTransform_iface.lpVtbl = &video_mixer_transform_vtbl;
2389 object->IMFVideoDeviceID_iface.lpVtbl = &video_mixer_device_id_vtbl;
2390 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_mixer_service_client_vtbl;
2391 object->IMFVideoMixerControl2_iface.lpVtbl = &video_mixer_control_vtbl;
2392 object->IMFGetService_iface.lpVtbl = &video_mixer_getservice_vtbl;
2393 object->IMFVideoMixerBitmap_iface.lpVtbl = &video_mixer_bitmap_vtbl;
2394 object->IMFVideoPositionMapper_iface.lpVtbl = &video_mixer_position_mapper_vtbl;
2395 object->IMFVideoProcessor_iface.lpVtbl = &video_mixer_processor_vtbl;
2396 object->IMFAttributes_iface.lpVtbl = &video_mixer_attributes_vtbl;
2397 object->IMFQualityAdvise_iface.lpVtbl = &video_mixer_quality_advise_vtbl;
2398 object->IMFClockStateSink_iface.lpVtbl = &video_mixer_clock_state_sink_vtbl;
2399 object->IUnknown_inner.lpVtbl = &video_mixer_inner_vtbl;
2400 object->outer_unk = outer ? outer : &object->IUnknown_inner;
2401 object->refcount = 1;
2402 object->input_count = 1;
2403 object->lower_bound = MFT_OUTPUT_BOUND_LOWER_UNBOUNDED;
2404 object->upper_bound = MFT_OUTPUT_BOUND_UPPER_UNBOUNDED;
2405 video_mixer_init_input(&object->inputs[0]);
2406 InitializeCriticalSection(&object->cs);
2407 if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
2409 IUnknown_Release(&object->IUnknown_inner);
2410 return hr;
2412 if (FAILED(hr = MFCreateAttributes(&object->internal_attributes, 0)))
2414 IUnknown_Release(&object->IUnknown_inner);
2415 return hr;
2418 /* Default attributes configuration. */
2420 rect.left = rect.top = 0.0f;
2421 rect.right = rect.bottom = 1.0f;
2422 IMFAttributes_SetBlob(object->attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&rect, sizeof(rect));
2424 IMFAttributes_SetUINT32(object->internal_attributes, &MF_SA_D3D_AWARE, 1);
2426 *out = &object->IUnknown_inner;
2428 return S_OK;