evr: Add input type validation through dxva.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2020-06-29 15:43:38 +03:00 committed by Alexandre Julliard
parent 881336569c
commit 43eebcd3e6
2 changed files with 269 additions and 19 deletions

View File

@ -18,7 +18,6 @@
#define COBJMACROS
#include "wine/debug.h"
#include "evr.h"
#include "d3d9.h"
#include "dxva2api.h"
@ -30,6 +29,9 @@
#include "initguid.h"
#include "evr9.h"
#include "wine/debug.h"
#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(evr);
#define MAX_MIXER_INPUT_STREAMS 16
@ -38,6 +40,14 @@ struct input_stream
{
unsigned int id;
IMFAttributes *attributes;
IMFVideoMediaType *media_type;
};
struct output_stream
{
IMFVideoMediaType *media_type;
IMFVideoMediaType **media_types;
unsigned int type_count;
};
struct video_mixer
@ -55,6 +65,7 @@ struct video_mixer
struct input_stream inputs[MAX_MIXER_INPUT_STREAMS];
unsigned int input_ids[MAX_MIXER_INPUT_STREAMS];
unsigned int input_count;
struct output_stream output;
IDirect3DDeviceManager9 *device_manager;
@ -122,6 +133,26 @@ static void video_mixer_init_input(struct input_stream *stream)
IMFAttributes_SetUINT32(stream->attributes, &MF_SA_REQUIRED_SAMPLE_COUNT, 1);
}
static void video_mixer_clear_types(struct video_mixer *mixer)
{
unsigned int i;
for (i = 0; i < mixer->input_count; ++i)
{
if (mixer->inputs[i].media_type)
IMFVideoMediaType_Release(mixer->inputs[i].media_type);
mixer->inputs[i].media_type = NULL;
}
for (i = 0; i < mixer->output.type_count; ++i)
{
IMFVideoMediaType_Release(mixer->output.media_types[i]);
}
heap_free(mixer->output.media_types);
if (mixer->output.media_type)
IMFVideoMediaType_Release(mixer->output.media_type);
mixer->output.media_type = NULL;
}
static HRESULT WINAPI video_mixer_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
{
struct video_mixer *mixer = impl_from_IMFTransform(iface);
@ -198,6 +229,7 @@ static ULONG WINAPI video_mixer_transform_Release(IMFTransform *iface)
if (mixer->inputs[i].attributes)
IMFAttributes_Release(mixer->inputs[i].attributes);
}
video_mixer_clear_types(mixer);
if (mixer->device_manager)
IDirect3DDeviceManager9_Release(mixer->device_manager);
DeleteCriticalSection(&mixer->cs);
@ -430,9 +462,27 @@ static HRESULT WINAPI video_mixer_transform_GetInputAvailableType(IMFTransform *
static HRESULT WINAPI video_mixer_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
IMFMediaType **type)
{
FIXME("%p, %u, %u, %p.\n", iface, id, index, type);
struct video_mixer *mixer = impl_from_IMFTransform(iface);
HRESULT hr = S_OK;
return E_NOTIMPL;
TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
if (id)
return MF_E_INVALIDSTREAMNUMBER;
EnterCriticalSection(&mixer->cs);
if (index >= mixer->output.type_count)
hr = MF_E_NO_MORE_TYPES;
else
{
*type = (IMFMediaType *)mixer->output.media_types[index];
IMFMediaType_AddRef(*type);
}
LeaveCriticalSection(&mixer->cs);
return hr;
}
static HRESULT video_mixer_init_dxva_videodesc(IMFMediaType *media_type, DXVA2_VideoDesc *video_desc)
@ -465,24 +515,93 @@ done:
return hr;
}
static int rt_formats_sort_compare(const void *left, const void *right)
{
D3DFORMAT format1 = *(D3DFORMAT *)left, format2 = *(D3DFORMAT *)right;
if (format1 < format2) return -1;
if (format1 > format2) return 1;
return 0;
}
static HRESULT video_mixer_collect_output_types(struct video_mixer *mixer, const DXVA2_VideoDesc *video_desc,
IDirectXVideoProcessorService *service, unsigned int device_count, const GUID *devices)
{
unsigned int i, j, format_count, count;
D3DFORMAT *rt_formats = NULL, *formats, *ptr;
GUID subtype;
HRESULT hr;
count = 0;
for (i = 0; i < device_count; ++i)
{
if (SUCCEEDED(IDirectXVideoProcessorService_GetVideoProcessorRenderTargets(service, &devices[i], video_desc,
&format_count, &formats)))
{
if (!(ptr = heap_realloc(rt_formats, (count + format_count) * sizeof(*rt_formats))))
{
hr = E_OUTOFMEMORY;
CoTaskMemFree(formats);
break;
}
rt_formats = ptr;
memcpy(&rt_formats[count], formats, format_count * sizeof(*formats));
count += format_count;
CoTaskMemFree(formats);
}
}
if (count)
{
qsort(rt_formats, count, sizeof(*rt_formats), rt_formats_sort_compare);
j = 0;
for (i = j + 1; i < count; ++i)
{
if (rt_formats[i] != rt_formats[j])
{
rt_formats[++j] = rt_formats[i];
}
}
count = j + 1;
memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
if ((mixer->output.media_types = heap_calloc(count, sizeof(*mixer->output.media_types))))
{
for (i = 0; i < count; ++i)
{
subtype.Data1 = rt_formats[i];
MFCreateVideoMediaTypeFromSubtype(&subtype, &mixer->output.media_types[i]);
}
mixer->output.type_count = count;
}
else
hr = E_OUTOFMEMORY;
}
heap_free(rt_formats);
return hr;
}
static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *media_type, DWORD flags)
{
struct video_mixer *mixer = impl_from_IMFTransform(iface);
IDirectXVideoProcessorService *service;
DXVA2_VideoDesc video_desc;
HRESULT hr = E_NOTIMPL;
unsigned int count;
HANDLE handle;
GUID *guids;
TRACE("%p, %u, %p, %#x.\n", iface, id, media_type, flags);
if (id)
{
FIXME("Unimplemented for substreams.\n");
return E_NOTIMPL;
}
EnterCriticalSection(&mixer->cs);
video_mixer_clear_types(mixer);
if (!mixer->device_manager)
hr = MF_E_NOT_INITIALIZED;
else
@ -494,8 +613,21 @@ static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DW
{
if (SUCCEEDED(hr = video_mixer_init_dxva_videodesc(media_type, &video_desc)))
{
FIXME("Probe for supported devices.\n");
hr = E_NOTIMPL;
if (!id)
{
if (SUCCEEDED(hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc,
&count, &guids)))
{
if (SUCCEEDED(hr = video_mixer_collect_output_types(mixer, &video_desc, service, count, guids)))
FIXME("Set input type.\n");
CoTaskMemFree(guids);
}
}
else
{
FIXME("Unimplemented for substreams.\n");
hr = E_NOTIMPL;
}
}
}
IDirect3DDeviceManager9_CloseDeviceHandle(mixer->device_manager, handle);
@ -516,16 +648,55 @@ static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, D
static HRESULT WINAPI video_mixer_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
{
FIXME("%p, %u, %p.\n", iface, id, type);
struct video_mixer *mixer = impl_from_IMFTransform(iface);
struct input_stream *stream;
HRESULT hr = S_OK;
return E_NOTIMPL;
TRACE("%p, %u, %p.\n", iface, id, type);
EnterCriticalSection(&mixer->cs);
if ((stream = video_mixer_get_input(mixer, id)))
{
if (!stream->media_type)
hr = MF_E_TRANSFORM_TYPE_NOT_SET;
else
{
*type = (IMFMediaType *)stream->media_type;
IMFMediaType_AddRef(*type);
}
}
else
hr = MF_E_INVALIDSTREAMNUMBER;
LeaveCriticalSection(&mixer->cs);
return hr;
}
static HRESULT WINAPI video_mixer_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
{
FIXME("%p, %u, %p.\n", iface, id, type);
struct video_mixer *mixer = impl_from_IMFTransform(iface);
HRESULT hr = S_OK;
return E_NOTIMPL;
TRACE("%p, %u, %p.\n", iface, id, type);
if (id)
return MF_E_INVALIDSTREAMNUMBER;
EnterCriticalSection(&mixer->cs);
if (!mixer->output.media_type)
hr = MF_E_TRANSFORM_TYPE_NOT_SET;
else
{
*type = (IMFMediaType *)mixer->output.media_type;
IMFMediaType_AddRef(*type);
}
LeaveCriticalSection(&mixer->cs);
return hr;
}
static HRESULT WINAPI video_mixer_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)

