vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / evr / mixer.c
blob668a97da979e5d3ef2479077679872ae88666e71
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 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1934 IDirectXVideoProcessorService *service;
1935 DXVA2_VideoDesc video_desc;
1936 HRESULT hr;
1938 TRACE("%p, %p, %p.\n", iface, count, modes);
1940 EnterCriticalSection(&mixer->cs);
1942 if (!mixer->inputs[0].media_type || !mixer->output.media_type)
1943 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1944 else if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
1946 video_mixer_init_dxva_videodesc(mixer->inputs[0].media_type, &video_desc);
1947 hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc, count, modes);
1948 IDirectXVideoProcessorService_Release(service);
1951 LeaveCriticalSection(&mixer->cs);
1953 return hr;
1956 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorCaps(IMFVideoProcessor *iface, GUID *mode,
1957 DXVA2_VideoProcessorCaps *caps)
1959 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1960 IDirectXVideoProcessorService *service;
1961 DXVA2_VideoDesc video_desc;
1962 GUID subtype = { 0 };
1963 HRESULT hr;
1965 TRACE("%p, %s, %p.\n", iface, debugstr_guid(mode), caps);
1967 EnterCriticalSection(&mixer->cs);
1969 if (!mixer->inputs[0].media_type || !mixer->output.media_type)
1970 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1971 else if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
1973 video_mixer_init_dxva_videodesc(mixer->inputs[0].media_type, &video_desc);
1974 IMFMediaType_GetGUID(mixer->output.media_type, &MF_MT_SUBTYPE, &subtype);
1976 hr = IDirectXVideoProcessorService_GetVideoProcessorCaps(service, mode, &video_desc, subtype.Data1, caps);
1977 IDirectXVideoProcessorService_Release(service);
1980 LeaveCriticalSection(&mixer->cs);
1982 return hr;
1985 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1987 FIXME("%p, %p.\n", iface, mode);
1989 return E_NOTIMPL;
1992 static HRESULT WINAPI video_mixer_processor_SetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1994 FIXME("%p, %s.\n", iface, debugstr_guid(mode));
1996 return E_NOTIMPL;
1999 static HRESULT WINAPI video_mixer_processor_GetProcAmpRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
2001 FIXME("%p, %#lx, %p.\n", iface, prop, range);
2003 return E_NOTIMPL;
2006 static HRESULT WINAPI video_mixer_processor_GetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
2008 FIXME("%p, %#lx, %p.\n", iface, flags, values);
2010 return E_NOTIMPL;
2013 static HRESULT WINAPI video_mixer_processor_SetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
2015 FIXME("%p, %#lx, %p.\n", iface, flags, values);
2017 return E_NOTIMPL;
2020 static HRESULT WINAPI video_mixer_processor_GetFilteringRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
2022 FIXME("%p, %#lx, %p.\n", iface, prop, range);
2024 return E_NOTIMPL;
2027 static HRESULT WINAPI video_mixer_processor_GetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
2029 FIXME("%p, %#lx, %p.\n", iface, prop, value);
2031 return E_NOTIMPL;
2034 static HRESULT WINAPI video_mixer_processor_SetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
2036 FIXME("%p, %#lx, %p.\n", iface, prop, value);
2038 return E_NOTIMPL;
2041 static HRESULT WINAPI video_mixer_processor_GetBackgroundColor(IMFVideoProcessor *iface, COLORREF *color)
2043 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
2045 TRACE("%p, %p.\n", iface, color);
2047 if (!color)
2048 return E_POINTER;
2050 EnterCriticalSection(&mixer->cs);
2051 *color = mixer->bkgnd_color.rgba;
2052 LeaveCriticalSection(&mixer->cs);
2054 return S_OK;
2057 static void video_mixer_rgb_to_ycbcr(COLORREF rgb, DXVA2_AYUVSample16 *ayuv)
2059 int y, cb, cr, r, g, b;
2061 r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb);
2062 /* Coefficients according to SDTV ITU-R BT.601 */
2063 y = (77 * r + 150 * g + 29 * b + 128) / 256 + 16;
2064 cb = (-44 * r - 87 * g + 131 * b + 128) / 256 + 128;
2065 cr = (131 * r - 110 * g - 21 * b + 128) / 256 + 128;
2067 ayuv->Y = y * 0x100;
2068 ayuv->Cb = cb * 0x100;
2069 ayuv->Cr = cr * 0x100;
2070 ayuv->Alpha = 0xffff;
2073 static HRESULT WINAPI video_mixer_processor_SetBackgroundColor(IMFVideoProcessor *iface, COLORREF color)
2075 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
2077 TRACE("%p, %#lx.\n", iface, color);
2079 EnterCriticalSection(&mixer->cs);
2080 if (mixer->bkgnd_color.rgba != color)
2082 video_mixer_rgb_to_ycbcr(color, &mixer->bkgnd_color.ayuv);
2083 mixer->bkgnd_color.rgba = color;
2085 LeaveCriticalSection(&mixer->cs);
2087 return S_OK;
2090 static const IMFVideoProcessorVtbl video_mixer_processor_vtbl =
2092 video_mixer_processor_QueryInterface,
2093 video_mixer_processor_AddRef,
2094 video_mixer_processor_Release,
2095 video_mixer_processor_GetAvailableVideoProcessorModes,
2096 video_mixer_processor_GetVideoProcessorCaps,
2097 video_mixer_processor_GetVideoProcessorMode,
2098 video_mixer_processor_SetVideoProcessorMode,
2099 video_mixer_processor_GetProcAmpRange,
2100 video_mixer_processor_GetProcAmpValues,
2101 video_mixer_processor_SetProcAmpValues,
2102 video_mixer_processor_GetFilteringRange,
2103 video_mixer_processor_GetFilteringValue,
2104 video_mixer_processor_SetFilteringValue,
2105 video_mixer_processor_GetBackgroundColor,
2106 video_mixer_processor_SetBackgroundColor,
2109 static HRESULT WINAPI video_mixer_attributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out)
2111 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2112 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2115 static ULONG WINAPI video_mixer_attributes_AddRef(IMFAttributes *iface)
2117 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2118 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2121 static ULONG WINAPI video_mixer_attributes_Release(IMFAttributes *iface)
2123 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2124 return IMFTransform_Release(&mixer->IMFTransform_iface);
2127 static HRESULT WINAPI video_mixer_attributes_GetItem(IMFAttributes *iface, REFGUID key, PROPVARIANT *value)
2129 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2131 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2133 return IMFAttributes_GetItem(mixer->internal_attributes, key, value);
2136 static HRESULT WINAPI video_mixer_attributes_GetItemType(IMFAttributes *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
2138 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2140 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
2142 return IMFAttributes_GetItemType(mixer->internal_attributes, key, type);
2145 static HRESULT WINAPI video_mixer_attributes_CompareItem(IMFAttributes *iface, REFGUID key,
2146 REFPROPVARIANT value, BOOL *result)
2148 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2150 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
2152 return IMFAttributes_CompareItem(mixer->internal_attributes, key, value, result);
2155 static HRESULT WINAPI video_mixer_attributes_Compare(IMFAttributes *iface, IMFAttributes *theirs,
2156 MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
2158 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2160 TRACE("%p, %p, %d, %p.\n", iface, theirs, match_type, ret);
2162 return IMFAttributes_Compare(mixer->internal_attributes, theirs, match_type, ret);
2165 static HRESULT WINAPI video_mixer_attributes_GetUINT32(IMFAttributes *iface, REFGUID key, UINT32 *value)
2167 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2169 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2171 return IMFAttributes_GetUINT32(mixer->internal_attributes, key, value);
2174 static HRESULT WINAPI video_mixer_attributes_GetUINT64(IMFAttributes *iface, REFGUID key, UINT64 *value)
2176 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2178 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2180 return IMFAttributes_GetUINT64(mixer->internal_attributes, key, value);
2183 static HRESULT WINAPI video_mixer_attributes_GetDouble(IMFAttributes *iface, REFGUID key, double *value)
2185 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2187 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2189 return IMFAttributes_GetDouble(mixer->internal_attributes, key, value);
2192 static HRESULT WINAPI video_mixer_attributes_GetGUID(IMFAttributes *iface, REFGUID key, GUID *value)
2194 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2196 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2198 return IMFAttributes_GetGUID(mixer->internal_attributes, key, value);
2201 static HRESULT WINAPI video_mixer_attributes_GetStringLength(IMFAttributes *iface, REFGUID key, UINT32 *length)
2203 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2205 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
2207 return IMFAttributes_GetStringLength(mixer->internal_attributes, key, length);
2210 static HRESULT WINAPI video_mixer_attributes_GetString(IMFAttributes *iface, REFGUID key, WCHAR *value,
2211 UINT32 size, UINT32 *length)
2213 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2215 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), value, size, length);
2217 return IMFAttributes_GetString(mixer->internal_attributes, key, value, size, length);
2220 static HRESULT WINAPI video_mixer_attributes_GetAllocatedString(IMFAttributes *iface, REFGUID key,
2221 WCHAR **value, UINT32 *length)
2223 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2225 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
2227 return IMFAttributes_GetAllocatedString(mixer->internal_attributes, key, value, length);
2230 static HRESULT WINAPI video_mixer_attributes_GetBlobSize(IMFAttributes *iface, REFGUID key, UINT32 *size)
2232 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2234 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
2236 return IMFAttributes_GetBlobSize(mixer->internal_attributes, key, size);
2239 static HRESULT WINAPI video_mixer_attributes_GetBlob(IMFAttributes *iface, REFGUID key, UINT8 *buf,
2240 UINT32 bufsize, UINT32 *blobsize)
2242 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2244 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
2246 return IMFAttributes_GetBlob(mixer->internal_attributes, key, buf, bufsize, blobsize);
2249 static HRESULT WINAPI video_mixer_attributes_GetAllocatedBlob(IMFAttributes *iface, REFGUID key, UINT8 **buf, UINT32 *size)
2251 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2253 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
2255 return IMFAttributes_GetAllocatedBlob(mixer->internal_attributes, key, buf, size);
2258 static HRESULT WINAPI video_mixer_attributes_GetUnknown(IMFAttributes *iface, REFGUID key, REFIID riid, void **out)
2260 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2262 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
2264 return IMFAttributes_GetUnknown(mixer->internal_attributes, key, riid, out);
2267 static HRESULT WINAPI video_mixer_attributes_SetItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value)
2269 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2271 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2273 return IMFAttributes_SetItem(mixer->internal_attributes, key, value);
2276 static HRESULT WINAPI video_mixer_attributes_DeleteItem(IMFAttributes *iface, REFGUID key)
2278 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2280 TRACE("%p, %s.\n", iface, debugstr_guid(key));
2282 return IMFAttributes_DeleteItem(mixer->internal_attributes, key);
2285 static HRESULT WINAPI video_mixer_attributes_DeleteAllItems(IMFAttributes *iface)
2287 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2289 TRACE("%p.\n", iface);
2291 return IMFAttributes_DeleteAllItems(mixer->internal_attributes);
2294 static HRESULT WINAPI video_mixer_attributes_SetUINT32(IMFAttributes *iface, REFGUID key, UINT32 value)
2296 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2298 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
2300 return IMFAttributes_SetUINT32(mixer->internal_attributes, key, value);
2303 static HRESULT WINAPI video_mixer_attributes_SetUINT64(IMFAttributes *iface, REFGUID key, UINT64 value)
2305 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2307 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
2309 return IMFAttributes_SetUINT64(mixer->internal_attributes, key, value);
2312 static HRESULT WINAPI video_mixer_attributes_SetDouble(IMFAttributes *iface, REFGUID key, double value)
2314 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2316 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
2318 return IMFAttributes_SetDouble(mixer->internal_attributes, key, value);
2321 static HRESULT WINAPI video_mixer_attributes_SetGUID(IMFAttributes *iface, REFGUID key, REFGUID value)
2323 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2325 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
2327 return IMFAttributes_SetGUID(mixer->internal_attributes, key, value);
2330 static HRESULT WINAPI video_mixer_attributes_SetString(IMFAttributes *iface, REFGUID key, const WCHAR *value)
2332 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2334 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
2336 return IMFAttributes_SetString(mixer->internal_attributes, key, value);
2339 static HRESULT WINAPI video_mixer_attributes_SetBlob(IMFAttributes *iface, REFGUID key, const UINT8 *buf, UINT32 size)
2341 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2343 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
2345 return IMFAttributes_SetBlob(mixer->internal_attributes, key, buf, size);
2348 static HRESULT WINAPI video_mixer_attributes_SetUnknown(IMFAttributes *iface, REFGUID key, IUnknown *unknown)
2350 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2352 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
2354 return IMFAttributes_SetUnknown(mixer->internal_attributes, key, unknown);
2357 static HRESULT WINAPI video_mixer_attributes_LockStore(IMFAttributes *iface)
2359 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2361 TRACE("%p.\n", iface);
2363 return IMFAttributes_LockStore(mixer->internal_attributes);
2366 static HRESULT WINAPI video_mixer_attributes_UnlockStore(IMFAttributes *iface)
2368 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2370 TRACE("%p.\n", iface);
2372 return IMFAttributes_UnlockStore(mixer->internal_attributes);
2375 static HRESULT WINAPI video_mixer_attributes_GetCount(IMFAttributes *iface, UINT32 *count)
2377 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2379 TRACE("%p, %p.\n", iface, count);
2381 return IMFAttributes_GetCount(mixer->internal_attributes, count);
2384 static HRESULT WINAPI video_mixer_attributes_GetItemByIndex(IMFAttributes *iface, UINT32 index,
2385 GUID *key, PROPVARIANT *value)
2387 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2389 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
2391 return IMFAttributes_GetItemByIndex(mixer->internal_attributes, index, key, value);
2394 static HRESULT WINAPI video_mixer_attributes_CopyAllItems(IMFAttributes *iface, IMFAttributes *dest)
2396 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2398 TRACE("%p, %p.\n", iface, dest);
2400 return IMFAttributes_CopyAllItems(mixer->internal_attributes, dest);
2403 static const IMFAttributesVtbl video_mixer_attributes_vtbl =
2405 video_mixer_attributes_QueryInterface,
2406 video_mixer_attributes_AddRef,
2407 video_mixer_attributes_Release,
2408 video_mixer_attributes_GetItem,
2409 video_mixer_attributes_GetItemType,
2410 video_mixer_attributes_CompareItem,
2411 video_mixer_attributes_Compare,
2412 video_mixer_attributes_GetUINT32,
2413 video_mixer_attributes_GetUINT64,
2414 video_mixer_attributes_GetDouble,
2415 video_mixer_attributes_GetGUID,
2416 video_mixer_attributes_GetStringLength,
2417 video_mixer_attributes_GetString,
2418 video_mixer_attributes_GetAllocatedString,
2419 video_mixer_attributes_GetBlobSize,
2420 video_mixer_attributes_GetBlob,
2421 video_mixer_attributes_GetAllocatedBlob,
2422 video_mixer_attributes_GetUnknown,
2423 video_mixer_attributes_SetItem,
2424 video_mixer_attributes_DeleteItem,
2425 video_mixer_attributes_DeleteAllItems,
2426 video_mixer_attributes_SetUINT32,
2427 video_mixer_attributes_SetUINT64,
2428 video_mixer_attributes_SetDouble,
2429 video_mixer_attributes_SetGUID,
2430 video_mixer_attributes_SetString,
2431 video_mixer_attributes_SetBlob,
2432 video_mixer_attributes_SetUnknown,
2433 video_mixer_attributes_LockStore,
2434 video_mixer_attributes_UnlockStore,
2435 video_mixer_attributes_GetCount,
2436 video_mixer_attributes_GetItemByIndex,
2437 video_mixer_attributes_CopyAllItems
2440 static HRESULT WINAPI video_mixer_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
2442 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2443 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2446 static ULONG WINAPI video_mixer_quality_advise_AddRef(IMFQualityAdvise *iface)
2448 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2449 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2452 static ULONG WINAPI video_mixer_quality_advise_Release(IMFQualityAdvise *iface)
2454 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2455 return IMFTransform_Release(&mixer->IMFTransform_iface);
2458 static HRESULT WINAPI video_mixer_quality_advise_SetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE mode)
2460 FIXME("%p, %u.\n", iface, mode);
2462 return E_NOTIMPL;
2465 static HRESULT WINAPI video_mixer_quality_advise_SetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL level)
2467 FIXME("%p, %u.\n", iface, level);
2469 return E_NOTIMPL;
2472 static HRESULT WINAPI video_mixer_quality_advise_GetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE *mode)
2474 FIXME("%p, %p.\n", iface, mode);
2476 return E_NOTIMPL;
2479 static HRESULT WINAPI video_mixer_quality_advise_GetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL *level)
2481 FIXME("%p, %p.\n", iface, level);
2483 return E_NOTIMPL;
2486 static HRESULT WINAPI video_mixer_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
2488 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
2490 return E_NOTIMPL;
2493 static const IMFQualityAdviseVtbl video_mixer_quality_advise_vtbl =
2495 video_mixer_quality_advise_QueryInterface,
2496 video_mixer_quality_advise_AddRef,
2497 video_mixer_quality_advise_Release,
2498 video_mixer_quality_advise_SetDropMode,
2499 video_mixer_quality_advise_SetQualityLevel,
2500 video_mixer_quality_advise_GetDropMode,
2501 video_mixer_quality_advise_GetQualityLevel,
2502 video_mixer_quality_advise_DropTime,
2505 static HRESULT WINAPI video_mixer_clock_state_sink_QueryInterface(IMFClockStateSink *iface,
2506 REFIID riid, void **out)
2508 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2509 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2512 static ULONG WINAPI video_mixer_clock_state_sink_AddRef(IMFClockStateSink *iface)
2514 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2515 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2518 static ULONG WINAPI video_mixer_clock_state_sink_Release(IMFClockStateSink *iface)
2520 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2521 return IMFTransform_Release(&mixer->IMFTransform_iface);
2524 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStart(IMFClockStateSink *iface,
2525 MFTIME systime, LONGLONG offset)
2527 FIXME("%p.\n", iface);
2529 return E_NOTIMPL;
2532 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStop(IMFClockStateSink *iface,
2533 MFTIME systime)
2535 FIXME("%p.\n", iface);
2537 return E_NOTIMPL;
2540 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockPause(IMFClockStateSink *iface,
2541 MFTIME systime)
2543 FIXME("%p.\n", iface);
2545 return E_NOTIMPL;
2548 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockRestart(IMFClockStateSink *iface,
2549 MFTIME systime)
2551 FIXME("%p.\n", iface);
2553 return E_NOTIMPL;
2556 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockSetRate(IMFClockStateSink *iface,
2557 MFTIME systime, float rate)
2559 FIXME("%p, %f.\n", iface, rate);
2561 return E_NOTIMPL;
2564 static const IMFClockStateSinkVtbl video_mixer_clock_state_sink_vtbl =
2566 video_mixer_clock_state_sink_QueryInterface,
2567 video_mixer_clock_state_sink_AddRef,
2568 video_mixer_clock_state_sink_Release,
2569 video_mixer_clock_state_sink_OnClockStart,
2570 video_mixer_clock_state_sink_OnClockStop,
2571 video_mixer_clock_state_sink_OnClockPause,
2572 video_mixer_clock_state_sink_OnClockRestart,
2573 video_mixer_clock_state_sink_OnClockSetRate,
2576 HRESULT WINAPI MFCreateVideoMixer(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
2578 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
2580 *obj = NULL;
2582 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
2583 return E_INVALIDARG;
2585 return CoCreateInstance(&CLSID_MFVideoMixer9, owner, CLSCTX_INPROC_SERVER, riid, obj);
2588 HRESULT evr_mixer_create(IUnknown *outer, void **out)
2590 struct video_mixer *object;
2591 MFVideoNormalizedRect rect;
2592 HRESULT hr;
2594 if (!(object = calloc(1, sizeof(*object))))
2595 return E_OUTOFMEMORY;
2597 object->IMFTransform_iface.lpVtbl = &video_mixer_transform_vtbl;
2598 object->IMFVideoDeviceID_iface.lpVtbl = &video_mixer_device_id_vtbl;
2599 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_mixer_service_client_vtbl;
2600 object->IMFVideoMixerControl2_iface.lpVtbl = &video_mixer_control_vtbl;
2601 object->IMFGetService_iface.lpVtbl = &video_mixer_getservice_vtbl;
2602 object->IMFVideoMixerBitmap_iface.lpVtbl = &video_mixer_bitmap_vtbl;
2603 object->IMFVideoPositionMapper_iface.lpVtbl = &video_mixer_position_mapper_vtbl;
2604 object->IMFVideoProcessor_iface.lpVtbl = &video_mixer_processor_vtbl;
2605 object->IMFAttributes_iface.lpVtbl = &video_mixer_attributes_vtbl;
2606 object->IMFQualityAdvise_iface.lpVtbl = &video_mixer_quality_advise_vtbl;
2607 object->IMFClockStateSink_iface.lpVtbl = &video_mixer_clock_state_sink_vtbl;
2608 object->IUnknown_inner.lpVtbl = &video_mixer_inner_vtbl;
2609 object->outer_unk = outer ? outer : &object->IUnknown_inner;
2610 object->refcount = 1;
2611 object->input_count = 1;
2612 object->lower_bound = MFT_OUTPUT_BOUND_LOWER_UNBOUNDED;
2613 object->upper_bound = MFT_OUTPUT_BOUND_UPPER_UNBOUNDED;
2614 video_mixer_init_input(&object->inputs[0]);
2615 video_mixer_update_zorder_map(object);
2616 video_mixer_rgb_to_ycbcr(object->bkgnd_color.rgba, &object->bkgnd_color.ayuv);
2617 InitializeCriticalSection(&object->cs);
2618 if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
2620 IUnknown_Release(&object->IUnknown_inner);
2621 return hr;
2623 if (FAILED(hr = MFCreateAttributes(&object->internal_attributes, 0)))
2625 IUnknown_Release(&object->IUnknown_inner);
2626 return hr;
2629 /* Default attributes configuration. */
2631 rect.left = rect.top = 0.0f;
2632 rect.right = rect.bottom = 1.0f;
2633 IMFAttributes_SetBlob(object->attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&rect, sizeof(rect));
2635 IMFAttributes_SetUINT32(object->internal_attributes, &MF_SA_D3D_AWARE, 1);
2637 *out = &object->IUnknown_inner;
2639 return S_OK;