winegstreamer: Disconnect source pins before calling wg_parser_disconnect().
[wine.git] / dlls / evr / mixer.c
blob0b957e7b6bd0a3ebb4c23dd70a8b0193f633fbb3
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"
28 #include "evr_private.h"
30 #include "initguid.h"
31 #include "evr9.h"
32 #include "evcode.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(evr);
38 #define MAX_MIXER_INPUT_SUBSTREAMS (15)
39 #define MAX_MIXER_INPUT_STREAMS (MAX_MIXER_INPUT_SUBSTREAMS + 1)
41 struct input_stream
43 unsigned int id;
44 IMFAttributes *attributes;
45 IMFMediaType *media_type;
46 MFVideoNormalizedRect rect;
47 unsigned int zorder;
48 SIZE frame_size;
49 IMFSample *sample;
50 unsigned int sample_requested : 1;
53 struct rt_format
55 GUID device;
56 D3DFORMAT format;
57 IMFMediaType *media_type;
60 struct output_stream
62 IMFMediaType *media_type;
63 struct rt_format *rt_formats;
64 unsigned int rt_formats_count;
67 struct video_mixer
69 IMFTransform IMFTransform_iface;
70 IMFVideoDeviceID IMFVideoDeviceID_iface;
71 IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
72 IMFVideoMixerControl2 IMFVideoMixerControl2_iface;
73 IMFGetService IMFGetService_iface;
74 IMFVideoMixerBitmap IMFVideoMixerBitmap_iface;
75 IMFVideoPositionMapper IMFVideoPositionMapper_iface;
76 IMFVideoProcessor IMFVideoProcessor_iface;
77 IMFAttributes IMFAttributes_iface;
78 IMFQualityAdvise IMFQualityAdvise_iface;
79 IMFClockStateSink IMFClockStateSink_iface;
80 IUnknown IUnknown_inner;
81 IUnknown *outer_unk;
82 LONG refcount;
84 struct input_stream inputs[MAX_MIXER_INPUT_STREAMS];
85 unsigned int input_ids[MAX_MIXER_INPUT_STREAMS];
86 struct input_stream *zorder[MAX_MIXER_INPUT_STREAMS];
87 unsigned int input_count;
88 struct output_stream output;
90 IDirect3DDeviceManager9 *device_manager;
91 IDirectXVideoProcessor *processor;
92 HANDLE device_handle;
94 IMediaEventSink *event_sink;
95 IMFAttributes *attributes;
96 IMFAttributes *internal_attributes;
97 unsigned int mixing_flags;
98 unsigned int is_streaming : 1;
99 unsigned int output_rendered : 1;
100 struct
102 COLORREF rgba;
103 DXVA2_AYUVSample16 ayuv;
104 } bkgnd_color;
105 MFVideoArea aperture;
106 LONGLONG lower_bound;
107 LONGLONG upper_bound;
108 CRITICAL_SECTION cs;
111 static struct video_mixer *impl_from_IUnknown(IUnknown *iface)
113 return CONTAINING_RECORD(iface, struct video_mixer, IUnknown_inner);
116 static struct video_mixer *impl_from_IMFTransform(IMFTransform *iface)
118 return CONTAINING_RECORD(iface, struct video_mixer, IMFTransform_iface);
121 static struct video_mixer *impl_from_IMFVideoDeviceID(IMFVideoDeviceID *iface)
123 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoDeviceID_iface);
126 static struct video_mixer *impl_from_IMFTopologyServiceLookupClient(IMFTopologyServiceLookupClient *iface)
128 return CONTAINING_RECORD(iface, struct video_mixer, IMFTopologyServiceLookupClient_iface);
131 static struct video_mixer *impl_from_IMFVideoMixerControl2(IMFVideoMixerControl2 *iface)
133 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoMixerControl2_iface);
136 static struct video_mixer *impl_from_IMFGetService(IMFGetService *iface)
138 return CONTAINING_RECORD(iface, struct video_mixer, IMFGetService_iface);
141 static struct video_mixer *impl_from_IMFVideoMixerBitmap(IMFVideoMixerBitmap *iface)
143 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoMixerBitmap_iface);
146 static struct video_mixer *impl_from_IMFVideoPositionMapper(IMFVideoPositionMapper *iface)
148 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoPositionMapper_iface);
151 static struct video_mixer *impl_from_IMFVideoProcessor(IMFVideoProcessor *iface)
153 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoProcessor_iface);
156 static struct video_mixer *impl_from_IMFAttributes(IMFAttributes *iface)
158 return CONTAINING_RECORD(iface, struct video_mixer, IMFAttributes_iface);
161 static struct video_mixer *impl_from_IMFQualityAdvise(IMFQualityAdvise *iface)
163 return CONTAINING_RECORD(iface, struct video_mixer, IMFQualityAdvise_iface);
166 static struct video_mixer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
168 return CONTAINING_RECORD(iface, struct video_mixer, IMFClockStateSink_iface);
171 static int __cdecl video_mixer_compare_input_id(const void *a, const void *b)
173 const unsigned int *key = a;
174 const struct input_stream *input = b;
176 if (*key > input->id) return 1;
177 if (*key < input->id) return -1;
178 return 0;
181 static HRESULT video_mixer_get_input(const struct video_mixer *mixer, unsigned int id, struct input_stream **stream)
183 *stream = bsearch(&id, mixer->inputs, mixer->input_count, sizeof(*mixer->inputs), video_mixer_compare_input_id);
184 return *stream ? S_OK : MF_E_INVALIDSTREAMNUMBER;
187 static void video_mixer_init_input(struct input_stream *stream)
189 if (SUCCEEDED(MFCreateAttributes(&stream->attributes, 1)))
190 IMFAttributes_SetUINT32(stream->attributes, &MF_SA_REQUIRED_SAMPLE_COUNT, 1);
191 stream->rect.left = stream->rect.top = 0.0f;
192 stream->rect.right = stream->rect.bottom = 1.0f;
195 static int __cdecl video_mixer_zorder_sort_compare(const void *a, const void *b)
197 const struct input_stream *left = *(void **)a, *right = *(void **)b;
198 return left->zorder != right->zorder ? (left->zorder < right->zorder ? -1 : 1) : 0;
201 static void video_mixer_update_zorder_map(struct video_mixer *mixer)
203 unsigned int i;
205 for (i = 0; i < mixer->input_count; ++i)
206 mixer->zorder[i] = &mixer->inputs[i];
208 qsort(mixer->zorder, mixer->input_count, sizeof(*mixer->zorder), video_mixer_zorder_sort_compare);
211 static void video_mixer_flush_input(struct video_mixer *mixer)
213 unsigned int i;
215 for (i = 0; i < mixer->input_count; ++i)
217 if (mixer->inputs[i].sample)
218 IMFSample_Release(mixer->inputs[i].sample);
219 mixer->inputs[i].sample = NULL;
220 mixer->inputs[i].sample_requested = 0;
222 mixer->output_rendered = 0;
225 static void video_mixer_clear_types(struct video_mixer *mixer)
227 unsigned int i;
229 for (i = 0; i < mixer->input_count; ++i)
231 if (mixer->inputs[i].media_type)
232 IMFMediaType_Release(mixer->inputs[i].media_type);
233 mixer->inputs[i].media_type = NULL;
235 video_mixer_flush_input(mixer);
236 for (i = 0; i < mixer->output.rt_formats_count; ++i)
238 IMFMediaType_Release(mixer->output.rt_formats[i].media_type);
240 free(mixer->output.rt_formats);
241 if (mixer->output.media_type)
242 IMFMediaType_Release(mixer->output.media_type);
243 mixer->output.media_type = NULL;
246 static HRESULT WINAPI video_mixer_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
248 struct video_mixer *mixer = impl_from_IUnknown(iface);
250 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
252 if (IsEqualIID(riid, &IID_IUnknown))
254 *obj = iface;
256 else if (IsEqualIID(riid, &IID_IMFTransform))
258 *obj = &mixer->IMFTransform_iface;
260 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
262 *obj = &mixer->IMFVideoDeviceID_iface;
264 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
266 *obj = &mixer->IMFTopologyServiceLookupClient_iface;
268 else if (IsEqualIID(riid, &IID_IMFVideoMixerControl2) ||
269 IsEqualIID(riid, &IID_IMFVideoMixerControl))
271 *obj = &mixer->IMFVideoMixerControl2_iface;
273 else if (IsEqualIID(riid, &IID_IMFGetService))
275 *obj = &mixer->IMFGetService_iface;
277 else if (IsEqualIID(riid, &IID_IMFVideoMixerBitmap))
279 *obj = &mixer->IMFVideoMixerBitmap_iface;
281 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
283 *obj = &mixer->IMFVideoPositionMapper_iface;
285 else if (IsEqualIID(riid, &IID_IMFVideoProcessor))
287 *obj = &mixer->IMFVideoProcessor_iface;
289 else if (IsEqualIID(riid, &IID_IMFAttributes))
291 *obj = &mixer->IMFAttributes_iface;
293 else if (IsEqualIID(riid, &IID_IMFQualityAdvise))
295 *obj = &mixer->IMFQualityAdvise_iface;
297 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
299 *obj = &mixer->IMFClockStateSink_iface;
301 else
303 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
304 *obj = NULL;
305 return E_NOINTERFACE;
308 IUnknown_AddRef((IUnknown *)*obj);
309 return S_OK;
312 static ULONG WINAPI video_mixer_inner_AddRef(IUnknown *iface)
314 struct video_mixer *mixer = impl_from_IUnknown(iface);
315 ULONG refcount = InterlockedIncrement(&mixer->refcount);
317 TRACE("%p, refcount %lu.\n", iface, refcount);
319 return refcount;
322 static void video_mixer_release_device_manager(struct video_mixer *mixer)
324 if (mixer->processor)
325 IDirectXVideoProcessor_Release(mixer->processor);
326 if (mixer->device_manager)
328 IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, mixer->device_handle);
329 IDirect3DDeviceManager9_Release(mixer->device_manager);
331 mixer->device_handle = NULL;
332 mixer->device_manager = NULL;
333 mixer->processor = NULL;
336 static ULONG WINAPI video_mixer_inner_Release(IUnknown *iface)
338 struct video_mixer *mixer = impl_from_IUnknown(iface);
339 ULONG refcount = InterlockedDecrement(&mixer->refcount);
340 unsigned int i;
342 TRACE("%p, refcount %lu.\n", iface, refcount);
344 if (!refcount)
346 for (i = 0; i < mixer->input_count; ++i)
348 if (mixer->inputs[i].attributes)
349 IMFAttributes_Release(mixer->inputs[i].attributes);
351 video_mixer_clear_types(mixer);
352 video_mixer_release_device_manager(mixer);
353 if (mixer->attributes)
354 IMFAttributes_Release(mixer->attributes);
355 if (mixer->internal_attributes)
356 IMFAttributes_Release(mixer->internal_attributes);
357 DeleteCriticalSection(&mixer->cs);
358 free(mixer);
361 return refcount;
364 static const IUnknownVtbl video_mixer_inner_vtbl =
366 video_mixer_inner_QueryInterface,
367 video_mixer_inner_AddRef,
368 video_mixer_inner_Release,
371 static HRESULT WINAPI video_mixer_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
373 struct video_mixer *mixer = impl_from_IMFTransform(iface);
374 return IUnknown_QueryInterface(mixer->outer_unk, riid, obj);
377 static ULONG WINAPI video_mixer_transform_AddRef(IMFTransform *iface)
379 struct video_mixer *mixer = impl_from_IMFTransform(iface);
380 return IUnknown_AddRef(mixer->outer_unk);
383 static ULONG WINAPI video_mixer_transform_Release(IMFTransform *iface)
385 struct video_mixer *mixer = impl_from_IMFTransform(iface);
386 return IUnknown_Release(mixer->outer_unk);
389 static HRESULT WINAPI video_mixer_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
390 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
392 TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
394 *input_minimum = 1;
395 *input_maximum = MAX_MIXER_INPUT_STREAMS;
396 *output_minimum = 1;
397 *output_maximum = 1;
399 return S_OK;
402 static HRESULT WINAPI video_mixer_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
404 struct video_mixer *mixer = impl_from_IMFTransform(iface);
406 TRACE("%p, %p, %p.\n", iface, inputs, outputs);
408 EnterCriticalSection(&mixer->cs);
409 if (inputs) *inputs = mixer->input_count;
410 if (outputs) *outputs = 1;
411 LeaveCriticalSection(&mixer->cs);
413 return S_OK;
416 static HRESULT WINAPI video_mixer_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
417 DWORD output_size, DWORD *outputs)
419 struct video_mixer *mixer = impl_from_IMFTransform(iface);
420 HRESULT hr = S_OK;
422 TRACE("%p, %lu, %p, %lu, %p.\n", iface, input_size, inputs, output_size, outputs);
424 EnterCriticalSection(&mixer->cs);
425 if (mixer->input_count > input_size || !output_size)
426 hr = MF_E_BUFFERTOOSMALL;
427 else if (inputs)
428 memcpy(inputs, mixer->input_ids, mixer->input_count * sizeof(*inputs));
429 if (outputs) *outputs = 0;
430 LeaveCriticalSection(&mixer->cs);
432 return hr;
435 static HRESULT WINAPI video_mixer_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
437 struct video_mixer *mixer = impl_from_IMFTransform(iface);
438 struct input_stream *input;
439 HRESULT hr;
441 TRACE("%p, %lu, %p.\n", iface, id, info);
443 EnterCriticalSection(&mixer->cs);
445 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
447 memset(info, 0, sizeof(*info));
448 if (id)
449 info->dwFlags |= MFT_INPUT_STREAM_REMOVABLE | MFT_INPUT_STREAM_OPTIONAL;
452 LeaveCriticalSection(&mixer->cs);
454 return hr;
457 static HRESULT WINAPI video_mixer_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
459 TRACE("%p, %lu, %p.\n", iface, id, info);
461 if (id)
462 return MF_E_INVALIDSTREAMNUMBER;
464 memset(info, 0, sizeof(*info));
466 return S_OK;
469 static HRESULT WINAPI video_mixer_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
471 struct video_mixer *mixer = impl_from_IMFTransform(iface);
473 TRACE("%p, %p.\n", iface, attributes);
475 if (!attributes)
476 return E_POINTER;
478 *attributes = mixer->attributes;
479 IMFAttributes_AddRef(*attributes);
481 return S_OK;
484 static HRESULT WINAPI video_mixer_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
485 IMFAttributes **attributes)
487 struct video_mixer *mixer = impl_from_IMFTransform(iface);
488 struct input_stream *input;
489 HRESULT hr;
491 TRACE("%p, %lu, %p.\n", iface, id, attributes);
493 EnterCriticalSection(&mixer->cs);
495 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
497 *attributes = input->attributes;
498 if (*attributes)
499 IMFAttributes_AddRef(*attributes);
502 LeaveCriticalSection(&mixer->cs);
504 return hr;
507 static HRESULT WINAPI video_mixer_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
508 IMFAttributes **attributes)
510 TRACE("%p, %lu, %p.\n", iface, id, attributes);
512 return E_NOTIMPL;
515 static HRESULT WINAPI video_mixer_transform_DeleteInputStream(IMFTransform *iface, DWORD id)
517 struct video_mixer *mixer = impl_from_IMFTransform(iface);
518 struct input_stream *input;
519 unsigned int idx;
520 HRESULT hr;
522 TRACE("%p, %lu.\n", iface, id);
524 if (!id)
525 return MF_E_INVALIDSTREAMNUMBER;
527 EnterCriticalSection(&mixer->cs);
529 /* Can't delete reference stream. */
530 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
532 mixer->input_count--;
533 idx = input - mixer->inputs;
534 if (idx < mixer->input_count)
536 if (mixer->inputs[idx].attributes)
537 IMFAttributes_Release(mixer->inputs[idx].attributes);
538 memmove(&mixer->inputs[idx], &mixer->inputs[idx + 1], (mixer->input_count - idx) * sizeof(*mixer->inputs));
539 memmove(&mixer->input_ids[idx], &mixer->input_ids[idx + 1], (mixer->input_count - idx) *
540 sizeof(*mixer->input_ids));
541 video_mixer_update_zorder_map(mixer);
545 LeaveCriticalSection(&mixer->cs);
547 return hr;
550 static int __cdecl video_mixer_add_input_sort_compare(const void *a, const void *b)
552 const struct input_stream *left = a, *right = b;
553 return left->id != right->id ? (left->id < right->id ? -1 : 1) : 0;
556 static HRESULT WINAPI video_mixer_transform_AddInputStreams(IMFTransform *iface, DWORD count, DWORD *ids)
558 struct video_mixer *mixer = impl_from_IMFTransform(iface);
559 struct input_stream inputs[MAX_MIXER_INPUT_STREAMS] = { {0} };
560 struct input_stream *input;
561 unsigned int i, len;
562 HRESULT hr = S_OK;
564 TRACE("%p, %lu, %p.\n", iface, count, ids);
566 if (!ids)
567 return E_POINTER;
569 EnterCriticalSection(&mixer->cs);
570 if (count > ARRAY_SIZE(mixer->inputs) - mixer->input_count)
571 hr = E_INVALIDARG;
572 else
574 /* Test for collisions. */
575 memcpy(inputs, mixer->inputs, mixer->input_count * sizeof(*inputs));
576 for (i = 0; i < count; ++i)
577 inputs[i + mixer->input_count].id = ids[i];
579 len = mixer->input_count + count;
581 qsort(inputs, len, sizeof(*inputs), video_mixer_add_input_sort_compare);
583 for (i = 1; i < len; ++i)
585 if (inputs[i - 1].id == inputs[i].id)
587 hr = E_INVALIDARG;
588 break;
592 if (SUCCEEDED(hr))
594 unsigned int zorder = mixer->input_count;
596 for (i = 0; i < count; ++i)
598 if ((input = bsearch(&ids[i], inputs, len, sizeof(*inputs), video_mixer_compare_input_id)))
599 video_mixer_init_input(input);
601 memcpy(&mixer->input_ids[mixer->input_count], ids, count * sizeof(*ids));
602 memcpy(mixer->inputs, inputs, len * sizeof(*inputs));
603 mixer->input_count += count;
605 for (i = 0; i < count; ++i)
607 if (SUCCEEDED(video_mixer_get_input(mixer, ids[i], &input)))
608 input->zorder = zorder;
609 zorder++;
612 video_mixer_update_zorder_map(mixer);
615 LeaveCriticalSection(&mixer->cs);
617 return hr;
620 static HRESULT WINAPI video_mixer_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
621 IMFMediaType **type)
623 TRACE("%p, %lu, %lu, %p.\n", iface, id, index, type);
625 return E_NOTIMPL;
628 static HRESULT WINAPI video_mixer_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
629 IMFMediaType **type)
631 struct video_mixer *mixer = impl_from_IMFTransform(iface);
632 HRESULT hr = S_OK;
634 TRACE("%p, %lu, %lu, %p.\n", iface, id, index, type);
636 if (id)
637 return MF_E_INVALIDSTREAMNUMBER;
639 EnterCriticalSection(&mixer->cs);
641 if (!mixer->inputs[0].media_type)
642 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
643 else if (index >= mixer->output.rt_formats_count)
644 hr = MF_E_NO_MORE_TYPES;
645 else
647 if (SUCCEEDED(hr = MFCreateMediaType(type)))
648 hr = IMFMediaType_CopyAllItems(mixer->output.rt_formats[index].media_type, (IMFAttributes *)*type);
651 LeaveCriticalSection(&mixer->cs);
653 return hr;
656 static HRESULT video_mixer_init_dxva_videodesc(IMFMediaType *media_type, DXVA2_VideoDesc *video_desc)
658 const MFVIDEOFORMAT *video_format;
659 IMFVideoMediaType *video_type;
660 BOOL is_compressed = TRUE;
661 HRESULT hr = S_OK;
663 if (FAILED(IMFMediaType_QueryInterface(media_type, &IID_IMFVideoMediaType, (void **)&video_type)))
664 return MF_E_INVALIDMEDIATYPE;
666 video_format = IMFVideoMediaType_GetVideoFormat(video_type);
667 IMFVideoMediaType_IsCompressedFormat(video_type, &is_compressed);
669 if (!video_format || !video_format->videoInfo.dwWidth || !video_format->videoInfo.dwHeight || is_compressed)
671 hr = MF_E_INVALIDMEDIATYPE;
672 goto done;
675 memset(video_desc, 0, sizeof(*video_desc));
676 video_desc->SampleWidth = video_format->videoInfo.dwWidth;
677 video_desc->SampleHeight = video_format->videoInfo.dwHeight;
678 video_desc->Format = video_format->surfaceInfo.Format;
680 done:
681 IMFVideoMediaType_Release(video_type);
683 return hr;
686 static void video_mixer_append_rt_format(struct rt_format *rt_formats, unsigned int *count,
687 const GUID *device, D3DFORMAT format)
689 unsigned int i;
691 for (i = 0; i < *count; ++i)
693 if (rt_formats[i].format == format) return;
696 rt_formats[*count].format = format;
697 rt_formats[*count].device = *device;
698 *count += 1;
701 static unsigned int video_mixer_get_interlace_mode_from_video_desc(const DXVA2_VideoDesc *video_desc)
703 switch (video_desc->SampleFormat.SampleFormat)
705 case DXVA2_SampleFieldInterleavedEvenFirst:
706 return MFVideoInterlace_FieldInterleavedUpperFirst;
707 case DXVA2_SampleFieldInterleavedOddFirst:
708 return MFVideoInterlace_FieldInterleavedLowerFirst;
709 case DXVA2_SampleFieldSingleEven:
710 return MFVideoInterlace_FieldSingleUpper;
711 case DXVA2_SampleFieldSingleOdd:
712 return MFVideoInterlace_FieldSingleLower;
713 default:
714 return MFVideoInterlace_Progressive;
718 static void mf_get_attribute_uint32(IMFMediaType *media_type, const GUID *key, UINT32 *value,
719 UINT32 default_value)
721 if (FAILED(IMFMediaType_GetUINT32(media_type, key, value)))
722 *value = default_value;
725 static void mf_get_attribute_uint64(IMFMediaType *media_type, const GUID *key, UINT64 *value,
726 UINT64 default_value)
728 if (FAILED(IMFMediaType_GetUINT64(media_type, key, value)))
729 *value = default_value;
732 static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const DXVA2_VideoDesc *video_desc,
733 IMFMediaType *media_type, IDirectXVideoProcessorService *service, unsigned int device_count,
734 const GUID *devices, unsigned int flags)
736 struct rt_format *rt_formats = NULL, *ptr;
737 unsigned int i, j, format_count, count;
738 HRESULT hr = MF_E_INVALIDMEDIATYPE;
739 D3DFORMAT *formats;
740 GUID subtype;
742 count = 0;
743 for (i = 0; i < device_count; ++i)
745 if (SUCCEEDED(IDirectXVideoProcessorService_GetVideoProcessorRenderTargets(service, &devices[i], video_desc,
746 &format_count, &formats)))
748 if (!(ptr = realloc(rt_formats, (count + format_count) * sizeof(*rt_formats))))
750 hr = E_OUTOFMEMORY;
751 count = 0;
752 CoTaskMemFree(formats);
753 break;
755 rt_formats = ptr;
757 for (j = 0; j < format_count; ++j)
758 video_mixer_append_rt_format(rt_formats, &count, &devices[i], formats[j]);
760 CoTaskMemFree(formats);
764 if (count && !(flags & MFT_SET_TYPE_TEST_ONLY))
766 UINT32 fixed_samples, interlace_mode;
767 MFVideoArea aperture;
768 UINT64 par;
770 if (!(mixer->output.rt_formats = calloc(count, sizeof(*mixer->output.rt_formats))))
772 free(rt_formats);
773 return E_OUTOFMEMORY;
776 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
777 memset(&aperture, 0, sizeof(aperture));
778 if (FAILED(IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture,
779 sizeof(aperture), NULL)))
781 aperture.Area.cx = video_desc->SampleWidth;
782 aperture.Area.cy = video_desc->SampleHeight;
784 interlace_mode = video_mixer_get_interlace_mode_from_video_desc(video_desc);
785 mf_get_attribute_uint64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &par, (UINT64)1 << 32 | 1);
786 mf_get_attribute_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &fixed_samples, 1);
788 for (i = 0; i < count; ++i)
790 IMFMediaType *rt_media_type;
792 subtype.Data1 = rt_formats[i].format;
793 mixer->output.rt_formats[i] = rt_formats[i];
795 MFCreateMediaType(&rt_media_type);
796 IMFMediaType_CopyAllItems(media_type, (IMFAttributes *)rt_media_type);
797 IMFMediaType_SetGUID(rt_media_type, &MF_MT_SUBTYPE, &subtype);
798 IMFMediaType_SetUINT64(rt_media_type, &MF_MT_FRAME_SIZE, (UINT64)aperture.Area.cx << 32 | aperture.Area.cy);
799 IMFMediaType_SetBlob(rt_media_type, &MF_MT_GEOMETRIC_APERTURE, (const UINT8 *)&aperture, sizeof(aperture));
800 IMFMediaType_SetBlob(rt_media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (const UINT8 *)&aperture, sizeof(aperture));
801 IMFMediaType_SetUINT32(rt_media_type, &MF_MT_INTERLACE_MODE, interlace_mode);
802 IMFMediaType_SetUINT64(rt_media_type, &MF_MT_PIXEL_ASPECT_RATIO, par);
803 IMFMediaType_SetUINT32(rt_media_type, &MF_MT_FIXED_SIZE_SAMPLES, fixed_samples);
805 mixer->output.rt_formats[i].media_type = rt_media_type;
807 mixer->output.rt_formats_count = count;
810 free(rt_formats);
812 return count ? S_OK : hr;
815 static HRESULT video_mixer_open_device_handle(struct video_mixer *mixer)
817 IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, mixer->device_handle);
818 mixer->device_handle = NULL;
819 return IDirect3DDeviceManager9_OpenDeviceHandle(mixer->device_manager, &mixer->device_handle);
822 static HRESULT video_mixer_get_processor_service(struct video_mixer *mixer, IDirectXVideoProcessorService **service)
824 HRESULT hr;
826 if (!mixer->device_handle)
828 if (FAILED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(mixer->device_manager, &mixer->device_handle)))
829 return hr;
832 for (;;)
834 hr = IDirect3DDeviceManager9_GetVideoService(mixer->device_manager, mixer->device_handle,
835 &IID_IDirectXVideoProcessorService, (void **)service);
836 if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
838 if (SUCCEEDED(hr = video_mixer_open_device_handle(mixer)))
839 continue;
841 break;
844 return hr;
847 static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *media_type, DWORD flags)
849 struct video_mixer *mixer = impl_from_IMFTransform(iface);
850 IDirectXVideoProcessorService *service;
851 DXVA2_VideoDesc video_desc;
852 HRESULT hr = E_NOTIMPL;
853 unsigned int count;
854 GUID *guids;
856 TRACE("%p, %lu, %p, %#lx.\n", iface, id, media_type, flags);
858 EnterCriticalSection(&mixer->cs);
860 if (!(flags & MFT_SET_TYPE_TEST_ONLY))
861 video_mixer_clear_types(mixer);
863 if (!mixer->device_manager)
864 hr = MF_E_NOT_INITIALIZED;
865 else
867 if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
869 if (SUCCEEDED(hr = video_mixer_init_dxva_videodesc(media_type, &video_desc)))
871 if (!id)
873 if (SUCCEEDED(hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc,
874 &count, &guids)))
876 if (SUCCEEDED(hr = video_mixer_collect_output_types(mixer, &video_desc, media_type,
877 service, count, guids, flags)) && !(flags & MFT_SET_TYPE_TEST_ONLY))
879 if (mixer->inputs[0].media_type)
880 IMFMediaType_Release(mixer->inputs[0].media_type);
881 mixer->inputs[0].media_type = media_type;
882 mixer->inputs[0].frame_size.cx = video_desc.SampleWidth;
883 mixer->inputs[0].frame_size.cy = video_desc.SampleHeight;
884 IMFMediaType_AddRef(mixer->inputs[0].media_type);
886 CoTaskMemFree(guids);
889 else
891 FIXME("Unimplemented for substreams.\n");
892 hr = E_NOTIMPL;
895 IDirectXVideoProcessorService_Release(service);
899 LeaveCriticalSection(&mixer->cs);
901 return hr;
904 static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
906 const unsigned int equality_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
907 struct video_mixer *mixer = impl_from_IMFTransform(iface);
908 HRESULT hr = MF_E_INVALIDMEDIATYPE;
909 BOOL is_compressed = TRUE;
910 DWORD compare_flags;
911 unsigned int i;
913 TRACE("%p, %lu, %p, %#lx.\n", iface, id, type, flags);
915 if (id)
916 return MF_E_INVALIDSTREAMNUMBER;
918 if (!type)
919 return E_INVALIDARG;
921 if (FAILED(IMFMediaType_IsCompressedFormat(type, &is_compressed)) || is_compressed)
922 return MF_E_INVALIDMEDIATYPE;
924 EnterCriticalSection(&mixer->cs);
926 for (i = 0; i < mixer->output.rt_formats_count; ++i)
928 compare_flags = 0;
929 if (FAILED(IMFMediaType_IsEqual(type, mixer->output.rt_formats[i].media_type, &compare_flags)))
930 continue;
932 if ((compare_flags & equality_flags) == equality_flags)
934 hr = S_OK;
935 break;
939 if (SUCCEEDED(hr) && !(flags & MFT_SET_TYPE_TEST_ONLY))
941 IDirectXVideoProcessorService *service;
943 if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
945 DXVA2_VideoDesc video_desc;
946 GUID subtype = { 0 };
947 D3DFORMAT rt_format;
949 if (mixer->processor)
950 IDirectXVideoProcessor_Release(mixer->processor);
951 mixer->processor = NULL;
953 video_mixer_init_dxva_videodesc(mixer->inputs[0].media_type, &video_desc);
954 IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype);
955 rt_format = subtype.Data1;
957 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &mixer->output.rt_formats[i].device,
958 &video_desc, rt_format, MAX_MIXER_INPUT_SUBSTREAMS, &mixer->processor)))
960 if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&mixer->aperture,
961 sizeof(mixer->aperture), NULL)))
963 memset(&mixer->aperture, 0, sizeof(mixer->aperture));
965 if (mixer->output.media_type)
966 IMFMediaType_Release(mixer->output.media_type);
967 mixer->output.media_type = type;
968 IMFMediaType_AddRef(mixer->output.media_type);
971 IDirectXVideoProcessorService_Release(service);
975 LeaveCriticalSection(&mixer->cs);
977 return hr;
980 static HRESULT WINAPI video_mixer_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
982 struct video_mixer *mixer = impl_from_IMFTransform(iface);
983 struct input_stream *stream;
984 HRESULT hr;
986 TRACE("%p, %lu, %p.\n", iface, id, type);
988 EnterCriticalSection(&mixer->cs);
990 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
992 if (!stream->media_type)
993 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
994 else
996 *type = stream->media_type;
997 IMFMediaType_AddRef(*type);
1001 LeaveCriticalSection(&mixer->cs);
1003 return hr;
1006 static HRESULT WINAPI video_mixer_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
1008 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1009 HRESULT hr = S_OK;
1011 TRACE("%p, %lu, %p.\n", iface, id, type);
1013 if (id)
1014 return MF_E_INVALIDSTREAMNUMBER;
1016 EnterCriticalSection(&mixer->cs);
1018 if (!mixer->output.media_type)
1019 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1020 else
1022 *type = mixer->output.media_type;
1023 IMFMediaType_AddRef(*type);
1026 LeaveCriticalSection(&mixer->cs);
1028 return hr;
1031 static HRESULT WINAPI video_mixer_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *status)
1033 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1034 struct input_stream *stream;
1035 HRESULT hr;
1037 TRACE("%p, %lu, %p.\n", iface, id, status);
1039 if (!status)
1040 return E_POINTER;
1042 EnterCriticalSection(&mixer->cs);
1044 if (!mixer->output.media_type)
1045 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1046 else if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1048 *status = stream->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA;
1051 LeaveCriticalSection(&mixer->cs);
1053 return hr;
1056 static HRESULT WINAPI video_mixer_transform_GetOutputStatus(IMFTransform *iface, DWORD *status)
1058 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1059 HRESULT hr = S_OK;
1060 unsigned int i;
1062 TRACE("%p, %p.\n", iface, status);
1064 if (!status)
1065 return E_POINTER;
1067 EnterCriticalSection(&mixer->cs);
1069 if (!mixer->output.media_type)
1070 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1071 else
1073 *status = MFT_OUTPUT_STATUS_SAMPLE_READY;
1074 for (i = 0; i < mixer->input_count; ++i)
1076 if (!mixer->inputs[i].sample)
1078 *status = 0;
1079 break;
1084 LeaveCriticalSection(&mixer->cs);
1086 return hr;
1089 static HRESULT WINAPI video_mixer_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
1091 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1093 TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
1095 EnterCriticalSection(&mixer->cs);
1097 mixer->lower_bound = lower;
1098 mixer->upper_bound = upper;
1100 LeaveCriticalSection(&mixer->cs);
1102 return S_OK;
1105 static HRESULT WINAPI video_mixer_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
1107 FIXME("%p, %lu, %p.\n", iface, id, event);
1109 return E_NOTIMPL;
1112 static void video_mixer_request_sample(struct video_mixer *mixer, unsigned int idx)
1114 if (!mixer->event_sink || mixer->inputs[idx].sample_requested)
1115 return;
1117 IMediaEventSink_Notify(mixer->event_sink, EC_SAMPLE_NEEDED, idx, 0);
1118 mixer->inputs[idx].sample_requested = 1;
1121 static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
1123 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1124 HRESULT hr = S_OK;
1125 unsigned int i;
1127 TRACE("%p, %#x, %Iu.\n", iface, message, param);
1129 EnterCriticalSection(&mixer->cs);
1131 switch (message)
1133 case MFT_MESSAGE_SET_D3D_MANAGER:
1134 video_mixer_release_device_manager(mixer);
1135 if (param)
1136 hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&mixer->device_manager);
1138 break;
1140 case MFT_MESSAGE_COMMAND_FLUSH:
1141 video_mixer_flush_input(mixer);
1143 break;
1145 case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
1146 case MFT_MESSAGE_NOTIFY_END_STREAMING:
1147 if (mixer->is_streaming)
1148 video_mixer_flush_input(mixer);
1149 else
1151 for (i = 0; i < mixer->input_count; ++i)
1152 video_mixer_request_sample(mixer, i);
1155 mixer->is_streaming = message == MFT_MESSAGE_NOTIFY_BEGIN_STREAMING;
1157 break;
1159 case MFT_MESSAGE_COMMAND_DRAIN:
1160 break;
1162 default:
1163 WARN("Message not handled %d.\n", message);
1164 hr = E_NOTIMPL;
1167 LeaveCriticalSection(&mixer->cs);
1169 return hr;
1172 static HRESULT WINAPI video_mixer_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
1174 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1175 struct input_stream *input;
1176 HRESULT hr;
1178 TRACE("%p, %lu, %p, %#lx.\n", iface, id, sample, flags);
1180 if (!sample)
1181 return E_POINTER;
1183 EnterCriticalSection(&mixer->cs);
1185 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
1187 if (!input->media_type || !mixer->output.media_type)
1188 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1189 else if (input->sample && !mixer->output_rendered)
1190 hr = MF_E_NOTACCEPTING;
1191 else
1193 if (input->sample && mixer->output_rendered)
1194 video_mixer_flush_input(mixer);
1195 mixer->is_streaming = 1;
1196 input->sample_requested = 0;
1197 input->sample = sample;
1198 IMFSample_AddRef(input->sample);
1202 LeaveCriticalSection(&mixer->cs);
1204 return hr;
1207 static HRESULT video_mixer_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface)
1209 IMFMediaBuffer *buffer;
1210 IMFGetService *gs;
1211 HRESULT hr;
1213 if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer)))
1214 return hr;
1216 hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&gs);
1217 IMFMediaBuffer_Release(buffer);
1218 if (FAILED(hr))
1219 return hr;
1221 hr = IMFGetService_GetService(gs, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)surface);
1222 IMFGetService_Release(gs);
1223 return hr;
1226 static HRESULT video_mixer_get_d3d_device(struct video_mixer *mixer, IDirect3DDevice9 **device)
1228 HRESULT hr;
1230 for (;;)
1232 hr = IDirect3DDeviceManager9_LockDevice(mixer->device_manager, mixer->device_handle,
1233 device, TRUE);
1234 if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
1236 if (SUCCEEDED(hr = video_mixer_open_device_handle(mixer)))
1237 continue;
1239 break;
1242 return hr;
1245 static BOOL video_mixer_rect_needs_scaling(const MFVideoNormalizedRect *scale)
1247 return scale->left != 0.0f || scale->top != 0.0f || scale->right != 1.0f || scale->bottom != 1.0f;
1250 static void video_mixer_scale_rect(RECT *rect, unsigned int width, unsigned int height,
1251 const MFVideoNormalizedRect *scale)
1253 if (video_mixer_rect_needs_scaling(scale))
1255 rect->left = width * scale->left;
1256 rect->right = width * scale->right;
1257 rect->top = height * scale->top;
1258 rect->bottom = height * scale->bottom;
1260 else
1261 SetRect(rect, 0, 0, width, height);
1264 static void video_mixer_correct_aspect_ratio(const RECT *src, RECT *dst)
1266 unsigned int src_width = src->right - src->left, src_height = src->bottom - src->top;
1267 unsigned int dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
1269 if (src_width * dst_height > dst_width * src_height)
1271 /* src is "wider" than dst. */
1272 unsigned int dst_center = (dst->top + dst->bottom) / 2;
1273 unsigned int scaled_height = src_height * dst_width / src_width;
1275 dst->top = dst_center - scaled_height / 2;
1276 dst->bottom = dst->top + scaled_height;
1278 else if (src_width * dst_height < dst_width * src_height)
1280 /* src is "taller" than dst. */
1281 unsigned int dst_center = (dst->left + dst->right) / 2;
1282 unsigned int scaled_width = src_width * dst_height / src_height;
1284 dst->left = dst_center - scaled_width / 2;
1285 dst->right = dst->left + scaled_width;
1289 static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt)
1291 DXVA2_VideoSample samples[MAX_MIXER_INPUT_STREAMS] = {{ 0 }};
1292 DXVA2_VideoProcessBltParams params = { 0 };
1293 MFVideoNormalizedRect zoom_rect;
1294 struct input_stream *stream;
1295 HRESULT hr = S_OK;
1296 unsigned int i;
1297 RECT dst;
1299 if (FAILED(IMFAttributes_GetBlob(mixer->attributes, &VIDEO_ZOOM_RECT, (UINT8 *)&zoom_rect,
1300 sizeof(zoom_rect), NULL)))
1302 zoom_rect.left = zoom_rect.top = 0.0f;
1303 zoom_rect.right = zoom_rect.bottom = 1.0f;
1306 SetRect(&dst, 0, 0, mixer->aperture.Area.cx, mixer->aperture.Area.cy);
1307 OffsetRect(&dst, mixer->aperture.OffsetX.value, mixer->aperture.OffsetY.value);
1309 for (i = 0; i < mixer->input_count; ++i)
1311 DXVA2_VideoSample *sample = &samples[i];
1312 IDirect3DSurface9 *surface;
1314 stream = mixer->zorder[i];
1316 if (FAILED(hr = video_mixer_get_sample_surface(stream->sample, &surface)))
1318 WARN("Failed to get source surface for stream %u, hr %#lx.\n", i, hr);
1319 break;
1322 /* Full input frame corrected to full destination rectangle. */
1324 video_mixer_scale_rect(&sample->SrcRect, stream->frame_size.cx, stream->frame_size.cy, &zoom_rect);
1325 CopyRect(&sample->DstRect, &dst);
1326 video_mixer_correct_aspect_ratio(&sample->SrcRect, &sample->DstRect);
1328 if (video_mixer_rect_needs_scaling(&stream->rect))
1329 WARN("Ignoring stream %u rectangle %s.\n", stream->id, debugstr_normalized_rect(&stream->rect));
1331 sample->SampleFormat.SampleFormat = stream->id == 0 ? DXVA2_SampleProgressiveFrame : DXVA2_SampleSubStream;
1332 sample->SrcSurface = surface;
1333 sample->PlanarAlpha = DXVA2_Fixed32OpaqueAlpha();
1336 if (SUCCEEDED(hr))
1338 SetRect(&params.TargetRect, 0, 0, mixer->aperture.Area.cx, mixer->aperture.Area.cy);
1339 OffsetRect(&params.TargetRect, mixer->aperture.OffsetX.value, mixer->aperture.OffsetY.value);
1341 params.BackgroundColor = mixer->bkgnd_color.ayuv;
1342 params.Alpha = DXVA2_Fixed32OpaqueAlpha();
1344 if (FAILED(hr = IDirectXVideoProcessor_VideoProcessBlt(mixer->processor, rt, &params, samples,
1345 mixer->input_count, NULL)))
1347 WARN("Failed to process samples, hr %#lx.\n", hr);
1351 for (i = 0; i < mixer->input_count; ++i)
1353 if (samples[i].SrcSurface)
1354 IDirect3DSurface9_Release(samples[i].SrcSurface);
1358 static HRESULT video_mixer_get_sample_desired_time(IMFSample *sample, LONGLONG *timestamp, LONGLONG *duration)
1360 IMFDesiredSample *desired;
1361 HRESULT hr;
1363 *timestamp = *duration = 0;
1364 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFDesiredSample, (void **)&desired)))
1366 hr = IMFDesiredSample_GetDesiredSampleTimeAndDuration(desired, timestamp, duration);
1367 IMFDesiredSample_Release(desired);
1370 return hr;
1373 static BOOL video_mixer_has_input(const struct video_mixer *mixer)
1375 unsigned int i;
1377 for (i = 0; i < mixer->input_count; ++i)
1379 if (!mixer->inputs[i].sample) return FALSE;
1382 return TRUE;
1385 static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
1386 MFT_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
1388 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1389 LONGLONG timestamp, duration;
1390 IDirect3DSurface9 *surface;
1391 IDirect3DDevice9 *device;
1392 BOOL repaint = FALSE;
1393 unsigned int i;
1394 HRESULT hr;
1396 TRACE("%p, %#lx, %lu, %p, %p.\n", iface, flags, count, buffers, status);
1398 if (!buffers || !count || count > 1 || !buffers->pSample)
1399 return E_INVALIDARG;
1401 if (buffers->dwStreamID)
1402 return MF_E_INVALIDSTREAMNUMBER;
1404 *status = 0;
1406 EnterCriticalSection(&mixer->cs);
1408 if (SUCCEEDED(hr = video_mixer_get_sample_surface(buffers->pSample, &surface)))
1410 if (mixer->is_streaming)
1412 /* Desired timestamp is ignored, duration is required to be non-zero but is not used either. */
1413 if (SUCCEEDED(video_mixer_get_sample_desired_time(buffers->pSample, &timestamp, &duration)))
1415 if (!(repaint = !!duration))
1417 WARN("Unexpected sample duration.\n");
1418 hr = E_INVALIDARG;
1422 /* Not enough input, or no new input. */
1423 if (SUCCEEDED(hr) && (!video_mixer_has_input(mixer) || (!repaint && mixer->output_rendered)))
1424 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1426 if (SUCCEEDED(hr))
1428 video_mixer_render(mixer, surface);
1430 timestamp = duration = 0;
1431 if (SUCCEEDED(IMFSample_GetSampleTime(mixer->inputs[0].sample, &timestamp)))
1433 IMFSample_GetSampleDuration(mixer->inputs[0].sample, &duration);
1434 IMFSample_SetSampleTime(buffers->pSample, timestamp);
1435 IMFSample_SetSampleDuration(buffers->pSample, duration);
1437 mixer->output_rendered = 1;
1440 if (SUCCEEDED(hr) && !repaint)
1442 for (i = 0; i < mixer->input_count; ++i)
1443 video_mixer_request_sample(mixer, i);
1446 else
1448 if (SUCCEEDED(video_mixer_get_sample_desired_time(buffers->pSample, &timestamp, &duration)))
1450 if (SUCCEEDED(hr = video_mixer_get_d3d_device(mixer, &device)))
1452 IDirect3DDevice9_ColorFill(device, surface, NULL, 0);
1453 IDirect3DDeviceManager9_UnlockDevice(mixer->device_manager, mixer->device_handle, FALSE);
1454 IDirect3DDevice9_Release(device);
1457 else
1458 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1460 IDirect3DSurface9_Release(surface);
1463 LeaveCriticalSection(&mixer->cs);
1465 return hr;
1468 static const IMFTransformVtbl video_mixer_transform_vtbl =
1470 video_mixer_transform_QueryInterface,
1471 video_mixer_transform_AddRef,
1472 video_mixer_transform_Release,
1473 video_mixer_transform_GetStreamLimits,
1474 video_mixer_transform_GetStreamCount,
1475 video_mixer_transform_GetStreamIDs,
1476 video_mixer_transform_GetInputStreamInfo,
1477 video_mixer_transform_GetOutputStreamInfo,
1478 video_mixer_transform_GetAttributes,
1479 video_mixer_transform_GetInputStreamAttributes,
1480 video_mixer_transform_GetOutputStreamAttributes,
1481 video_mixer_transform_DeleteInputStream,
1482 video_mixer_transform_AddInputStreams,
1483 video_mixer_transform_GetInputAvailableType,
1484 video_mixer_transform_GetOutputAvailableType,
1485 video_mixer_transform_SetInputType,
1486 video_mixer_transform_SetOutputType,
1487 video_mixer_transform_GetInputCurrentType,
1488 video_mixer_transform_GetOutputCurrentType,
1489 video_mixer_transform_GetInputStatus,
1490 video_mixer_transform_GetOutputStatus,
1491 video_mixer_transform_SetOutputBounds,
1492 video_mixer_transform_ProcessEvent,
1493 video_mixer_transform_ProcessMessage,
1494 video_mixer_transform_ProcessInput,
1495 video_mixer_transform_ProcessOutput,
1498 static HRESULT WINAPI video_mixer_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
1500 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1501 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1504 static ULONG WINAPI video_mixer_device_id_AddRef(IMFVideoDeviceID *iface)
1506 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1507 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1510 static ULONG WINAPI video_mixer_device_id_Release(IMFVideoDeviceID *iface)
1512 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1513 return IMFTransform_Release(&mixer->IMFTransform_iface);
1516 static HRESULT WINAPI video_mixer_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
1518 TRACE("%p, %p.\n", iface, device_id);
1520 if (!device_id)
1521 return E_POINTER;
1523 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
1525 return S_OK;
1528 static const IMFVideoDeviceIDVtbl video_mixer_device_id_vtbl =
1530 video_mixer_device_id_QueryInterface,
1531 video_mixer_device_id_AddRef,
1532 video_mixer_device_id_Release,
1533 video_mixer_device_id_GetDeviceID,
1536 static HRESULT WINAPI video_mixer_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
1537 REFIID riid, void **obj)
1539 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1540 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1543 static ULONG WINAPI video_mixer_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
1545 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1546 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1549 static ULONG WINAPI video_mixer_service_client_Release(IMFTopologyServiceLookupClient *iface)
1551 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1552 return IMFTransform_Release(&mixer->IMFTransform_iface);
1555 static HRESULT WINAPI video_mixer_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
1556 IMFTopologyServiceLookup *service_lookup)
1558 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1559 DWORD count;
1560 HRESULT hr;
1562 TRACE("%p, %p.\n", iface, service_lookup);
1564 if (!service_lookup)
1565 return E_POINTER;
1567 EnterCriticalSection(&mixer->cs);
1569 count = 1;
1570 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1571 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&mixer->event_sink, &count)))
1573 WARN("Failed to get renderer event sink, hr %#lx.\n", hr);
1576 LeaveCriticalSection(&mixer->cs);
1578 return hr;
1581 static HRESULT WINAPI video_mixer_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
1583 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1585 TRACE("%p.\n", iface);
1587 EnterCriticalSection(&mixer->cs);
1589 if (mixer->event_sink)
1590 IMediaEventSink_Release(mixer->event_sink);
1591 mixer->event_sink = NULL;
1593 LeaveCriticalSection(&mixer->cs);
1595 return S_OK;
1598 static const IMFTopologyServiceLookupClientVtbl video_mixer_service_client_vtbl =
1600 video_mixer_service_client_QueryInterface,
1601 video_mixer_service_client_AddRef,
1602 video_mixer_service_client_Release,
1603 video_mixer_service_client_InitServicePointers,
1604 video_mixer_service_client_ReleaseServicePointers,
1607 static HRESULT WINAPI video_mixer_control_QueryInterface(IMFVideoMixerControl2 *iface, REFIID riid, void **obj)
1609 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1610 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1613 static ULONG WINAPI video_mixer_control_AddRef(IMFVideoMixerControl2 *iface)
1615 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1616 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1619 static ULONG WINAPI video_mixer_control_Release(IMFVideoMixerControl2 *iface)
1621 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1622 return IMFTransform_Release(&mixer->IMFTransform_iface);
1625 static HRESULT WINAPI video_mixer_control_SetStreamZOrder(IMFVideoMixerControl2 *iface, DWORD id, DWORD zorder)
1627 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1628 struct input_stream *stream;
1629 HRESULT hr;
1631 TRACE("%p, %lu, %lu.\n", iface, id, zorder);
1633 /* Can't change reference stream. */
1634 if (!id && zorder)
1635 return E_INVALIDARG;
1637 EnterCriticalSection(&mixer->cs);
1639 if (zorder >= mixer->input_count)
1640 hr = E_INVALIDARG;
1641 else if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1643 /* Lowest zorder only applies to reference stream. */
1644 if (id && !zorder)
1645 hr = MF_E_INVALIDREQUEST;
1646 else if (stream->zorder != zorder)
1648 stream->zorder = zorder;
1649 video_mixer_update_zorder_map(mixer);
1653 LeaveCriticalSection(&mixer->cs);
1655 return hr;
1658 static HRESULT WINAPI video_mixer_control_GetStreamZOrder(IMFVideoMixerControl2 *iface, DWORD id, DWORD *zorder)
1660 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1661 struct input_stream *stream;
1662 HRESULT hr;
1664 TRACE("%p, %lu, %p.\n", iface, id, zorder);
1666 if (!zorder)
1667 return E_POINTER;
1669 EnterCriticalSection(&mixer->cs);
1671 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1672 *zorder = stream->zorder;
1674 LeaveCriticalSection(&mixer->cs);
1676 return hr;
1679 static HRESULT WINAPI video_mixer_control_SetStreamOutputRect(IMFVideoMixerControl2 *iface, DWORD id,
1680 const MFVideoNormalizedRect *rect)
1682 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1683 struct input_stream *stream;
1684 HRESULT hr;
1686 TRACE("%p, %lu, %s.\n", iface, id, debugstr_normalized_rect(rect));
1688 if (!rect)
1689 return E_POINTER;
1691 if (rect->left > rect->right || rect->top > rect->bottom ||
1692 rect->left < 0.0f || rect->top < 0.0f || rect->right > 1.0f || rect->bottom > 1.0f)
1694 return E_INVALIDARG;
1697 EnterCriticalSection(&mixer->cs);
1699 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1700 stream->rect = *rect;
1702 LeaveCriticalSection(&mixer->cs);
1704 return hr;
1707 static HRESULT WINAPI video_mixer_control_GetStreamOutputRect(IMFVideoMixerControl2 *iface, DWORD id,
1708 MFVideoNormalizedRect *rect)
1710 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1711 struct input_stream *stream;
1712 HRESULT hr;
1714 TRACE("%p, %lu, %p.\n", iface, id, rect);
1716 if (!rect)
1717 return E_POINTER;
1719 EnterCriticalSection(&mixer->cs);
1721 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1722 *rect = stream->rect;
1724 LeaveCriticalSection(&mixer->cs);
1726 return hr;
1729 static HRESULT WINAPI video_mixer_control_SetMixingPrefs(IMFVideoMixerControl2 *iface, DWORD flags)
1731 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1733 TRACE("%p, %#lx.\n", iface, flags);
1735 EnterCriticalSection(&mixer->cs);
1736 mixer->mixing_flags = flags;
1737 LeaveCriticalSection(&mixer->cs);
1739 return S_OK;
1742 static HRESULT WINAPI video_mixer_control_GetMixingPrefs(IMFVideoMixerControl2 *iface, DWORD *flags)
1744 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1746 TRACE("%p, %p.\n", iface, flags);
1748 if (!flags)
1749 return E_POINTER;
1751 EnterCriticalSection(&mixer->cs);
1752 *flags = mixer->mixing_flags;
1753 LeaveCriticalSection(&mixer->cs);
1755 return S_OK;
1758 static const IMFVideoMixerControl2Vtbl video_mixer_control_vtbl =
1760 video_mixer_control_QueryInterface,
1761 video_mixer_control_AddRef,
1762 video_mixer_control_Release,
1763 video_mixer_control_SetStreamZOrder,
1764 video_mixer_control_GetStreamZOrder,
1765 video_mixer_control_SetStreamOutputRect,
1766 video_mixer_control_GetStreamOutputRect,
1767 video_mixer_control_SetMixingPrefs,
1768 video_mixer_control_GetMixingPrefs,
1771 static HRESULT WINAPI video_mixer_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1773 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1774 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1777 static ULONG WINAPI video_mixer_getservice_AddRef(IMFGetService *iface)
1779 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1780 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1783 static ULONG WINAPI video_mixer_getservice_Release(IMFGetService *iface)
1785 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1786 return IMFTransform_Release(&mixer->IMFTransform_iface);
1789 static HRESULT WINAPI video_mixer_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1791 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1793 if (IsEqualGUID(service, &MR_VIDEO_MIXER_SERVICE))
1795 if (IsEqualIID(riid, &IID_IMFVideoMixerBitmap) ||
1796 IsEqualIID(riid, &IID_IMFVideoProcessor) ||
1797 IsEqualIID(riid, &IID_IMFVideoPositionMapper) ||
1798 IsEqualIID(riid, &IID_IMFVideoMixerControl) ||
1799 IsEqualIID(riid, &IID_IMFVideoMixerControl2))
1801 return IMFGetService_QueryInterface(iface, riid, obj);
1804 return E_NOINTERFACE;
1807 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1809 return MF_E_UNSUPPORTED_SERVICE;
1812 static const IMFGetServiceVtbl video_mixer_getservice_vtbl =
1814 video_mixer_getservice_QueryInterface,
1815 video_mixer_getservice_AddRef,
1816 video_mixer_getservice_Release,
1817 video_mixer_getservice_GetService,
1820 static HRESULT WINAPI video_mixer_bitmap_QueryInterface(IMFVideoMixerBitmap *iface, REFIID riid, void **obj)
1822 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1823 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1826 static ULONG WINAPI video_mixer_bitmap_AddRef(IMFVideoMixerBitmap *iface)
1828 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1829 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1832 static ULONG WINAPI video_mixer_bitmap_Release(IMFVideoMixerBitmap *iface)
1834 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1835 return IMFTransform_Release(&mixer->IMFTransform_iface);
1838 static HRESULT WINAPI video_mixer_bitmap_SetAlphaBitmap(IMFVideoMixerBitmap *iface, const MFVideoAlphaBitmap *bitmap)
1840 FIXME("%p, %p.\n", iface, bitmap);
1842 return E_NOTIMPL;
1845 static HRESULT WINAPI video_mixer_bitmap_ClearAlphaBitmap(IMFVideoMixerBitmap *iface)
1847 FIXME("%p.\n", iface);
1849 return E_NOTIMPL;
1852 static HRESULT WINAPI video_mixer_bitmap_UpdateAlphaBitmapParameters(IMFVideoMixerBitmap *iface,
1853 const MFVideoAlphaBitmapParams *params)
1855 FIXME("%p, %p.\n", iface, params);
1857 return E_NOTIMPL;
1860 static HRESULT WINAPI video_mixer_bitmap_GetAlphaBitmapParameters(IMFVideoMixerBitmap *iface, MFVideoAlphaBitmapParams *params)
1862 FIXME("%p, %p.\n", iface, params);
1864 return E_NOTIMPL;
1867 static const IMFVideoMixerBitmapVtbl video_mixer_bitmap_vtbl =
1869 video_mixer_bitmap_QueryInterface,
1870 video_mixer_bitmap_AddRef,
1871 video_mixer_bitmap_Release,
1872 video_mixer_bitmap_SetAlphaBitmap,
1873 video_mixer_bitmap_ClearAlphaBitmap,
1874 video_mixer_bitmap_UpdateAlphaBitmapParameters,
1875 video_mixer_bitmap_GetAlphaBitmapParameters,
1878 static HRESULT WINAPI video_mixer_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1880 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1881 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1884 static ULONG WINAPI video_mixer_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1886 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1887 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1890 static ULONG WINAPI video_mixer_position_mapper_Release(IMFVideoPositionMapper *iface)
1892 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1893 return IMFTransform_Release(&mixer->IMFTransform_iface);
1896 static HRESULT WINAPI video_mixer_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1897 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1899 FIXME("%p, %f, %f, %lu, %lu, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1901 return E_NOTIMPL;
1904 static const IMFVideoPositionMapperVtbl video_mixer_position_mapper_vtbl =
1906 video_mixer_position_mapper_QueryInterface,
1907 video_mixer_position_mapper_AddRef,
1908 video_mixer_position_mapper_Release,
1909 video_mixer_position_mapper_MapOutputCoordinateToInputStream,
1912 static HRESULT WINAPI video_mixer_processor_QueryInterface(IMFVideoProcessor *iface, REFIID riid, void **obj)
1914 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1915 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1918 static ULONG WINAPI video_mixer_processor_AddRef(IMFVideoProcessor *iface)
1920 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1921 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1924 static ULONG WINAPI video_mixer_processor_Release(IMFVideoProcessor *iface)
1926 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1927 return IMFTransform_Release(&mixer->IMFTransform_iface);
1930 static HRESULT WINAPI video_mixer_processor_GetAvailableVideoProcessorModes(IMFVideoProcessor *iface, UINT *count,
1931 GUID **modes)
1933 FIXME("%p, %p, %p.\n", iface, count, modes);
1935 return E_NOTIMPL;
1938 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorCaps(IMFVideoProcessor *iface, GUID *mode,
1939 DXVA2_VideoProcessorCaps *caps)
1941 FIXME("%p, %s, %p.\n", iface, debugstr_guid(mode), caps);
1943 return E_NOTIMPL;
1946 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1948 FIXME("%p, %p.\n", iface, mode);
1950 return E_NOTIMPL;
1953 static HRESULT WINAPI video_mixer_processor_SetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1955 FIXME("%p, %s.\n", iface, debugstr_guid(mode));
1957 return E_NOTIMPL;
1960 static HRESULT WINAPI video_mixer_processor_GetProcAmpRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
1962 FIXME("%p, %#lx, %p.\n", iface, prop, range);
1964 return E_NOTIMPL;
1967 static HRESULT WINAPI video_mixer_processor_GetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
1969 FIXME("%p, %#lx, %p.\n", iface, flags, values);
1971 return E_NOTIMPL;
1974 static HRESULT WINAPI video_mixer_processor_SetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
1976 FIXME("%p, %#lx, %p.\n", iface, flags, values);
1978 return E_NOTIMPL;
1981 static HRESULT WINAPI video_mixer_processor_GetFilteringRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
1983 FIXME("%p, %#lx, %p.\n", iface, prop, range);
1985 return E_NOTIMPL;
1988 static HRESULT WINAPI video_mixer_processor_GetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
1990 FIXME("%p, %#lx, %p.\n", iface, prop, value);
1992 return E_NOTIMPL;
1995 static HRESULT WINAPI video_mixer_processor_SetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
1997 FIXME("%p, %#lx, %p.\n", iface, prop, value);
1999 return E_NOTIMPL;
2002 static HRESULT WINAPI video_mixer_processor_GetBackgroundColor(IMFVideoProcessor *iface, COLORREF *color)
2004 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
2006 TRACE("%p, %p.\n", iface, color);
2008 if (!color)
2009 return E_POINTER;
2011 EnterCriticalSection(&mixer->cs);
2012 *color = mixer->bkgnd_color.rgba;
2013 LeaveCriticalSection(&mixer->cs);
2015 return S_OK;
2018 static void video_mixer_rgb_to_ycbcr(COLORREF rgb, DXVA2_AYUVSample16 *ayuv)
2020 int y, cb, cr, r, g, b;
2022 r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb);
2023 /* Coefficients according to SDTV ITU-R BT.601 */
2024 y = (77 * r + 150 * g + 29 * b + 128) / 256 + 16;
2025 cb = (-44 * r - 87 * g + 131 * b + 128) / 256 + 128;
2026 cr = (131 * r - 110 * g - 21 * b + 128) / 256 + 128;
2028 ayuv->Y = y * 0x100;
2029 ayuv->Cb = cb * 0x100;
2030 ayuv->Cr = cr * 0x100;
2031 ayuv->Alpha = 0xffff;
2034 static HRESULT WINAPI video_mixer_processor_SetBackgroundColor(IMFVideoProcessor *iface, COLORREF color)
2036 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
2038 TRACE("%p, %#lx.\n", iface, color);
2040 EnterCriticalSection(&mixer->cs);
2041 if (mixer->bkgnd_color.rgba != color)
2043 video_mixer_rgb_to_ycbcr(color, &mixer->bkgnd_color.ayuv);
2044 mixer->bkgnd_color.rgba = color;
2046 LeaveCriticalSection(&mixer->cs);
2048 return S_OK;
2051 static const IMFVideoProcessorVtbl video_mixer_processor_vtbl =
2053 video_mixer_processor_QueryInterface,
2054 video_mixer_processor_AddRef,
2055 video_mixer_processor_Release,
2056 video_mixer_processor_GetAvailableVideoProcessorModes,
2057 video_mixer_processor_GetVideoProcessorCaps,
2058 video_mixer_processor_GetVideoProcessorMode,
2059 video_mixer_processor_SetVideoProcessorMode,
2060 video_mixer_processor_GetProcAmpRange,
2061 video_mixer_processor_GetProcAmpValues,
2062 video_mixer_processor_SetProcAmpValues,
2063 video_mixer_processor_GetFilteringRange,
2064 video_mixer_processor_GetFilteringValue,
2065 video_mixer_processor_SetFilteringValue,
2066 video_mixer_processor_GetBackgroundColor,
2067 video_mixer_processor_SetBackgroundColor,
2070 static HRESULT WINAPI video_mixer_attributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out)
2072 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2073 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2076 static ULONG WINAPI video_mixer_attributes_AddRef(IMFAttributes *iface)
2078 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2079 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2082 static ULONG WINAPI video_mixer_attributes_Release(IMFAttributes *iface)
2084 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2085 return IMFTransform_Release(&mixer->IMFTransform_iface);
2088 static HRESULT WINAPI video_mixer_attributes_GetItem(IMFAttributes *iface, REFGUID key, PROPVARIANT *value)
2090 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2092 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2094 return IMFAttributes_GetItem(mixer->internal_attributes, key, value);
2097 static HRESULT WINAPI video_mixer_attributes_GetItemType(IMFAttributes *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
2099 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2101 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
2103 return IMFAttributes_GetItemType(mixer->internal_attributes, key, type);
2106 static HRESULT WINAPI video_mixer_attributes_CompareItem(IMFAttributes *iface, REFGUID key,
2107 REFPROPVARIANT value, BOOL *result)
2109 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2111 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
2113 return IMFAttributes_CompareItem(mixer->internal_attributes, key, value, result);
2116 static HRESULT WINAPI video_mixer_attributes_Compare(IMFAttributes *iface, IMFAttributes *theirs,
2117 MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
2119 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2121 TRACE("%p, %p, %d, %p.\n", iface, theirs, match_type, ret);
2123 return IMFAttributes_Compare(mixer->internal_attributes, theirs, match_type, ret);
2126 static HRESULT WINAPI video_mixer_attributes_GetUINT32(IMFAttributes *iface, REFGUID key, UINT32 *value)
2128 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2130 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2132 return IMFAttributes_GetUINT32(mixer->internal_attributes, key, value);
2135 static HRESULT WINAPI video_mixer_attributes_GetUINT64(IMFAttributes *iface, REFGUID key, UINT64 *value)
2137 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2139 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2141 return IMFAttributes_GetUINT64(mixer->internal_attributes, key, value);
2144 static HRESULT WINAPI video_mixer_attributes_GetDouble(IMFAttributes *iface, REFGUID key, double *value)
2146 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2148 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2150 return IMFAttributes_GetDouble(mixer->internal_attributes, key, value);
2153 static HRESULT WINAPI video_mixer_attributes_GetGUID(IMFAttributes *iface, REFGUID key, GUID *value)
2155 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2157 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2159 return IMFAttributes_GetGUID(mixer->internal_attributes, key, value);
2162 static HRESULT WINAPI video_mixer_attributes_GetStringLength(IMFAttributes *iface, REFGUID key, UINT32 *length)
2164 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2166 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
2168 return IMFAttributes_GetStringLength(mixer->internal_attributes, key, length);
2171 static HRESULT WINAPI video_mixer_attributes_GetString(IMFAttributes *iface, REFGUID key, WCHAR *value,
2172 UINT32 size, UINT32 *length)
2174 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2176 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), value, size, length);
2178 return IMFAttributes_GetString(mixer->internal_attributes, key, value, size, length);
2181 static HRESULT WINAPI video_mixer_attributes_GetAllocatedString(IMFAttributes *iface, REFGUID key,
2182 WCHAR **value, UINT32 *length)
2184 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2186 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
2188 return IMFAttributes_GetAllocatedString(mixer->internal_attributes, key, value, length);
2191 static HRESULT WINAPI video_mixer_attributes_GetBlobSize(IMFAttributes *iface, REFGUID key, UINT32 *size)
2193 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2195 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
2197 return IMFAttributes_GetBlobSize(mixer->internal_attributes, key, size);
2200 static HRESULT WINAPI video_mixer_attributes_GetBlob(IMFAttributes *iface, REFGUID key, UINT8 *buf,
2201 UINT32 bufsize, UINT32 *blobsize)
2203 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2205 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
2207 return IMFAttributes_GetBlob(mixer->internal_attributes, key, buf, bufsize, blobsize);
2210 static HRESULT WINAPI video_mixer_attributes_GetAllocatedBlob(IMFAttributes *iface, REFGUID key, UINT8 **buf, UINT32 *size)
2212 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2214 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
2216 return IMFAttributes_GetAllocatedBlob(mixer->internal_attributes, key, buf, size);
2219 static HRESULT WINAPI video_mixer_attributes_GetUnknown(IMFAttributes *iface, REFGUID key, REFIID riid, void **out)
2221 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2223 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
2225 return IMFAttributes_GetUnknown(mixer->internal_attributes, key, riid, out);
2228 static HRESULT WINAPI video_mixer_attributes_SetItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value)
2230 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2232 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2234 return IMFAttributes_SetItem(mixer->internal_attributes, key, value);
2237 static HRESULT WINAPI video_mixer_attributes_DeleteItem(IMFAttributes *iface, REFGUID key)
2239 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2241 TRACE("%p, %s.\n", iface, debugstr_guid(key));
2243 return IMFAttributes_DeleteItem(mixer->internal_attributes, key);
2246 static HRESULT WINAPI video_mixer_attributes_DeleteAllItems(IMFAttributes *iface)
2248 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2250 TRACE("%p.\n", iface);
2252 return IMFAttributes_DeleteAllItems(mixer->internal_attributes);
2255 static HRESULT WINAPI video_mixer_attributes_SetUINT32(IMFAttributes *iface, REFGUID key, UINT32 value)
2257 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2259 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
2261 return IMFAttributes_SetUINT32(mixer->internal_attributes, key, value);
2264 static HRESULT WINAPI video_mixer_attributes_SetUINT64(IMFAttributes *iface, REFGUID key, UINT64 value)
2266 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2268 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
2270 return IMFAttributes_SetUINT64(mixer->internal_attributes, key, value);
2273 static HRESULT WINAPI video_mixer_attributes_SetDouble(IMFAttributes *iface, REFGUID key, double value)
2275 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2277 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
2279 return IMFAttributes_SetDouble(mixer->internal_attributes, key, value);
2282 static HRESULT WINAPI video_mixer_attributes_SetGUID(IMFAttributes *iface, REFGUID key, REFGUID value)
2284 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2286 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
2288 return IMFAttributes_SetGUID(mixer->internal_attributes, key, value);
2291 static HRESULT WINAPI video_mixer_attributes_SetString(IMFAttributes *iface, REFGUID key, const WCHAR *value)
2293 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2295 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
2297 return IMFAttributes_SetString(mixer->internal_attributes, key, value);
2300 static HRESULT WINAPI video_mixer_attributes_SetBlob(IMFAttributes *iface, REFGUID key, const UINT8 *buf, UINT32 size)
2302 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2304 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
2306 return IMFAttributes_SetBlob(mixer->internal_attributes, key, buf, size);
2309 static HRESULT WINAPI video_mixer_attributes_SetUnknown(IMFAttributes *iface, REFGUID key, IUnknown *unknown)
2311 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2313 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
2315 return IMFAttributes_SetUnknown(mixer->internal_attributes, key, unknown);
2318 static HRESULT WINAPI video_mixer_attributes_LockStore(IMFAttributes *iface)
2320 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2322 TRACE("%p.\n", iface);
2324 return IMFAttributes_LockStore(mixer->internal_attributes);
2327 static HRESULT WINAPI video_mixer_attributes_UnlockStore(IMFAttributes *iface)
2329 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2331 TRACE("%p.\n", iface);
2333 return IMFAttributes_UnlockStore(mixer->internal_attributes);
2336 static HRESULT WINAPI video_mixer_attributes_GetCount(IMFAttributes *iface, UINT32 *count)
2338 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2340 TRACE("%p, %p.\n", iface, count);
2342 return IMFAttributes_GetCount(mixer->internal_attributes, count);
2345 static HRESULT WINAPI video_mixer_attributes_GetItemByIndex(IMFAttributes *iface, UINT32 index,
2346 GUID *key, PROPVARIANT *value)
2348 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2350 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
2352 return IMFAttributes_GetItemByIndex(mixer->internal_attributes, index, key, value);
2355 static HRESULT WINAPI video_mixer_attributes_CopyAllItems(IMFAttributes *iface, IMFAttributes *dest)
2357 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2359 TRACE("%p, %p.\n", iface, dest);
2361 return IMFAttributes_CopyAllItems(mixer->internal_attributes, dest);
2364 static const IMFAttributesVtbl video_mixer_attributes_vtbl =
2366 video_mixer_attributes_QueryInterface,
2367 video_mixer_attributes_AddRef,
2368 video_mixer_attributes_Release,
2369 video_mixer_attributes_GetItem,
2370 video_mixer_attributes_GetItemType,
2371 video_mixer_attributes_CompareItem,
2372 video_mixer_attributes_Compare,
2373 video_mixer_attributes_GetUINT32,
2374 video_mixer_attributes_GetUINT64,
2375 video_mixer_attributes_GetDouble,
2376 video_mixer_attributes_GetGUID,
2377 video_mixer_attributes_GetStringLength,
2378 video_mixer_attributes_GetString,
2379 video_mixer_attributes_GetAllocatedString,
2380 video_mixer_attributes_GetBlobSize,
2381 video_mixer_attributes_GetBlob,
2382 video_mixer_attributes_GetAllocatedBlob,
2383 video_mixer_attributes_GetUnknown,
2384 video_mixer_attributes_SetItem,
2385 video_mixer_attributes_DeleteItem,
2386 video_mixer_attributes_DeleteAllItems,
2387 video_mixer_attributes_SetUINT32,
2388 video_mixer_attributes_SetUINT64,
2389 video_mixer_attributes_SetDouble,
2390 video_mixer_attributes_SetGUID,
2391 video_mixer_attributes_SetString,
2392 video_mixer_attributes_SetBlob,
2393 video_mixer_attributes_SetUnknown,
2394 video_mixer_attributes_LockStore,
2395 video_mixer_attributes_UnlockStore,
2396 video_mixer_attributes_GetCount,
2397 video_mixer_attributes_GetItemByIndex,
2398 video_mixer_attributes_CopyAllItems
2401 static HRESULT WINAPI video_mixer_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
2403 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2404 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2407 static ULONG WINAPI video_mixer_quality_advise_AddRef(IMFQualityAdvise *iface)
2409 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2410 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2413 static ULONG WINAPI video_mixer_quality_advise_Release(IMFQualityAdvise *iface)
2415 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2416 return IMFTransform_Release(&mixer->IMFTransform_iface);
2419 static HRESULT WINAPI video_mixer_quality_advise_SetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE mode)
2421 FIXME("%p, %u.\n", iface, mode);
2423 return E_NOTIMPL;
2426 static HRESULT WINAPI video_mixer_quality_advise_SetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL level)
2428 FIXME("%p, %u.\n", iface, level);
2430 return E_NOTIMPL;
2433 static HRESULT WINAPI video_mixer_quality_advise_GetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE *mode)
2435 FIXME("%p, %p.\n", iface, mode);
2437 return E_NOTIMPL;
2440 static HRESULT WINAPI video_mixer_quality_advise_GetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL *level)
2442 FIXME("%p, %p.\n", iface, level);
2444 return E_NOTIMPL;
2447 static HRESULT WINAPI video_mixer_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
2449 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
2451 return E_NOTIMPL;
2454 static const IMFQualityAdviseVtbl video_mixer_quality_advise_vtbl =
2456 video_mixer_quality_advise_QueryInterface,
2457 video_mixer_quality_advise_AddRef,
2458 video_mixer_quality_advise_Release,
2459 video_mixer_quality_advise_SetDropMode,
2460 video_mixer_quality_advise_SetQualityLevel,
2461 video_mixer_quality_advise_GetDropMode,
2462 video_mixer_quality_advise_GetQualityLevel,
2463 video_mixer_quality_advise_DropTime,
2466 static HRESULT WINAPI video_mixer_clock_state_sink_QueryInterface(IMFClockStateSink *iface,
2467 REFIID riid, void **out)
2469 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2470 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2473 static ULONG WINAPI video_mixer_clock_state_sink_AddRef(IMFClockStateSink *iface)
2475 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2476 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2479 static ULONG WINAPI video_mixer_clock_state_sink_Release(IMFClockStateSink *iface)
2481 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2482 return IMFTransform_Release(&mixer->IMFTransform_iface);
2485 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStart(IMFClockStateSink *iface,
2486 MFTIME systime, LONGLONG offset)
2488 FIXME("%p.\n", iface);
2490 return E_NOTIMPL;
2493 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStop(IMFClockStateSink *iface,
2494 MFTIME systime)
2496 FIXME("%p.\n", iface);
2498 return E_NOTIMPL;
2501 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockPause(IMFClockStateSink *iface,
2502 MFTIME systime)
2504 FIXME("%p.\n", iface);
2506 return E_NOTIMPL;
2509 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockRestart(IMFClockStateSink *iface,
2510 MFTIME systime)
2512 FIXME("%p.\n", iface);
2514 return E_NOTIMPL;
2517 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockSetRate(IMFClockStateSink *iface,
2518 MFTIME systime, float rate)
2520 FIXME("%p, %f.\n", iface, rate);
2522 return E_NOTIMPL;
2525 static const IMFClockStateSinkVtbl video_mixer_clock_state_sink_vtbl =
2527 video_mixer_clock_state_sink_QueryInterface,
2528 video_mixer_clock_state_sink_AddRef,
2529 video_mixer_clock_state_sink_Release,
2530 video_mixer_clock_state_sink_OnClockStart,
2531 video_mixer_clock_state_sink_OnClockStop,
2532 video_mixer_clock_state_sink_OnClockPause,
2533 video_mixer_clock_state_sink_OnClockRestart,
2534 video_mixer_clock_state_sink_OnClockSetRate,
2537 HRESULT WINAPI MFCreateVideoMixer(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
2539 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
2541 *obj = NULL;
2543 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
2544 return E_INVALIDARG;
2546 return CoCreateInstance(&CLSID_MFVideoMixer9, owner, CLSCTX_INPROC_SERVER, riid, obj);
2549 HRESULT evr_mixer_create(IUnknown *outer, void **out)
2551 struct video_mixer *object;
2552 MFVideoNormalizedRect rect;
2553 HRESULT hr;
2555 if (!(object = calloc(1, sizeof(*object))))
2556 return E_OUTOFMEMORY;
2558 object->IMFTransform_iface.lpVtbl = &video_mixer_transform_vtbl;
2559 object->IMFVideoDeviceID_iface.lpVtbl = &video_mixer_device_id_vtbl;
2560 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_mixer_service_client_vtbl;
2561 object->IMFVideoMixerControl2_iface.lpVtbl = &video_mixer_control_vtbl;
2562 object->IMFGetService_iface.lpVtbl = &video_mixer_getservice_vtbl;
2563 object->IMFVideoMixerBitmap_iface.lpVtbl = &video_mixer_bitmap_vtbl;
2564 object->IMFVideoPositionMapper_iface.lpVtbl = &video_mixer_position_mapper_vtbl;
2565 object->IMFVideoProcessor_iface.lpVtbl = &video_mixer_processor_vtbl;
2566 object->IMFAttributes_iface.lpVtbl = &video_mixer_attributes_vtbl;
2567 object->IMFQualityAdvise_iface.lpVtbl = &video_mixer_quality_advise_vtbl;
2568 object->IMFClockStateSink_iface.lpVtbl = &video_mixer_clock_state_sink_vtbl;
2569 object->IUnknown_inner.lpVtbl = &video_mixer_inner_vtbl;
2570 object->outer_unk = outer ? outer : &object->IUnknown_inner;
2571 object->refcount = 1;
2572 object->input_count = 1;
2573 object->lower_bound = MFT_OUTPUT_BOUND_LOWER_UNBOUNDED;
2574 object->upper_bound = MFT_OUTPUT_BOUND_UPPER_UNBOUNDED;
2575 video_mixer_init_input(&object->inputs[0]);
2576 video_mixer_update_zorder_map(object);
2577 video_mixer_rgb_to_ycbcr(object->bkgnd_color.rgba, &object->bkgnd_color.ayuv);
2578 InitializeCriticalSection(&object->cs);
2579 if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
2581 IUnknown_Release(&object->IUnknown_inner);
2582 return hr;
2584 if (FAILED(hr = MFCreateAttributes(&object->internal_attributes, 0)))
2586 IUnknown_Release(&object->IUnknown_inner);
2587 return hr;
2590 /* Default attributes configuration. */
2592 rect.left = rect.top = 0.0f;
2593 rect.right = rect.bottom = 1.0f;
2594 IMFAttributes_SetBlob(object->attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&rect, sizeof(rect));
2596 IMFAttributes_SetUINT32(object->internal_attributes, &MF_SA_D3D_AWARE, 1);
2598 *out = &object->IUnknown_inner;
2600 return S_OK;