View File

@ -376,17 +376,23 @@ static void test_pin_info(void)
static void test_default_mixer(void)
{
DWORD input_min, input_max, output_min, output_max;
IMFAttributes *attributes, *attributes2;
MFT_OUTPUT_STREAM_INFO output_info;
MFT_INPUT_STREAM_INFO input_info;
DWORD input_count, output_count;
IMFVideoProcessor *processor;
IMFVideoDeviceID *deviceid;
DWORD input_id, output_id;
IMFAttributes *attributes, *attributes2;
IMFTransform *transform;
DXVA2_ValueRange range;
DXVA2_Fixed32 value;
IMFGetService *gs;
COLORREF color;
unsigned int i;
DWORD ids[16];
IUnknown *unk;
DWORD count;
GUID *guids;
HRESULT hr;
IID iid;
@ -404,9 +410,37 @@ static void test_default_mixer(void)
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IUnknown_Release(unk);
hr = IMFGetService_GetService(gs, &MR_VIDEO_MIXER_SERVICE, &IID_IMFVideoProcessor, (void **)&unk);
hr = IMFGetService_GetService(gs, &MR_VIDEO_MIXER_SERVICE, &IID_IMFVideoProcessor, (void **)&processor);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IUnknown_Release(unk);
color = 1;
hr = IMFVideoProcessor_GetBackgroundColor(processor, &color);
todo_wine {
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(!color, "Unexpected color %#x.\n", color);
}
hr = IMFVideoProcessor_SetBackgroundColor(processor, 0x00121212);
todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFVideoProcessor_GetBackgroundColor(processor, &color);
todo_wine {
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(color == 0x121212, "Unexpected color %#x.\n", color);
}
hr = IMFVideoProcessor_GetFilteringRange(processor, DXVA2_DetailFilterChromaLevel, &range);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
hr = IMFVideoProcessor_GetFilteringValue(processor, DXVA2_DetailFilterChromaLevel, &value);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
hr = IMFVideoProcessor_GetAvailableVideoProcessorModes(processor, &count, &guids);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
IMFVideoProcessor_Release(processor);
hr = IMFGetService_GetService(gs, &MR_VIDEO_MIXER_SERVICE, &IID_IMFVideoPositionMapper, (void **)&unk);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
@ -663,12 +697,17 @@ done:
static void test_default_mixer_type_negotiation(void)
{
IDirect3DDeviceManager9 *manager;
DXVA2_VideoProcessorCaps caps;
IMFVideoMediaType *video_type;
IMFVideoProcessor *processor;
IMFMediaType *media_type;
IDirect3DDevice9 *device;
IMFTransform *transform;
GUID guid, *guids;
IDirect3D9 *d3d;
IUnknown *unk;
HWND window;
DWORD count;
HRESULT hr;
UINT token;
@ -685,7 +724,6 @@ static void test_default_mixer_type_negotiation(void)
ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
hr = MFCreateMediaType(&media_type);
@ -746,15 +784,56 @@ todo_wine
todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFTransform_QueryInterface(transform, &IID_IMFVideoProcessor, (void **)&processor);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFVideoProcessor_GetVideoProcessorMode(processor, &guid);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
hr = IMFVideoProcessor_GetVideoProcessorCaps(processor, (GUID *)&DXVA2_VideoProcSoftwareDevice, &caps);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type);
todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
if (SUCCEEDED(hr))
{
ok(media_type != (IMFMediaType *)video_type, "Unexpected pointer.\n");
hr = IMFMediaType_QueryInterface(media_type, &IID_IMFVideoMediaType, (void **)&unk);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IUnknown_Release(unk);
IMFMediaType_Release(media_type);
}
hr = IMFVideoProcessor_GetAvailableVideoProcessorModes(processor, &count, &guids);
todo_wine
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr);
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
if (SUCCEEDED(hr))
{
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMFMediaType_Release(media_type);
}
hr = IMFVideoProcessor_GetVideoProcessorMode(processor, &guid);
todo_wine
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
hr = IMFVideoProcessor_GetAvailableVideoProcessorModes(processor, &count, &guids);
todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
if (SUCCEEDED(hr))
CoTaskMemFree(guids);
IMFVideoProcessor_Release(processor);
IMFVideoMediaType_Release(video_type);
IDirect3DDeviceManager9_Release(manager);