msdasql: Support IRowsetInfo in IRowset interface.
[wine.git] / dlls / evr / mixer.c
blob30b4ed31b3f804968dd3b19208c2756939833817
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_STREAMS 16
40 struct input_stream
42 unsigned int id;
43 IMFAttributes *attributes;
44 IMFMediaType *media_type;
45 MFVideoNormalizedRect rect;
46 unsigned int zorder;
47 IMFSample *sample;
48 unsigned int sample_requested : 1;
51 struct rt_format
53 GUID device;
54 D3DFORMAT format;
55 IMFMediaType *media_type;
58 struct output_stream
60 IMFMediaType *media_type;
61 struct rt_format *rt_formats;
62 unsigned int rt_formats_count;
65 struct video_mixer
67 IMFTransform IMFTransform_iface;
68 IMFVideoDeviceID IMFVideoDeviceID_iface;
69 IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
70 IMFVideoMixerControl2 IMFVideoMixerControl2_iface;
71 IMFGetService IMFGetService_iface;
72 IMFVideoMixerBitmap IMFVideoMixerBitmap_iface;
73 IMFVideoPositionMapper IMFVideoPositionMapper_iface;
74 IMFVideoProcessor IMFVideoProcessor_iface;
75 IMFAttributes IMFAttributes_iface;
76 IMFQualityAdvise IMFQualityAdvise_iface;
77 IMFClockStateSink IMFClockStateSink_iface;
78 IUnknown IUnknown_inner;
79 IUnknown *outer_unk;
80 LONG refcount;
82 struct input_stream inputs[MAX_MIXER_INPUT_STREAMS];
83 unsigned int input_ids[MAX_MIXER_INPUT_STREAMS];
84 struct input_stream *zorder[MAX_MIXER_INPUT_STREAMS];
85 unsigned int input_count;
86 struct output_stream output;
88 IDirect3DDeviceManager9 *device_manager;
89 IDirectXVideoProcessor *processor;
90 HANDLE device_handle;
92 IMediaEventSink *event_sink;
93 IMFAttributes *attributes;
94 IMFAttributes *internal_attributes;
95 unsigned int mixing_flags;
96 unsigned int is_streaming;
97 COLORREF bkgnd_color;
98 LONGLONG lower_bound;
99 LONGLONG upper_bound;
100 CRITICAL_SECTION cs;
103 static struct video_mixer *impl_from_IUnknown(IUnknown *iface)
105 return CONTAINING_RECORD(iface, struct video_mixer, IUnknown_inner);
108 static struct video_mixer *impl_from_IMFTransform(IMFTransform *iface)
110 return CONTAINING_RECORD(iface, struct video_mixer, IMFTransform_iface);
113 static struct video_mixer *impl_from_IMFVideoDeviceID(IMFVideoDeviceID *iface)
115 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoDeviceID_iface);
118 static struct video_mixer *impl_from_IMFTopologyServiceLookupClient(IMFTopologyServiceLookupClient *iface)
120 return CONTAINING_RECORD(iface, struct video_mixer, IMFTopologyServiceLookupClient_iface);
123 static struct video_mixer *impl_from_IMFVideoMixerControl2(IMFVideoMixerControl2 *iface)
125 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoMixerControl2_iface);
128 static struct video_mixer *impl_from_IMFGetService(IMFGetService *iface)
130 return CONTAINING_RECORD(iface, struct video_mixer, IMFGetService_iface);
133 static struct video_mixer *impl_from_IMFVideoMixerBitmap(IMFVideoMixerBitmap *iface)
135 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoMixerBitmap_iface);
138 static struct video_mixer *impl_from_IMFVideoPositionMapper(IMFVideoPositionMapper *iface)
140 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoPositionMapper_iface);
143 static struct video_mixer *impl_from_IMFVideoProcessor(IMFVideoProcessor *iface)
145 return CONTAINING_RECORD(iface, struct video_mixer, IMFVideoProcessor_iface);
148 static struct video_mixer *impl_from_IMFAttributes(IMFAttributes *iface)
150 return CONTAINING_RECORD(iface, struct video_mixer, IMFAttributes_iface);
153 static struct video_mixer *impl_from_IMFQualityAdvise(IMFQualityAdvise *iface)
155 return CONTAINING_RECORD(iface, struct video_mixer, IMFQualityAdvise_iface);
158 static struct video_mixer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
160 return CONTAINING_RECORD(iface, struct video_mixer, IMFClockStateSink_iface);
163 static int __cdecl video_mixer_compare_input_id(const void *a, const void *b)
165 const unsigned int *key = a;
166 const struct input_stream *input = b;
168 if (*key > input->id) return 1;
169 if (*key < input->id) return -1;
170 return 0;
173 static HRESULT video_mixer_get_input(const struct video_mixer *mixer, unsigned int id, struct input_stream **stream)
175 *stream = bsearch(&id, mixer->inputs, mixer->input_count, sizeof(*mixer->inputs), video_mixer_compare_input_id);
176 return *stream ? S_OK : MF_E_INVALIDSTREAMNUMBER;
179 static void video_mixer_init_input(struct input_stream *stream)
181 if (SUCCEEDED(MFCreateAttributes(&stream->attributes, 1)))
182 IMFAttributes_SetUINT32(stream->attributes, &MF_SA_REQUIRED_SAMPLE_COUNT, 1);
183 stream->rect.left = stream->rect.top = 0.0f;
184 stream->rect.right = stream->rect.bottom = 1.0f;
187 static int __cdecl video_mixer_zorder_sort_compare(const void *a, const void *b)
189 const struct input_stream *left = *(void **)a, *right = *(void **)b;
190 return left->zorder != right->zorder ? (left->zorder < right->zorder ? -1 : 1) : 0;
193 static void video_mixer_update_zorder_map(struct video_mixer *mixer)
195 unsigned int i;
197 for (i = 0; i < mixer->input_count; ++i)
198 mixer->zorder[i] = &mixer->inputs[i];
200 qsort(mixer->zorder, mixer->input_count, sizeof(*mixer->zorder), video_mixer_zorder_sort_compare);
203 static void video_mixer_clear_types(struct video_mixer *mixer)
205 unsigned int i;
207 for (i = 0; i < mixer->input_count; ++i)
209 if (mixer->inputs[i].media_type)
210 IMFMediaType_Release(mixer->inputs[i].media_type);
211 mixer->inputs[i].media_type = NULL;
212 if (mixer->inputs[i].sample)
213 IMFSample_Release(mixer->inputs[i].sample);
214 mixer->inputs[i].sample = NULL;
216 for (i = 0; i < mixer->output.rt_formats_count; ++i)
218 IMFMediaType_Release(mixer->output.rt_formats[i].media_type);
220 free(mixer->output.rt_formats);
221 if (mixer->output.media_type)
222 IMFMediaType_Release(mixer->output.media_type);
223 mixer->output.media_type = NULL;
226 static HRESULT WINAPI video_mixer_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
228 struct video_mixer *mixer = impl_from_IUnknown(iface);
230 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
232 if (IsEqualIID(riid, &IID_IUnknown))
234 *obj = iface;
236 else if (IsEqualIID(riid, &IID_IMFTransform))
238 *obj = &mixer->IMFTransform_iface;
240 else if (IsEqualIID(riid, &IID_IMFVideoDeviceID))
242 *obj = &mixer->IMFVideoDeviceID_iface;
244 else if (IsEqualIID(riid, &IID_IMFTopologyServiceLookupClient))
246 *obj = &mixer->IMFTopologyServiceLookupClient_iface;
248 else if (IsEqualIID(riid, &IID_IMFVideoMixerControl2) ||
249 IsEqualIID(riid, &IID_IMFVideoMixerControl))
251 *obj = &mixer->IMFVideoMixerControl2_iface;
253 else if (IsEqualIID(riid, &IID_IMFGetService))
255 *obj = &mixer->IMFGetService_iface;
257 else if (IsEqualIID(riid, &IID_IMFVideoMixerBitmap))
259 *obj = &mixer->IMFVideoMixerBitmap_iface;
261 else if (IsEqualIID(riid, &IID_IMFVideoPositionMapper))
263 *obj = &mixer->IMFVideoPositionMapper_iface;
265 else if (IsEqualIID(riid, &IID_IMFVideoProcessor))
267 *obj = &mixer->IMFVideoProcessor_iface;
269 else if (IsEqualIID(riid, &IID_IMFAttributes))
271 *obj = &mixer->IMFAttributes_iface;
273 else if (IsEqualIID(riid, &IID_IMFQualityAdvise))
275 *obj = &mixer->IMFQualityAdvise_iface;
277 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
279 *obj = &mixer->IMFClockStateSink_iface;
281 else
283 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
284 *obj = NULL;
285 return E_NOINTERFACE;
288 IUnknown_AddRef((IUnknown *)*obj);
289 return S_OK;
292 static ULONG WINAPI video_mixer_inner_AddRef(IUnknown *iface)
294 struct video_mixer *mixer = impl_from_IUnknown(iface);
295 ULONG refcount = InterlockedIncrement(&mixer->refcount);
297 TRACE("%p, refcount %u.\n", iface, refcount);
299 return refcount;
302 static void video_mixer_release_device_manager(struct video_mixer *mixer)
304 if (mixer->processor)
305 IDirectXVideoProcessor_Release(mixer->processor);
306 if (mixer->device_manager)
308 IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, mixer->device_handle);
309 IDirect3DDeviceManager9_Release(mixer->device_manager);
311 mixer->device_handle = NULL;
312 mixer->device_manager = NULL;
313 mixer->processor = NULL;
316 static ULONG WINAPI video_mixer_inner_Release(IUnknown *iface)
318 struct video_mixer *mixer = impl_from_IUnknown(iface);
319 ULONG refcount = InterlockedDecrement(&mixer->refcount);
320 unsigned int i;
322 TRACE("%p, refcount %u.\n", iface, refcount);
324 if (!refcount)
326 for (i = 0; i < mixer->input_count; ++i)
328 if (mixer->inputs[i].attributes)
329 IMFAttributes_Release(mixer->inputs[i].attributes);
331 video_mixer_clear_types(mixer);
332 video_mixer_release_device_manager(mixer);
333 if (mixer->attributes)
334 IMFAttributes_Release(mixer->attributes);
335 if (mixer->internal_attributes)
336 IMFAttributes_Release(mixer->internal_attributes);
337 DeleteCriticalSection(&mixer->cs);
338 free(mixer);
341 return refcount;
344 static const IUnknownVtbl video_mixer_inner_vtbl =
346 video_mixer_inner_QueryInterface,
347 video_mixer_inner_AddRef,
348 video_mixer_inner_Release,
351 static HRESULT WINAPI video_mixer_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
353 struct video_mixer *mixer = impl_from_IMFTransform(iface);
354 return IUnknown_QueryInterface(mixer->outer_unk, riid, obj);
357 static ULONG WINAPI video_mixer_transform_AddRef(IMFTransform *iface)
359 struct video_mixer *mixer = impl_from_IMFTransform(iface);
360 return IUnknown_AddRef(mixer->outer_unk);
363 static ULONG WINAPI video_mixer_transform_Release(IMFTransform *iface)
365 struct video_mixer *mixer = impl_from_IMFTransform(iface);
366 return IUnknown_Release(mixer->outer_unk);
369 static HRESULT WINAPI video_mixer_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
370 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
372 TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
374 *input_minimum = 1;
375 *input_maximum = MAX_MIXER_INPUT_STREAMS;
376 *output_minimum = 1;
377 *output_maximum = 1;
379 return S_OK;
382 static HRESULT WINAPI video_mixer_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
384 struct video_mixer *mixer = impl_from_IMFTransform(iface);
386 TRACE("%p, %p, %p.\n", iface, inputs, outputs);
388 EnterCriticalSection(&mixer->cs);
389 if (inputs) *inputs = mixer->input_count;
390 if (outputs) *outputs = 1;
391 LeaveCriticalSection(&mixer->cs);
393 return S_OK;
396 static HRESULT WINAPI video_mixer_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
397 DWORD output_size, DWORD *outputs)
399 struct video_mixer *mixer = impl_from_IMFTransform(iface);
400 HRESULT hr = S_OK;
402 TRACE("%p, %u, %p, %u, %p.\n", iface, input_size, inputs, output_size, outputs);
404 EnterCriticalSection(&mixer->cs);
405 if (mixer->input_count > input_size || !output_size)
406 hr = MF_E_BUFFERTOOSMALL;
407 else if (inputs)
408 memcpy(inputs, mixer->input_ids, mixer->input_count * sizeof(*inputs));
409 if (outputs) *outputs = 0;
410 LeaveCriticalSection(&mixer->cs);
412 return hr;
415 static HRESULT WINAPI video_mixer_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
417 struct video_mixer *mixer = impl_from_IMFTransform(iface);
418 struct input_stream *input;
419 HRESULT hr;
421 TRACE("%p, %u, %p.\n", iface, id, info);
423 EnterCriticalSection(&mixer->cs);
425 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
427 memset(info, 0, sizeof(*info));
428 if (id)
429 info->dwFlags |= MFT_INPUT_STREAM_REMOVABLE | MFT_INPUT_STREAM_OPTIONAL;
432 LeaveCriticalSection(&mixer->cs);
434 return hr;
437 static HRESULT WINAPI video_mixer_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
439 TRACE("%p, %u, %p.\n", iface, id, info);
441 if (id)
442 return MF_E_INVALIDSTREAMNUMBER;
444 memset(info, 0, sizeof(*info));
446 return S_OK;
449 static HRESULT WINAPI video_mixer_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
451 struct video_mixer *mixer = impl_from_IMFTransform(iface);
453 TRACE("%p, %p.\n", iface, attributes);
455 if (!attributes)
456 return E_POINTER;
458 *attributes = mixer->attributes;
459 IMFAttributes_AddRef(*attributes);
461 return S_OK;
464 static HRESULT WINAPI video_mixer_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
465 IMFAttributes **attributes)
467 struct video_mixer *mixer = impl_from_IMFTransform(iface);
468 struct input_stream *input;
469 HRESULT hr;
471 TRACE("%p, %u, %p.\n", iface, id, attributes);
473 EnterCriticalSection(&mixer->cs);
475 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
477 *attributes = input->attributes;
478 if (*attributes)
479 IMFAttributes_AddRef(*attributes);
482 LeaveCriticalSection(&mixer->cs);
484 return hr;
487 static HRESULT WINAPI video_mixer_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
488 IMFAttributes **attributes)
490 TRACE("%p, %u, %p.\n", iface, id, attributes);
492 return E_NOTIMPL;
495 static HRESULT WINAPI video_mixer_transform_DeleteInputStream(IMFTransform *iface, DWORD id)
497 struct video_mixer *mixer = impl_from_IMFTransform(iface);
498 struct input_stream *input;
499 unsigned int idx;
500 HRESULT hr;
502 TRACE("%p, %u.\n", iface, id);
504 if (!id)
505 return MF_E_INVALIDSTREAMNUMBER;
507 EnterCriticalSection(&mixer->cs);
509 /* Can't delete reference stream. */
510 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
512 mixer->input_count--;
513 idx = input - mixer->inputs;
514 if (idx < mixer->input_count)
516 if (mixer->inputs[idx].attributes)
517 IMFAttributes_Release(mixer->inputs[idx].attributes);
518 memmove(&mixer->inputs[idx], &mixer->inputs[idx + 1], (mixer->input_count - idx) * sizeof(*mixer->inputs));
519 memmove(&mixer->input_ids[idx], &mixer->input_ids[idx + 1], (mixer->input_count - idx) *
520 sizeof(*mixer->input_ids));
521 video_mixer_update_zorder_map(mixer);
525 LeaveCriticalSection(&mixer->cs);
527 return hr;
530 static int __cdecl video_mixer_add_input_sort_compare(const void *a, const void *b)
532 const struct input_stream *left = a, *right = b;
533 return left->id != right->id ? (left->id < right->id ? -1 : 1) : 0;
536 static HRESULT WINAPI video_mixer_transform_AddInputStreams(IMFTransform *iface, DWORD count, DWORD *ids)
538 struct video_mixer *mixer = impl_from_IMFTransform(iface);
539 struct input_stream inputs[MAX_MIXER_INPUT_STREAMS] = { {0} };
540 struct input_stream *input;
541 unsigned int i, len;
542 HRESULT hr = S_OK;
544 TRACE("%p, %u, %p.\n", iface, count, ids);
546 if (!ids)
547 return E_POINTER;
549 EnterCriticalSection(&mixer->cs);
550 if (count > ARRAY_SIZE(mixer->inputs) - mixer->input_count)
551 hr = E_INVALIDARG;
552 else
554 /* Test for collisions. */
555 memcpy(inputs, mixer->inputs, mixer->input_count * sizeof(*inputs));
556 for (i = 0; i < count; ++i)
557 inputs[i + mixer->input_count].id = ids[i];
559 len = mixer->input_count + count;
561 qsort(inputs, len, sizeof(*inputs), video_mixer_add_input_sort_compare);
563 for (i = 1; i < len; ++i)
565 if (inputs[i - 1].id == inputs[i].id)
567 hr = E_INVALIDARG;
568 break;
572 if (SUCCEEDED(hr))
574 unsigned int zorder = mixer->input_count;
576 for (i = 0; i < count; ++i)
578 if ((input = bsearch(&ids[i], inputs, len, sizeof(*inputs), video_mixer_compare_input_id)))
579 video_mixer_init_input(input);
581 memcpy(&mixer->input_ids[mixer->input_count], ids, count * sizeof(*ids));
582 memcpy(mixer->inputs, inputs, len * sizeof(*inputs));
583 mixer->input_count += count;
585 for (i = 0; i < count; ++i)
587 if (SUCCEEDED(video_mixer_get_input(mixer, ids[i], &input)))
588 input->zorder = zorder;
589 zorder++;
592 video_mixer_update_zorder_map(mixer);
595 LeaveCriticalSection(&mixer->cs);
597 return hr;
600 static HRESULT WINAPI video_mixer_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
601 IMFMediaType **type)
603 TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
605 return E_NOTIMPL;
608 static HRESULT WINAPI video_mixer_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
609 IMFMediaType **type)
611 struct video_mixer *mixer = impl_from_IMFTransform(iface);
612 HRESULT hr = S_OK;
614 TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
616 if (id)
617 return MF_E_INVALIDSTREAMNUMBER;
619 EnterCriticalSection(&mixer->cs);
621 if (!mixer->inputs[0].media_type)
622 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
623 else if (index >= mixer->output.rt_formats_count)
624 hr = MF_E_NO_MORE_TYPES;
625 else
627 if (SUCCEEDED(hr = MFCreateMediaType(type)))
628 hr = IMFMediaType_CopyAllItems(mixer->output.rt_formats[index].media_type, (IMFAttributes *)*type);
631 LeaveCriticalSection(&mixer->cs);
633 return hr;
636 static HRESULT video_mixer_init_dxva_videodesc(IMFMediaType *media_type, DXVA2_VideoDesc *video_desc)
638 const MFVIDEOFORMAT *video_format;
639 IMFVideoMediaType *video_type;
640 BOOL is_compressed = TRUE;
641 HRESULT hr = S_OK;
643 if (FAILED(IMFMediaType_QueryInterface(media_type, &IID_IMFVideoMediaType, (void **)&video_type)))
644 return MF_E_INVALIDMEDIATYPE;
646 video_format = IMFVideoMediaType_GetVideoFormat(video_type);
647 IMFVideoMediaType_IsCompressedFormat(video_type, &is_compressed);
649 if (!video_format || !video_format->videoInfo.dwWidth || !video_format->videoInfo.dwHeight || is_compressed)
651 hr = MF_E_INVALIDMEDIATYPE;
652 goto done;
655 memset(video_desc, 0, sizeof(*video_desc));
656 video_desc->SampleWidth = video_format->videoInfo.dwWidth;
657 video_desc->SampleHeight = video_format->videoInfo.dwHeight;
658 video_desc->Format = video_format->surfaceInfo.Format;
660 done:
661 IMFVideoMediaType_Release(video_type);
663 return hr;
666 static void video_mixer_append_rt_format(struct rt_format *rt_formats, unsigned int *count,
667 const GUID *device, D3DFORMAT format)
669 unsigned int i;
671 for (i = 0; i < *count; ++i)
673 if (rt_formats[i].format == format) return;
676 rt_formats[*count].format = format;
677 rt_formats[*count].device = *device;
678 *count += 1;
681 static unsigned int video_mixer_get_interlace_mode_from_video_desc(const DXVA2_VideoDesc *video_desc)
683 switch (video_desc->SampleFormat.SampleFormat)
685 case DXVA2_SampleFieldInterleavedEvenFirst:
686 return MFVideoInterlace_FieldInterleavedUpperFirst;
687 case DXVA2_SampleFieldInterleavedOddFirst:
688 return MFVideoInterlace_FieldInterleavedLowerFirst;
689 case DXVA2_SampleFieldSingleEven:
690 return MFVideoInterlace_FieldSingleUpper;
691 case DXVA2_SampleFieldSingleOdd:
692 return MFVideoInterlace_FieldSingleLower;
693 default:
694 return MFVideoInterlace_Progressive;
698 static void mf_get_attribute_uint32(IMFMediaType *media_type, const GUID *key, UINT32 *value,
699 UINT32 default_value)
701 if (FAILED(IMFMediaType_GetUINT32(media_type, key, value)))
702 *value = default_value;
705 static void mf_get_attribute_uint64(IMFMediaType *media_type, const GUID *key, UINT64 *value,
706 UINT64 default_value)
708 if (FAILED(IMFMediaType_GetUINT64(media_type, key, value)))
709 *value = default_value;
712 static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const DXVA2_VideoDesc *video_desc,
713 IMFMediaType *media_type, IDirectXVideoProcessorService *service, unsigned int device_count,
714 const GUID *devices, unsigned int flags)
716 struct rt_format *rt_formats = NULL, *ptr;
717 unsigned int i, j, format_count, count;
718 HRESULT hr = MF_E_INVALIDMEDIATYPE;
719 D3DFORMAT *formats;
720 GUID subtype;
722 count = 0;
723 for (i = 0; i < device_count; ++i)
725 if (SUCCEEDED(IDirectXVideoProcessorService_GetVideoProcessorRenderTargets(service, &devices[i], video_desc,
726 &format_count, &formats)))
728 if (!(ptr = realloc(rt_formats, (count + format_count) * sizeof(*rt_formats))))
730 hr = E_OUTOFMEMORY;
731 count = 0;
732 CoTaskMemFree(formats);
733 break;
735 rt_formats = ptr;
737 for (j = 0; j < format_count; ++j)
738 video_mixer_append_rt_format(rt_formats, &count, &devices[i], formats[j]);
740 CoTaskMemFree(formats);
744 if (count && !(flags & MFT_SET_TYPE_TEST_ONLY))
746 UINT32 fixed_samples, interlace_mode;
747 MFVideoArea aperture;
748 UINT64 par;
750 if (!(mixer->output.rt_formats = calloc(count, sizeof(*mixer->output.rt_formats))))
752 free(rt_formats);
753 return E_OUTOFMEMORY;
756 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
757 memset(&aperture, 0, sizeof(aperture));
758 if (FAILED(IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture,
759 sizeof(aperture), NULL)))
761 aperture.Area.cx = video_desc->SampleWidth;
762 aperture.Area.cy = video_desc->SampleHeight;
764 interlace_mode = video_mixer_get_interlace_mode_from_video_desc(video_desc);
765 mf_get_attribute_uint64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &par, (UINT64)1 << 32 | 1);
766 mf_get_attribute_uint32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, &fixed_samples, 1);
768 for (i = 0; i < count; ++i)
770 IMFMediaType *rt_media_type;
772 subtype.Data1 = rt_formats[i].format;
773 mixer->output.rt_formats[i] = rt_formats[i];
775 MFCreateMediaType(&rt_media_type);
776 IMFMediaType_CopyAllItems(media_type, (IMFAttributes *)rt_media_type);
777 IMFMediaType_SetGUID(rt_media_type, &MF_MT_SUBTYPE, &subtype);
778 IMFMediaType_SetUINT64(rt_media_type, &MF_MT_FRAME_SIZE, (UINT64)aperture.Area.cx << 32 | aperture.Area.cy);
779 IMFMediaType_SetBlob(rt_media_type, &MF_MT_GEOMETRIC_APERTURE, (const UINT8 *)&aperture, sizeof(aperture));
780 IMFMediaType_SetBlob(rt_media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (const UINT8 *)&aperture, sizeof(aperture));
781 IMFMediaType_SetUINT32(rt_media_type, &MF_MT_INTERLACE_MODE, interlace_mode);
782 IMFMediaType_SetUINT64(rt_media_type, &MF_MT_PIXEL_ASPECT_RATIO, par);
783 IMFMediaType_SetUINT32(rt_media_type, &MF_MT_FIXED_SIZE_SAMPLES, fixed_samples);
785 mixer->output.rt_formats[i].media_type = rt_media_type;
787 mixer->output.rt_formats_count = count;
790 free(rt_formats);
792 return count ? S_OK : hr;
795 static HRESULT video_mixer_open_device_handle(struct video_mixer *mixer)
797 IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, mixer->device_handle);
798 mixer->device_handle = NULL;
799 return IDirect3DDeviceManager9_OpenDeviceHandle(mixer->device_manager, &mixer->device_handle);
802 static HRESULT video_mixer_get_processor_service(struct video_mixer *mixer, IDirectXVideoProcessorService **service)
804 HRESULT hr;
806 if (!mixer->device_handle)
808 if (FAILED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(mixer->device_manager, &mixer->device_handle)))
809 return hr;
812 for (;;)
814 hr = IDirect3DDeviceManager9_GetVideoService(mixer->device_manager, mixer->device_handle,
815 &IID_IDirectXVideoProcessorService, (void **)service);
816 if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
818 if (SUCCEEDED(hr = video_mixer_open_device_handle(mixer)))
819 continue;
821 break;
824 return hr;
827 static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *media_type, DWORD flags)
829 struct video_mixer *mixer = impl_from_IMFTransform(iface);
830 IDirectXVideoProcessorService *service;
831 DXVA2_VideoDesc video_desc;
832 HRESULT hr = E_NOTIMPL;
833 unsigned int count;
834 GUID *guids;
836 TRACE("%p, %u, %p, %#x.\n", iface, id, media_type, flags);
838 EnterCriticalSection(&mixer->cs);
840 if (!(flags & MFT_SET_TYPE_TEST_ONLY))
841 video_mixer_clear_types(mixer);
843 if (!mixer->device_manager)
844 hr = MF_E_NOT_INITIALIZED;
845 else
847 if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
849 if (SUCCEEDED(hr = video_mixer_init_dxva_videodesc(media_type, &video_desc)))
851 if (!id)
853 if (SUCCEEDED(hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc,
854 &count, &guids)))
856 if (SUCCEEDED(hr = video_mixer_collect_output_types(mixer, &video_desc, media_type,
857 service, count, guids, flags)) && !(flags & MFT_SET_TYPE_TEST_ONLY))
859 if (mixer->inputs[0].media_type)
860 IMFMediaType_Release(mixer->inputs[0].media_type);
861 mixer->inputs[0].media_type = media_type;
862 IMFMediaType_AddRef(mixer->inputs[0].media_type);
864 CoTaskMemFree(guids);
867 else
869 FIXME("Unimplemented for substreams.\n");
870 hr = E_NOTIMPL;
873 IDirectXVideoProcessorService_Release(service);
877 LeaveCriticalSection(&mixer->cs);
879 return hr;
882 static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
884 const unsigned int equality_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
885 struct video_mixer *mixer = impl_from_IMFTransform(iface);
886 HRESULT hr = MF_E_INVALIDMEDIATYPE;
887 unsigned int i, compare_flags;
888 BOOL is_compressed = TRUE;
890 TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
892 if (id)
893 return MF_E_INVALIDSTREAMNUMBER;
895 if (!type)
896 return E_INVALIDARG;
898 if (FAILED(IMFMediaType_IsCompressedFormat(type, &is_compressed)) || is_compressed)
899 return MF_E_INVALIDMEDIATYPE;
901 EnterCriticalSection(&mixer->cs);
903 for (i = 0; i < mixer->output.rt_formats_count; ++i)
905 compare_flags = 0;
906 if (FAILED(IMFMediaType_IsEqual(type, mixer->output.rt_formats[i].media_type, &compare_flags)))
907 continue;
909 if ((compare_flags & equality_flags) == equality_flags)
911 hr = S_OK;
912 break;
916 if (SUCCEEDED(hr) && !(flags & MFT_SET_TYPE_TEST_ONLY))
918 IDirectXVideoProcessorService *service;
920 if (SUCCEEDED(hr = video_mixer_get_processor_service(mixer, &service)))
922 DXVA2_VideoDesc video_desc;
923 GUID subtype = { 0 };
924 D3DFORMAT rt_format;
926 if (mixer->processor)
927 IDirectXVideoProcessor_Release(mixer->processor);
928 mixer->processor = NULL;
930 video_mixer_init_dxva_videodesc(mixer->inputs[0].media_type, &video_desc);
931 IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype);
932 rt_format = subtype.Data1;
934 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &mixer->output.rt_formats[i].device,
935 &video_desc, rt_format, MAX_MIXER_INPUT_STREAMS, &mixer->processor)))
937 if (mixer->output.media_type)
938 IMFMediaType_Release(mixer->output.media_type);
939 mixer->output.media_type = type;
940 IMFMediaType_AddRef(mixer->output.media_type);
943 IDirectXVideoProcessorService_Release(service);
947 LeaveCriticalSection(&mixer->cs);
949 return hr;
952 static HRESULT WINAPI video_mixer_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
954 struct video_mixer *mixer = impl_from_IMFTransform(iface);
955 struct input_stream *stream;
956 HRESULT hr;
958 TRACE("%p, %u, %p.\n", iface, id, type);
960 EnterCriticalSection(&mixer->cs);
962 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
964 if (!stream->media_type)
965 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
966 else
968 *type = stream->media_type;
969 IMFMediaType_AddRef(*type);
973 LeaveCriticalSection(&mixer->cs);
975 return hr;
978 static HRESULT WINAPI video_mixer_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
980 struct video_mixer *mixer = impl_from_IMFTransform(iface);
981 HRESULT hr = S_OK;
983 TRACE("%p, %u, %p.\n", iface, id, type);
985 if (id)
986 return MF_E_INVALIDSTREAMNUMBER;
988 EnterCriticalSection(&mixer->cs);
990 if (!mixer->output.media_type)
991 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
992 else
994 *type = mixer->output.media_type;
995 IMFMediaType_AddRef(*type);
998 LeaveCriticalSection(&mixer->cs);
1000 return hr;
1003 static HRESULT WINAPI video_mixer_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *status)
1005 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1006 struct input_stream *stream;
1007 HRESULT hr;
1009 TRACE("%p, %u, %p.\n", iface, id, status);
1011 if (!status)
1012 return E_POINTER;
1014 EnterCriticalSection(&mixer->cs);
1016 if (!mixer->output.media_type)
1017 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1018 else if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1020 *status = stream->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA;
1023 LeaveCriticalSection(&mixer->cs);
1025 return hr;
1028 static HRESULT WINAPI video_mixer_transform_GetOutputStatus(IMFTransform *iface, DWORD *status)
1030 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1031 HRESULT hr = S_OK;
1032 unsigned int i;
1034 TRACE("%p, %p.\n", iface, status);
1036 if (!status)
1037 return E_POINTER;
1039 EnterCriticalSection(&mixer->cs);
1041 if (!mixer->output.media_type)
1042 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1043 else
1045 *status = MFT_OUTPUT_STATUS_SAMPLE_READY;
1046 for (i = 0; i < mixer->input_count; ++i)
1048 if (!mixer->inputs[i].sample)
1050 *status = 0;
1051 break;
1056 LeaveCriticalSection(&mixer->cs);
1058 return hr;
1061 static HRESULT WINAPI video_mixer_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
1063 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1065 TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
1067 EnterCriticalSection(&mixer->cs);
1069 mixer->lower_bound = lower;
1070 mixer->upper_bound = upper;
1072 LeaveCriticalSection(&mixer->cs);
1074 return S_OK;
1077 static HRESULT WINAPI video_mixer_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
1079 FIXME("%p, %u, %p.\n", iface, id, event);
1081 return E_NOTIMPL;
1084 static void video_mixer_request_sample(struct video_mixer *mixer, unsigned int idx)
1086 if (!mixer->event_sink || mixer->inputs[idx].sample_requested)
1087 return;
1089 IMediaEventSink_Notify(mixer->event_sink, EC_SAMPLE_NEEDED, idx, 0);
1090 mixer->inputs[idx].sample_requested = 1;
1093 static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
1095 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1096 HRESULT hr = S_OK;
1097 unsigned int i;
1099 TRACE("%p, %#x, %#lx.\n", iface, message, param);
1101 switch (message)
1103 case MFT_MESSAGE_SET_D3D_MANAGER:
1105 EnterCriticalSection(&mixer->cs);
1107 video_mixer_release_device_manager(mixer);
1108 if (param)
1109 hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&mixer->device_manager);
1111 LeaveCriticalSection(&mixer->cs);
1113 break;
1115 case MFT_MESSAGE_COMMAND_FLUSH:
1117 EnterCriticalSection(&mixer->cs);
1119 for (i = 0; i < mixer->input_count; ++i)
1121 if (mixer->inputs[i].sample)
1123 IMFSample_Release(mixer->inputs[i].sample);
1124 mixer->inputs[i].sample = NULL;
1125 mixer->inputs[i].sample_requested = 0;
1129 LeaveCriticalSection(&mixer->cs);
1131 break;
1133 case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
1134 case MFT_MESSAGE_NOTIFY_END_STREAMING:
1136 EnterCriticalSection(&mixer->cs);
1138 if (!mixer->is_streaming)
1140 for (i = 0; i < mixer->input_count; ++i)
1141 video_mixer_request_sample(mixer, i);
1144 mixer->is_streaming = message == MFT_MESSAGE_NOTIFY_BEGIN_STREAMING;
1146 LeaveCriticalSection(&mixer->cs);
1148 break;
1150 case MFT_MESSAGE_COMMAND_DRAIN:
1151 break;
1153 default:
1154 WARN("Message not handled %d.\n", message);
1155 hr = E_NOTIMPL;
1158 return hr;
1161 static HRESULT WINAPI video_mixer_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
1163 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1164 struct input_stream *input;
1165 HRESULT hr;
1167 TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags);
1169 if (!sample)
1170 return E_POINTER;
1172 EnterCriticalSection(&mixer->cs);
1174 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &input)))
1176 if (!input->media_type || !mixer->output.media_type)
1177 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1178 else if (input->sample)
1179 hr = MF_E_NOTACCEPTING;
1180 else
1182 mixer->is_streaming = 1;
1183 input->sample_requested = 0;
1184 input->sample = sample;
1185 IMFSample_AddRef(input->sample);
1189 LeaveCriticalSection(&mixer->cs);
1191 return hr;
1194 static HRESULT video_mixer_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface)
1196 IMFMediaBuffer *buffer;
1197 IMFGetService *gs;
1198 HRESULT hr;
1200 if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer)))
1201 return hr;
1203 hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&gs);
1204 IMFMediaBuffer_Release(buffer);
1205 if (FAILED(hr))
1206 return hr;
1208 hr = IMFGetService_GetService(gs, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)surface);
1209 IMFGetService_Release(gs);
1210 return hr;
1213 static HRESULT video_mixer_get_d3d_device(struct video_mixer *mixer, IDirect3DDevice9 **device)
1215 HRESULT hr;
1217 for (;;)
1219 hr = IDirect3DDeviceManager9_LockDevice(mixer->device_manager, mixer->device_handle,
1220 device, TRUE);
1221 if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
1223 if (SUCCEEDED(hr = video_mixer_open_device_handle(mixer)))
1224 continue;
1226 break;
1229 return hr;
1232 static void video_mixer_scale_rect(RECT *rect, unsigned int width, unsigned int height,
1233 const MFVideoNormalizedRect *scale)
1235 if (rect->left == 0.0f && rect->top == 0.0f && rect->right == 1.0f && rect->bottom == 1.0f)
1237 SetRect(rect, 0, 0, width, height);
1239 else
1241 rect->left = width * scale->left;
1242 rect->right = width * scale->right;
1243 rect->top = height * scale->top;
1244 rect->bottom = height * scale->bottom;
1248 static void video_mixer_normalize_rect(const RECT *full, const RECT *part, MFVideoNormalizedRect *ret)
1250 float width = full->right - full->left;
1251 float height = full->bottom - full->top;
1253 ret->left = (part->left - full->left) / width;
1254 ret->right = (part->right - full->left) / width;
1255 ret->bottom = (part->bottom - full->top) / height;
1256 ret->top = (part->top - full->top) / height;
1259 static void video_mixer_render(struct video_mixer *mixer, IDirect3DSurface9 *rt)
1261 DXVA2_VideoSample samples[MAX_MIXER_INPUT_STREAMS] = {{ 0 }};
1262 DXVA2_VideoProcessBltParams params = { 0 };
1263 MFVideoNormalizedRect zoom_rect, norm;
1264 unsigned int i, sample_count = 0;
1265 D3DSURFACE_DESC desc, rt_desc;
1266 struct input_stream *stream;
1267 HRESULT hr = S_OK;
1268 RECT dst;
1270 IDirect3DSurface9_GetDesc(rt, &rt_desc);
1272 if (FAILED(IMFAttributes_GetBlob(mixer->attributes, &VIDEO_ZOOM_RECT, (UINT8 *)&zoom_rect,
1273 sizeof(zoom_rect), NULL)))
1275 zoom_rect.left = zoom_rect.top = 0.0f;
1276 zoom_rect.right = zoom_rect.bottom = 1.0f;
1279 SetRect(&params.TargetRect, 0, 0, rt_desc.Width, rt_desc.Height);
1280 video_mixer_scale_rect(&dst, rt_desc.Width, rt_desc.Height, &zoom_rect);
1282 for (i = 0; i < mixer->input_count; ++i)
1284 RECT stream_dst, stream_vis;
1286 IDirect3DSurface9 *surface;
1288 stream = mixer->zorder[i];
1290 if (FAILED(hr = video_mixer_get_sample_surface(stream->sample, &surface)))
1292 WARN("Failed to get source surface for stream %u, hr %#x.\n", i, hr);
1293 break;
1296 IDirect3DSurface9_GetDesc(surface, &desc);
1298 /* In order to compute source/destination rectangles for each stream:
1300 * per-stream rectangle is used to get destination rectangle in target coordinates;
1301 * destination per-stream rectangle is clipped with zoom rectangle, applied to target coordinates;
1302 * visible rectangle is scaled back to get source area of the stream that would be visible;
1303 * visible rectangle is scaled back to get destination area in target coordinates for given steam.
1307 video_mixer_scale_rect(&stream_dst, rt_desc.Width, rt_desc.Height, &stream->rect);
1309 /* Part of the stream that's visible after zooming. */
1310 if (!IntersectRect(&stream_vis, &stream_dst, &dst))
1312 IDirect3DSurface9_Release(surface);
1313 continue;
1316 samples[sample_count].SampleFormat.SampleFormat = stream->id == 0 ?
1317 DXVA2_SampleProgressiveFrame : DXVA2_SampleSubStream;
1318 samples[sample_count].SrcSurface = surface;
1320 video_mixer_normalize_rect(&stream_dst, &stream_vis, &norm);
1321 video_mixer_scale_rect(&samples[sample_count].SrcRect, desc.Width, desc.Height, &norm);
1323 video_mixer_normalize_rect(&dst, &stream_vis, &norm);
1324 video_mixer_scale_rect(&samples[sample_count].DstRect, rt_desc.Width, rt_desc.Height, &norm);
1326 sample_count++;
1329 if (SUCCEEDED(hr))
1331 if (FAILED(hr = IDirectXVideoProcessor_VideoProcessBlt(mixer->processor, rt, &params, samples,
1332 sample_count, NULL)))
1334 WARN("Failed to process samples, hr %#x.\n", hr);
1338 for (i = 0; i < sample_count; ++i)
1340 if (samples[i].SrcSurface)
1341 IDirect3DSurface9_Release(samples[i].SrcSurface);
1345 static HRESULT video_mixer_get_sample_desired_time(IMFSample *sample, LONGLONG *timestamp, LONGLONG *duration)
1347 IMFDesiredSample *desired;
1348 HRESULT hr;
1350 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFDesiredSample, (void **)&desired)))
1352 hr = IMFDesiredSample_GetDesiredSampleTimeAndDuration(desired, timestamp, duration);
1353 IMFDesiredSample_Release(desired);
1356 return hr;
1359 static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
1360 MFT_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
1362 struct video_mixer *mixer = impl_from_IMFTransform(iface);
1363 LONGLONG timestamp, duration;
1364 IDirect3DSurface9 *surface;
1365 IDirect3DDevice9 *device;
1366 unsigned int i;
1367 HRESULT hr;
1369 TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, buffers, status);
1371 if (!buffers || !count || count > 1 || !buffers->pSample)
1372 return E_INVALIDARG;
1374 if (buffers->dwStreamID)
1375 return MF_E_INVALIDSTREAMNUMBER;
1377 *status = 0;
1379 EnterCriticalSection(&mixer->cs);
1381 if (SUCCEEDED(hr = video_mixer_get_sample_surface(buffers->pSample, &surface)))
1383 if (mixer->is_streaming)
1385 for (i = 0; i < mixer->input_count; ++i)
1387 if (!mixer->inputs[i].sample)
1389 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1390 break;
1394 if (SUCCEEDED(hr))
1396 video_mixer_render(mixer, surface);
1398 timestamp = duration = 0;
1399 if (SUCCEEDED(IMFSample_GetSampleTime(mixer->inputs[0].sample, &timestamp)))
1401 IMFSample_SetSampleTime(buffers->pSample, timestamp);
1403 IMFSample_GetSampleDuration(mixer->inputs[0].sample, &duration);
1404 IMFSample_SetSampleDuration(buffers->pSample, duration);
1408 if (SUCCEEDED(hr))
1410 for (i = 0; i < mixer->input_count; ++i)
1412 if (mixer->inputs[i].sample)
1413 IMFSample_Release(mixer->inputs[i].sample);
1414 mixer->inputs[i].sample = NULL;
1415 video_mixer_request_sample(mixer, i);
1419 else
1421 if (SUCCEEDED(video_mixer_get_sample_desired_time(buffers->pSample, &timestamp, &duration)))
1423 if (SUCCEEDED(hr = video_mixer_get_d3d_device(mixer, &device)))
1425 IDirect3DDevice9_ColorFill(device, surface, NULL, 0);
1426 IDirect3DDeviceManager9_UnlockDevice(mixer->device_manager, mixer->device_handle, FALSE);
1427 IDirect3DDevice9_Release(device);
1430 else
1431 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1433 IDirect3DSurface9_Release(surface);
1436 LeaveCriticalSection(&mixer->cs);
1438 return hr;
1441 static const IMFTransformVtbl video_mixer_transform_vtbl =
1443 video_mixer_transform_QueryInterface,
1444 video_mixer_transform_AddRef,
1445 video_mixer_transform_Release,
1446 video_mixer_transform_GetStreamLimits,
1447 video_mixer_transform_GetStreamCount,
1448 video_mixer_transform_GetStreamIDs,
1449 video_mixer_transform_GetInputStreamInfo,
1450 video_mixer_transform_GetOutputStreamInfo,
1451 video_mixer_transform_GetAttributes,
1452 video_mixer_transform_GetInputStreamAttributes,
1453 video_mixer_transform_GetOutputStreamAttributes,
1454 video_mixer_transform_DeleteInputStream,
1455 video_mixer_transform_AddInputStreams,
1456 video_mixer_transform_GetInputAvailableType,
1457 video_mixer_transform_GetOutputAvailableType,
1458 video_mixer_transform_SetInputType,
1459 video_mixer_transform_SetOutputType,
1460 video_mixer_transform_GetInputCurrentType,
1461 video_mixer_transform_GetOutputCurrentType,
1462 video_mixer_transform_GetInputStatus,
1463 video_mixer_transform_GetOutputStatus,
1464 video_mixer_transform_SetOutputBounds,
1465 video_mixer_transform_ProcessEvent,
1466 video_mixer_transform_ProcessMessage,
1467 video_mixer_transform_ProcessInput,
1468 video_mixer_transform_ProcessOutput,
1471 static HRESULT WINAPI video_mixer_device_id_QueryInterface(IMFVideoDeviceID *iface, REFIID riid, void **obj)
1473 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1474 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1477 static ULONG WINAPI video_mixer_device_id_AddRef(IMFVideoDeviceID *iface)
1479 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1480 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1483 static ULONG WINAPI video_mixer_device_id_Release(IMFVideoDeviceID *iface)
1485 struct video_mixer *mixer = impl_from_IMFVideoDeviceID(iface);
1486 return IMFTransform_Release(&mixer->IMFTransform_iface);
1489 static HRESULT WINAPI video_mixer_device_id_GetDeviceID(IMFVideoDeviceID *iface, IID *device_id)
1491 TRACE("%p, %p.\n", iface, device_id);
1493 if (!device_id)
1494 return E_POINTER;
1496 memcpy(device_id, &IID_IDirect3DDevice9, sizeof(*device_id));
1498 return S_OK;
1501 static const IMFVideoDeviceIDVtbl video_mixer_device_id_vtbl =
1503 video_mixer_device_id_QueryInterface,
1504 video_mixer_device_id_AddRef,
1505 video_mixer_device_id_Release,
1506 video_mixer_device_id_GetDeviceID,
1509 static HRESULT WINAPI video_mixer_service_client_QueryInterface(IMFTopologyServiceLookupClient *iface,
1510 REFIID riid, void **obj)
1512 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1513 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1516 static ULONG WINAPI video_mixer_service_client_AddRef(IMFTopologyServiceLookupClient *iface)
1518 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1519 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1522 static ULONG WINAPI video_mixer_service_client_Release(IMFTopologyServiceLookupClient *iface)
1524 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1525 return IMFTransform_Release(&mixer->IMFTransform_iface);
1528 static HRESULT WINAPI video_mixer_service_client_InitServicePointers(IMFTopologyServiceLookupClient *iface,
1529 IMFTopologyServiceLookup *service_lookup)
1531 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1532 unsigned int count;
1533 HRESULT hr;
1535 TRACE("%p, %p.\n", iface, service_lookup);
1537 if (!service_lookup)
1538 return E_POINTER;
1540 EnterCriticalSection(&mixer->cs);
1542 count = 1;
1543 if (FAILED(hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0,
1544 &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&mixer->event_sink, &count)))
1546 WARN("Failed to get renderer event sink, hr %#x.\n", hr);
1549 LeaveCriticalSection(&mixer->cs);
1551 return hr;
1554 static HRESULT WINAPI video_mixer_service_client_ReleaseServicePointers(IMFTopologyServiceLookupClient *iface)
1556 struct video_mixer *mixer = impl_from_IMFTopologyServiceLookupClient(iface);
1558 TRACE("%p.\n", iface);
1560 EnterCriticalSection(&mixer->cs);
1562 if (mixer->event_sink)
1563 IMediaEventSink_Release(mixer->event_sink);
1564 mixer->event_sink = NULL;
1566 LeaveCriticalSection(&mixer->cs);
1568 return S_OK;
1571 static const IMFTopologyServiceLookupClientVtbl video_mixer_service_client_vtbl =
1573 video_mixer_service_client_QueryInterface,
1574 video_mixer_service_client_AddRef,
1575 video_mixer_service_client_Release,
1576 video_mixer_service_client_InitServicePointers,
1577 video_mixer_service_client_ReleaseServicePointers,
1580 static HRESULT WINAPI video_mixer_control_QueryInterface(IMFVideoMixerControl2 *iface, REFIID riid, void **obj)
1582 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1583 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1586 static ULONG WINAPI video_mixer_control_AddRef(IMFVideoMixerControl2 *iface)
1588 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1589 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1592 static ULONG WINAPI video_mixer_control_Release(IMFVideoMixerControl2 *iface)
1594 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1595 return IMFTransform_Release(&mixer->IMFTransform_iface);
1598 static HRESULT WINAPI video_mixer_control_SetStreamZOrder(IMFVideoMixerControl2 *iface, DWORD id, DWORD zorder)
1600 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1601 struct input_stream *stream;
1602 HRESULT hr;
1604 TRACE("%p, %u, %u.\n", iface, id, zorder);
1606 /* Can't change reference stream. */
1607 if (!id && zorder)
1608 return E_INVALIDARG;
1610 EnterCriticalSection(&mixer->cs);
1612 if (zorder >= mixer->input_count)
1613 hr = E_INVALIDARG;
1614 else if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1616 /* Lowest zorder only applies to reference stream. */
1617 if (id && !zorder)
1618 hr = MF_E_INVALIDREQUEST;
1619 else if (stream->zorder != zorder)
1621 stream->zorder = zorder;
1622 video_mixer_update_zorder_map(mixer);
1626 LeaveCriticalSection(&mixer->cs);
1628 return hr;
1631 static HRESULT WINAPI video_mixer_control_GetStreamZOrder(IMFVideoMixerControl2 *iface, DWORD id, DWORD *zorder)
1633 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1634 struct input_stream *stream;
1635 HRESULT hr;
1637 TRACE("%p, %u, %p.\n", iface, id, zorder);
1639 if (!zorder)
1640 return E_POINTER;
1642 EnterCriticalSection(&mixer->cs);
1644 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1645 *zorder = stream->zorder;
1647 LeaveCriticalSection(&mixer->cs);
1649 return hr;
1652 static HRESULT WINAPI video_mixer_control_SetStreamOutputRect(IMFVideoMixerControl2 *iface, DWORD id,
1653 const MFVideoNormalizedRect *rect)
1655 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1656 struct input_stream *stream;
1657 HRESULT hr;
1659 TRACE("%p, %u, %s.\n", iface, id, debugstr_normalized_rect(rect));
1661 if (!rect)
1662 return E_POINTER;
1664 if (rect->left > rect->right || rect->top > rect->bottom ||
1665 rect->left < 0.0f || rect->top < 0.0f || rect->right > 1.0f || rect->bottom > 1.0f)
1667 return E_INVALIDARG;
1670 EnterCriticalSection(&mixer->cs);
1672 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1673 stream->rect = *rect;
1675 LeaveCriticalSection(&mixer->cs);
1677 return hr;
1680 static HRESULT WINAPI video_mixer_control_GetStreamOutputRect(IMFVideoMixerControl2 *iface, DWORD id,
1681 MFVideoNormalizedRect *rect)
1683 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1684 struct input_stream *stream;
1685 HRESULT hr;
1687 TRACE("%p, %u, %p.\n", iface, id, rect);
1689 if (!rect)
1690 return E_POINTER;
1692 EnterCriticalSection(&mixer->cs);
1694 if (SUCCEEDED(hr = video_mixer_get_input(mixer, id, &stream)))
1695 *rect = stream->rect;
1697 LeaveCriticalSection(&mixer->cs);
1699 return hr;
1702 static HRESULT WINAPI video_mixer_control_SetMixingPrefs(IMFVideoMixerControl2 *iface, DWORD flags)
1704 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1706 TRACE("%p, %#x.\n", iface, flags);
1708 EnterCriticalSection(&mixer->cs);
1709 mixer->mixing_flags = flags;
1710 LeaveCriticalSection(&mixer->cs);
1712 return S_OK;
1715 static HRESULT WINAPI video_mixer_control_GetMixingPrefs(IMFVideoMixerControl2 *iface, DWORD *flags)
1717 struct video_mixer *mixer = impl_from_IMFVideoMixerControl2(iface);
1719 TRACE("%p, %p.\n", iface, flags);
1721 if (!flags)
1722 return E_POINTER;
1724 EnterCriticalSection(&mixer->cs);
1725 *flags = mixer->mixing_flags;
1726 LeaveCriticalSection(&mixer->cs);
1728 return S_OK;
1731 static const IMFVideoMixerControl2Vtbl video_mixer_control_vtbl =
1733 video_mixer_control_QueryInterface,
1734 video_mixer_control_AddRef,
1735 video_mixer_control_Release,
1736 video_mixer_control_SetStreamZOrder,
1737 video_mixer_control_GetStreamZOrder,
1738 video_mixer_control_SetStreamOutputRect,
1739 video_mixer_control_GetStreamOutputRect,
1740 video_mixer_control_SetMixingPrefs,
1741 video_mixer_control_GetMixingPrefs,
1744 static HRESULT WINAPI video_mixer_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1746 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1747 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1750 static ULONG WINAPI video_mixer_getservice_AddRef(IMFGetService *iface)
1752 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1753 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1756 static ULONG WINAPI video_mixer_getservice_Release(IMFGetService *iface)
1758 struct video_mixer *mixer = impl_from_IMFGetService(iface);
1759 return IMFTransform_Release(&mixer->IMFTransform_iface);
1762 static HRESULT WINAPI video_mixer_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1764 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1766 if (IsEqualGUID(service, &MR_VIDEO_MIXER_SERVICE))
1768 if (IsEqualIID(riid, &IID_IMFVideoMixerBitmap) ||
1769 IsEqualIID(riid, &IID_IMFVideoProcessor) ||
1770 IsEqualIID(riid, &IID_IMFVideoPositionMapper) ||
1771 IsEqualIID(riid, &IID_IMFVideoMixerControl) ||
1772 IsEqualIID(riid, &IID_IMFVideoMixerControl2))
1774 return IMFGetService_QueryInterface(iface, riid, obj);
1777 return E_NOINTERFACE;
1780 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1782 return MF_E_UNSUPPORTED_SERVICE;
1785 static const IMFGetServiceVtbl video_mixer_getservice_vtbl =
1787 video_mixer_getservice_QueryInterface,
1788 video_mixer_getservice_AddRef,
1789 video_mixer_getservice_Release,
1790 video_mixer_getservice_GetService,
1793 static HRESULT WINAPI video_mixer_bitmap_QueryInterface(IMFVideoMixerBitmap *iface, REFIID riid, void **obj)
1795 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1796 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1799 static ULONG WINAPI video_mixer_bitmap_AddRef(IMFVideoMixerBitmap *iface)
1801 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1802 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1805 static ULONG WINAPI video_mixer_bitmap_Release(IMFVideoMixerBitmap *iface)
1807 struct video_mixer *mixer = impl_from_IMFVideoMixerBitmap(iface);
1808 return IMFTransform_Release(&mixer->IMFTransform_iface);
1811 static HRESULT WINAPI video_mixer_bitmap_SetAlphaBitmap(IMFVideoMixerBitmap *iface, const MFVideoAlphaBitmap *bitmap)
1813 FIXME("%p, %p.\n", iface, bitmap);
1815 return E_NOTIMPL;
1818 static HRESULT WINAPI video_mixer_bitmap_ClearAlphaBitmap(IMFVideoMixerBitmap *iface)
1820 FIXME("%p.\n", iface);
1822 return E_NOTIMPL;
1825 static HRESULT WINAPI video_mixer_bitmap_UpdateAlphaBitmapParameters(IMFVideoMixerBitmap *iface,
1826 const MFVideoAlphaBitmapParams *params)
1828 FIXME("%p, %p.\n", iface, params);
1830 return E_NOTIMPL;
1833 static HRESULT WINAPI video_mixer_bitmap_GetAlphaBitmapParameters(IMFVideoMixerBitmap *iface, MFVideoAlphaBitmapParams *params)
1835 FIXME("%p, %p.\n", iface, params);
1837 return E_NOTIMPL;
1840 static const IMFVideoMixerBitmapVtbl video_mixer_bitmap_vtbl =
1842 video_mixer_bitmap_QueryInterface,
1843 video_mixer_bitmap_AddRef,
1844 video_mixer_bitmap_Release,
1845 video_mixer_bitmap_SetAlphaBitmap,
1846 video_mixer_bitmap_ClearAlphaBitmap,
1847 video_mixer_bitmap_UpdateAlphaBitmapParameters,
1848 video_mixer_bitmap_GetAlphaBitmapParameters,
1851 static HRESULT WINAPI video_mixer_position_mapper_QueryInterface(IMFVideoPositionMapper *iface, REFIID riid, void **obj)
1853 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1854 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1857 static ULONG WINAPI video_mixer_position_mapper_AddRef(IMFVideoPositionMapper *iface)
1859 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1860 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1863 static ULONG WINAPI video_mixer_position_mapper_Release(IMFVideoPositionMapper *iface)
1865 struct video_mixer *mixer = impl_from_IMFVideoPositionMapper(iface);
1866 return IMFTransform_Release(&mixer->IMFTransform_iface);
1869 static HRESULT WINAPI video_mixer_position_mapper_MapOutputCoordinateToInputStream(IMFVideoPositionMapper *iface,
1870 float x_out, float y_out, DWORD output_stream, DWORD input_stream, float *x_in, float *y_in)
1872 FIXME("%p, %f, %f, %u, %u, %p, %p.\n", iface, x_out, y_out, output_stream, input_stream, x_in, y_in);
1874 return E_NOTIMPL;
1877 static const IMFVideoPositionMapperVtbl video_mixer_position_mapper_vtbl =
1879 video_mixer_position_mapper_QueryInterface,
1880 video_mixer_position_mapper_AddRef,
1881 video_mixer_position_mapper_Release,
1882 video_mixer_position_mapper_MapOutputCoordinateToInputStream,
1885 static HRESULT WINAPI video_mixer_processor_QueryInterface(IMFVideoProcessor *iface, REFIID riid, void **obj)
1887 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1888 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, obj);
1891 static ULONG WINAPI video_mixer_processor_AddRef(IMFVideoProcessor *iface)
1893 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1894 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
1897 static ULONG WINAPI video_mixer_processor_Release(IMFVideoProcessor *iface)
1899 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1900 return IMFTransform_Release(&mixer->IMFTransform_iface);
1903 static HRESULT WINAPI video_mixer_processor_GetAvailableVideoProcessorModes(IMFVideoProcessor *iface, UINT *count,
1904 GUID **modes)
1906 FIXME("%p, %p, %p.\n", iface, count, modes);
1908 return E_NOTIMPL;
1911 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorCaps(IMFVideoProcessor *iface, GUID *mode,
1912 DXVA2_VideoProcessorCaps *caps)
1914 FIXME("%p, %s, %p.\n", iface, debugstr_guid(mode), caps);
1916 return E_NOTIMPL;
1919 static HRESULT WINAPI video_mixer_processor_GetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1921 FIXME("%p, %p.\n", iface, mode);
1923 return E_NOTIMPL;
1926 static HRESULT WINAPI video_mixer_processor_SetVideoProcessorMode(IMFVideoProcessor *iface, GUID *mode)
1928 FIXME("%p, %s.\n", iface, debugstr_guid(mode));
1930 return E_NOTIMPL;
1933 static HRESULT WINAPI video_mixer_processor_GetProcAmpRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
1935 FIXME("%p, %#x, %p.\n", iface, prop, range);
1937 return E_NOTIMPL;
1940 static HRESULT WINAPI video_mixer_processor_GetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
1942 FIXME("%p, %#x, %p.\n", iface, flags, values);
1944 return E_NOTIMPL;
1947 static HRESULT WINAPI video_mixer_processor_SetProcAmpValues(IMFVideoProcessor *iface, DWORD flags, DXVA2_ProcAmpValues *values)
1949 FIXME("%p, %#x, %p.\n", iface, flags, values);
1951 return E_NOTIMPL;
1954 static HRESULT WINAPI video_mixer_processor_GetFilteringRange(IMFVideoProcessor *iface, DWORD prop, DXVA2_ValueRange *range)
1956 FIXME("%p, %#x, %p.\n", iface, prop, range);
1958 return E_NOTIMPL;
1961 static HRESULT WINAPI video_mixer_processor_GetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
1963 FIXME("%p, %#x, %p.\n", iface, prop, value);
1965 return E_NOTIMPL;
1968 static HRESULT WINAPI video_mixer_processor_SetFilteringValue(IMFVideoProcessor *iface, DWORD prop, DXVA2_Fixed32 *value)
1970 FIXME("%p, %#x, %p.\n", iface, prop, value);
1972 return E_NOTIMPL;
1975 static HRESULT WINAPI video_mixer_processor_GetBackgroundColor(IMFVideoProcessor *iface, COLORREF *color)
1977 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1979 TRACE("%p, %p.\n", iface, color);
1981 if (!color)
1982 return E_POINTER;
1984 EnterCriticalSection(&mixer->cs);
1985 *color = mixer->bkgnd_color;
1986 LeaveCriticalSection(&mixer->cs);
1988 return S_OK;
1991 static HRESULT WINAPI video_mixer_processor_SetBackgroundColor(IMFVideoProcessor *iface, COLORREF color)
1993 struct video_mixer *mixer = impl_from_IMFVideoProcessor(iface);
1995 TRACE("%p, %#x.\n", iface, color);
1997 EnterCriticalSection(&mixer->cs);
1998 mixer->bkgnd_color = color;
1999 LeaveCriticalSection(&mixer->cs);
2001 return S_OK;
2004 static const IMFVideoProcessorVtbl video_mixer_processor_vtbl =
2006 video_mixer_processor_QueryInterface,
2007 video_mixer_processor_AddRef,
2008 video_mixer_processor_Release,
2009 video_mixer_processor_GetAvailableVideoProcessorModes,
2010 video_mixer_processor_GetVideoProcessorCaps,
2011 video_mixer_processor_GetVideoProcessorMode,
2012 video_mixer_processor_SetVideoProcessorMode,
2013 video_mixer_processor_GetProcAmpRange,
2014 video_mixer_processor_GetProcAmpValues,
2015 video_mixer_processor_SetProcAmpValues,
2016 video_mixer_processor_GetFilteringRange,
2017 video_mixer_processor_GetFilteringValue,
2018 video_mixer_processor_SetFilteringValue,
2019 video_mixer_processor_GetBackgroundColor,
2020 video_mixer_processor_SetBackgroundColor,
2023 static HRESULT WINAPI video_mixer_attributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out)
2025 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2026 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2029 static ULONG WINAPI video_mixer_attributes_AddRef(IMFAttributes *iface)
2031 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2032 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2035 static ULONG WINAPI video_mixer_attributes_Release(IMFAttributes *iface)
2037 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2038 return IMFTransform_Release(&mixer->IMFTransform_iface);
2041 static HRESULT WINAPI video_mixer_attributes_GetItem(IMFAttributes *iface, REFGUID key, PROPVARIANT *value)
2043 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2045 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2047 return IMFAttributes_GetItem(mixer->internal_attributes, key, value);
2050 static HRESULT WINAPI video_mixer_attributes_GetItemType(IMFAttributes *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
2052 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2054 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
2056 return IMFAttributes_GetItemType(mixer->internal_attributes, key, type);
2059 static HRESULT WINAPI video_mixer_attributes_CompareItem(IMFAttributes *iface, REFGUID key,
2060 REFPROPVARIANT value, BOOL *result)
2062 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2064 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
2066 return IMFAttributes_CompareItem(mixer->internal_attributes, key, value, result);
2069 static HRESULT WINAPI video_mixer_attributes_Compare(IMFAttributes *iface, IMFAttributes *theirs,
2070 MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
2072 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2074 TRACE("%p, %p, %d, %p.\n", iface, theirs, match_type, ret);
2076 return IMFAttributes_Compare(mixer->internal_attributes, theirs, match_type, ret);
2079 static HRESULT WINAPI video_mixer_attributes_GetUINT32(IMFAttributes *iface, REFGUID key, UINT32 *value)
2081 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2083 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2085 return IMFAttributes_GetUINT32(mixer->internal_attributes, key, value);
2088 static HRESULT WINAPI video_mixer_attributes_GetUINT64(IMFAttributes *iface, REFGUID key, UINT64 *value)
2090 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2092 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2094 return IMFAttributes_GetUINT64(mixer->internal_attributes, key, value);
2097 static HRESULT WINAPI video_mixer_attributes_GetDouble(IMFAttributes *iface, REFGUID key, double *value)
2099 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2101 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2103 return IMFAttributes_GetDouble(mixer->internal_attributes, key, value);
2106 static HRESULT WINAPI video_mixer_attributes_GetGUID(IMFAttributes *iface, REFGUID key, GUID *value)
2108 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2110 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2112 return IMFAttributes_GetGUID(mixer->internal_attributes, key, value);
2115 static HRESULT WINAPI video_mixer_attributes_GetStringLength(IMFAttributes *iface, REFGUID key, UINT32 *length)
2117 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2119 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
2121 return IMFAttributes_GetStringLength(mixer->internal_attributes, key, length);
2124 static HRESULT WINAPI video_mixer_attributes_GetString(IMFAttributes *iface, REFGUID key, WCHAR *value,
2125 UINT32 size, UINT32 *length)
2127 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2129 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), value, size, length);
2131 return IMFAttributes_GetString(mixer->internal_attributes, key, value, size, length);
2134 static HRESULT WINAPI video_mixer_attributes_GetAllocatedString(IMFAttributes *iface, REFGUID key,
2135 WCHAR **value, UINT32 *length)
2137 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2139 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
2141 return IMFAttributes_GetAllocatedString(mixer->internal_attributes, key, value, length);
2144 static HRESULT WINAPI video_mixer_attributes_GetBlobSize(IMFAttributes *iface, REFGUID key, UINT32 *size)
2146 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2148 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
2150 return IMFAttributes_GetBlobSize(mixer->internal_attributes, key, size);
2153 static HRESULT WINAPI video_mixer_attributes_GetBlob(IMFAttributes *iface, REFGUID key, UINT8 *buf,
2154 UINT32 bufsize, UINT32 *blobsize)
2156 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2158 TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
2160 return IMFAttributes_GetBlob(mixer->internal_attributes, key, buf, bufsize, blobsize);
2163 static HRESULT WINAPI video_mixer_attributes_GetAllocatedBlob(IMFAttributes *iface, REFGUID key, UINT8 **buf, UINT32 *size)
2165 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2167 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
2169 return IMFAttributes_GetAllocatedBlob(mixer->internal_attributes, key, buf, size);
2172 static HRESULT WINAPI video_mixer_attributes_GetUnknown(IMFAttributes *iface, REFGUID key, REFIID riid, void **out)
2174 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2176 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
2178 return IMFAttributes_GetUnknown(mixer->internal_attributes, key, riid, out);
2181 static HRESULT WINAPI video_mixer_attributes_SetItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value)
2183 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2185 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
2187 return IMFAttributes_SetItem(mixer->internal_attributes, key, value);
2190 static HRESULT WINAPI video_mixer_attributes_DeleteItem(IMFAttributes *iface, REFGUID key)
2192 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2194 TRACE("%p, %s.\n", iface, debugstr_guid(key));
2196 return IMFAttributes_DeleteItem(mixer->internal_attributes, key);
2199 static HRESULT WINAPI video_mixer_attributes_DeleteAllItems(IMFAttributes *iface)
2201 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2203 TRACE("%p.\n", iface);
2205 return IMFAttributes_DeleteAllItems(mixer->internal_attributes);
2208 static HRESULT WINAPI video_mixer_attributes_SetUINT32(IMFAttributes *iface, REFGUID key, UINT32 value)
2210 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2212 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
2214 return IMFAttributes_SetUINT32(mixer->internal_attributes, key, value);
2217 static HRESULT WINAPI video_mixer_attributes_SetUINT64(IMFAttributes *iface, REFGUID key, UINT64 value)
2219 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2221 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
2223 return IMFAttributes_SetUINT64(mixer->internal_attributes, key, value);
2226 static HRESULT WINAPI video_mixer_attributes_SetDouble(IMFAttributes *iface, REFGUID key, double value)
2228 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2230 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
2232 return IMFAttributes_SetDouble(mixer->internal_attributes, key, value);
2235 static HRESULT WINAPI video_mixer_attributes_SetGUID(IMFAttributes *iface, REFGUID key, REFGUID value)
2237 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2239 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
2241 return IMFAttributes_SetGUID(mixer->internal_attributes, key, value);
2244 static HRESULT WINAPI video_mixer_attributes_SetString(IMFAttributes *iface, REFGUID key, const WCHAR *value)
2246 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2248 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
2250 return IMFAttributes_SetString(mixer->internal_attributes, key, value);
2253 static HRESULT WINAPI video_mixer_attributes_SetBlob(IMFAttributes *iface, REFGUID key, const UINT8 *buf, UINT32 size)
2255 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2257 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
2259 return IMFAttributes_SetBlob(mixer->internal_attributes, key, buf, size);
2262 static HRESULT WINAPI video_mixer_attributes_SetUnknown(IMFAttributes *iface, REFGUID key, IUnknown *unknown)
2264 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2266 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
2268 return IMFAttributes_SetUnknown(mixer->internal_attributes, key, unknown);
2271 static HRESULT WINAPI video_mixer_attributes_LockStore(IMFAttributes *iface)
2273 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2275 TRACE("%p.\n", iface);
2277 return IMFAttributes_LockStore(mixer->internal_attributes);
2280 static HRESULT WINAPI video_mixer_attributes_UnlockStore(IMFAttributes *iface)
2282 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2284 TRACE("%p.\n", iface);
2286 return IMFAttributes_UnlockStore(mixer->internal_attributes);
2289 static HRESULT WINAPI video_mixer_attributes_GetCount(IMFAttributes *iface, UINT32 *count)
2291 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2293 TRACE("%p, %p.\n", iface, count);
2295 return IMFAttributes_GetCount(mixer->internal_attributes, count);
2298 static HRESULT WINAPI video_mixer_attributes_GetItemByIndex(IMFAttributes *iface, UINT32 index,
2299 GUID *key, PROPVARIANT *value)
2301 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2303 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
2305 return IMFAttributes_GetItemByIndex(mixer->internal_attributes, index, key, value);
2308 static HRESULT WINAPI video_mixer_attributes_CopyAllItems(IMFAttributes *iface, IMFAttributes *dest)
2310 struct video_mixer *mixer = impl_from_IMFAttributes(iface);
2312 TRACE("%p, %p.\n", iface, dest);
2314 return IMFAttributes_CopyAllItems(mixer->internal_attributes, dest);
2317 static const IMFAttributesVtbl video_mixer_attributes_vtbl =
2319 video_mixer_attributes_QueryInterface,
2320 video_mixer_attributes_AddRef,
2321 video_mixer_attributes_Release,
2322 video_mixer_attributes_GetItem,
2323 video_mixer_attributes_GetItemType,
2324 video_mixer_attributes_CompareItem,
2325 video_mixer_attributes_Compare,
2326 video_mixer_attributes_GetUINT32,
2327 video_mixer_attributes_GetUINT64,
2328 video_mixer_attributes_GetDouble,
2329 video_mixer_attributes_GetGUID,
2330 video_mixer_attributes_GetStringLength,
2331 video_mixer_attributes_GetString,
2332 video_mixer_attributes_GetAllocatedString,
2333 video_mixer_attributes_GetBlobSize,
2334 video_mixer_attributes_GetBlob,
2335 video_mixer_attributes_GetAllocatedBlob,
2336 video_mixer_attributes_GetUnknown,
2337 video_mixer_attributes_SetItem,
2338 video_mixer_attributes_DeleteItem,
2339 video_mixer_attributes_DeleteAllItems,
2340 video_mixer_attributes_SetUINT32,
2341 video_mixer_attributes_SetUINT64,
2342 video_mixer_attributes_SetDouble,
2343 video_mixer_attributes_SetGUID,
2344 video_mixer_attributes_SetString,
2345 video_mixer_attributes_SetBlob,
2346 video_mixer_attributes_SetUnknown,
2347 video_mixer_attributes_LockStore,
2348 video_mixer_attributes_UnlockStore,
2349 video_mixer_attributes_GetCount,
2350 video_mixer_attributes_GetItemByIndex,
2351 video_mixer_attributes_CopyAllItems
2354 static HRESULT WINAPI video_mixer_quality_advise_QueryInterface(IMFQualityAdvise *iface, REFIID riid, void **out)
2356 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2357 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2360 static ULONG WINAPI video_mixer_quality_advise_AddRef(IMFQualityAdvise *iface)
2362 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2363 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2366 static ULONG WINAPI video_mixer_quality_advise_Release(IMFQualityAdvise *iface)
2368 struct video_mixer *mixer = impl_from_IMFQualityAdvise(iface);
2369 return IMFTransform_Release(&mixer->IMFTransform_iface);
2372 static HRESULT WINAPI video_mixer_quality_advise_SetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE mode)
2374 FIXME("%p, %u.\n", iface, mode);
2376 return E_NOTIMPL;
2379 static HRESULT WINAPI video_mixer_quality_advise_SetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL level)
2381 FIXME("%p, %u.\n", iface, level);
2383 return E_NOTIMPL;
2386 static HRESULT WINAPI video_mixer_quality_advise_GetDropMode(IMFQualityAdvise *iface, MF_QUALITY_DROP_MODE *mode)
2388 FIXME("%p, %p.\n", iface, mode);
2390 return E_NOTIMPL;
2393 static HRESULT WINAPI video_mixer_quality_advise_GetQualityLevel(IMFQualityAdvise *iface, MF_QUALITY_LEVEL *level)
2395 FIXME("%p, %p.\n", iface, level);
2397 return E_NOTIMPL;
2400 static HRESULT WINAPI video_mixer_quality_advise_DropTime(IMFQualityAdvise *iface, LONGLONG interval)
2402 FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(interval));
2404 return E_NOTIMPL;
2407 static const IMFQualityAdviseVtbl video_mixer_quality_advise_vtbl =
2409 video_mixer_quality_advise_QueryInterface,
2410 video_mixer_quality_advise_AddRef,
2411 video_mixer_quality_advise_Release,
2412 video_mixer_quality_advise_SetDropMode,
2413 video_mixer_quality_advise_SetQualityLevel,
2414 video_mixer_quality_advise_GetDropMode,
2415 video_mixer_quality_advise_GetQualityLevel,
2416 video_mixer_quality_advise_DropTime,
2419 static HRESULT WINAPI video_mixer_clock_state_sink_QueryInterface(IMFClockStateSink *iface,
2420 REFIID riid, void **out)
2422 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2423 return IMFTransform_QueryInterface(&mixer->IMFTransform_iface, riid, out);
2426 static ULONG WINAPI video_mixer_clock_state_sink_AddRef(IMFClockStateSink *iface)
2428 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2429 return IMFTransform_AddRef(&mixer->IMFTransform_iface);
2432 static ULONG WINAPI video_mixer_clock_state_sink_Release(IMFClockStateSink *iface)
2434 struct video_mixer *mixer = impl_from_IMFClockStateSink(iface);
2435 return IMFTransform_Release(&mixer->IMFTransform_iface);
2438 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStart(IMFClockStateSink *iface,
2439 MFTIME systime, LONGLONG offset)
2441 FIXME("%p.\n", iface);
2443 return E_NOTIMPL;
2446 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockStop(IMFClockStateSink *iface,
2447 MFTIME systime)
2449 FIXME("%p.\n", iface);
2451 return E_NOTIMPL;
2454 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockPause(IMFClockStateSink *iface,
2455 MFTIME systime)
2457 FIXME("%p.\n", iface);
2459 return E_NOTIMPL;
2462 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockRestart(IMFClockStateSink *iface,
2463 MFTIME systime)
2465 FIXME("%p.\n", iface);
2467 return E_NOTIMPL;
2470 static HRESULT WINAPI video_mixer_clock_state_sink_OnClockSetRate(IMFClockStateSink *iface,
2471 MFTIME systime, float rate)
2473 FIXME("%p, %f.\n", iface, rate);
2475 return E_NOTIMPL;
2478 static const IMFClockStateSinkVtbl video_mixer_clock_state_sink_vtbl =
2480 video_mixer_clock_state_sink_QueryInterface,
2481 video_mixer_clock_state_sink_AddRef,
2482 video_mixer_clock_state_sink_Release,
2483 video_mixer_clock_state_sink_OnClockStart,
2484 video_mixer_clock_state_sink_OnClockStop,
2485 video_mixer_clock_state_sink_OnClockPause,
2486 video_mixer_clock_state_sink_OnClockRestart,
2487 video_mixer_clock_state_sink_OnClockSetRate,
2490 HRESULT WINAPI MFCreateVideoMixer(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj)
2492 TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj);
2494 *obj = NULL;
2496 if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9))
2497 return E_INVALIDARG;
2499 return CoCreateInstance(&CLSID_MFVideoMixer9, owner, CLSCTX_INPROC_SERVER, riid, obj);
2502 HRESULT evr_mixer_create(IUnknown *outer, void **out)
2504 struct video_mixer *object;
2505 MFVideoNormalizedRect rect;
2506 HRESULT hr;
2508 if (!(object = calloc(1, sizeof(*object))))
2509 return E_OUTOFMEMORY;
2511 object->IMFTransform_iface.lpVtbl = &video_mixer_transform_vtbl;
2512 object->IMFVideoDeviceID_iface.lpVtbl = &video_mixer_device_id_vtbl;
2513 object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_mixer_service_client_vtbl;
2514 object->IMFVideoMixerControl2_iface.lpVtbl = &video_mixer_control_vtbl;
2515 object->IMFGetService_iface.lpVtbl = &video_mixer_getservice_vtbl;
2516 object->IMFVideoMixerBitmap_iface.lpVtbl = &video_mixer_bitmap_vtbl;
2517 object->IMFVideoPositionMapper_iface.lpVtbl = &video_mixer_position_mapper_vtbl;
2518 object->IMFVideoProcessor_iface.lpVtbl = &video_mixer_processor_vtbl;
2519 object->IMFAttributes_iface.lpVtbl = &video_mixer_attributes_vtbl;
2520 object->IMFQualityAdvise_iface.lpVtbl = &video_mixer_quality_advise_vtbl;
2521 object->IMFClockStateSink_iface.lpVtbl = &video_mixer_clock_state_sink_vtbl;
2522 object->IUnknown_inner.lpVtbl = &video_mixer_inner_vtbl;
2523 object->outer_unk = outer ? outer : &object->IUnknown_inner;
2524 object->refcount = 1;
2525 object->input_count = 1;
2526 object->lower_bound = MFT_OUTPUT_BOUND_LOWER_UNBOUNDED;
2527 object->upper_bound = MFT_OUTPUT_BOUND_UPPER_UNBOUNDED;
2528 video_mixer_init_input(&object->inputs[0]);
2529 video_mixer_update_zorder_map(object);
2530 InitializeCriticalSection(&object->cs);
2531 if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
2533 IUnknown_Release(&object->IUnknown_inner);
2534 return hr;
2536 if (FAILED(hr = MFCreateAttributes(&object->internal_attributes, 0)))
2538 IUnknown_Release(&object->IUnknown_inner);
2539 return hr;
2542 /* Default attributes configuration. */
2544 rect.left = rect.top = 0.0f;
2545 rect.right = rect.bottom = 1.0f;
2546 IMFAttributes_SetBlob(object->attributes, &VIDEO_ZOOM_RECT, (const UINT8 *)&rect, sizeof(rect));
2548 IMFAttributes_SetUINT32(object->internal_attributes, &MF_SA_D3D_AWARE, 1);
2550 *out = &object->IUnknown_inner;
2552 return S_OK;