evr: Implement stream managment methods for default mixer.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9c11c636b3
commit
d6e5b6ca02
178
dlls/evr/mixer.c
178
dlls/evr/mixer.c
|
@ -21,17 +21,30 @@
|
|||
#include "wine/debug.h"
|
||||
#include "evr.h"
|
||||
#include "d3d9.h"
|
||||
#include "mferror.h"
|
||||
|
||||
#include "evr_classes.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(evr);
|
||||
|
||||
#define MAX_MIXER_INPUT_STREAMS 16
|
||||
|
||||
struct input_stream
|
||||
{
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
struct video_mixer
|
||||
{
|
||||
IMFTransform IMFTransform_iface;
|
||||
IMFVideoDeviceID IMFVideoDeviceID_iface;
|
||||
IMFTopologyServiceLookupClient IMFTopologyServiceLookupClient_iface;
|
||||
LONG refcount;
|
||||
|
||||
struct input_stream inputs[MAX_MIXER_INPUT_STREAMS];
|
||||
unsigned int input_ids[MAX_MIXER_INPUT_STREAMS];
|
||||
unsigned int input_count;
|
||||
CRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
static struct video_mixer *impl_from_IMFTransform(IMFTransform *iface)
|
||||
|
@ -49,6 +62,21 @@ static struct video_mixer *impl_from_IMFTopologyServiceLookupClient(IMFTopologyS
|
|||
return CONTAINING_RECORD(iface, struct video_mixer, IMFTopologyServiceLookupClient_iface);
|
||||
}
|
||||
|
||||
static int video_mixer_compare_input_id(const void *a, const void *b)
|
||||
{
|
||||
const unsigned int *key = a;
|
||||
const struct input_stream *input = b;
|
||||
|
||||
if (*key > input->id) return 1;
|
||||
if (*key < input->id) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct input_stream * video_mixer_get_input(const struct video_mixer *mixer, unsigned int id)
|
||||
{
|
||||
return bsearch(&id, mixer->inputs, mixer->input_count, sizeof(*mixer->inputs), video_mixer_compare_input_id);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
|
||||
{
|
||||
struct video_mixer *mixer = impl_from_IMFTransform(iface);
|
||||
|
@ -97,7 +125,10 @@ static ULONG WINAPI video_mixer_transform_Release(IMFTransform *iface)
|
|||
TRACE("%p, refcount %u.\n", iface, refcount);
|
||||
|
||||
if (!refcount)
|
||||
{
|
||||
DeleteCriticalSection(&mixer->cs);
|
||||
free(mixer);
|
||||
}
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
@ -105,38 +136,81 @@ static ULONG WINAPI video_mixer_transform_Release(IMFTransform *iface)
|
|||
static HRESULT WINAPI video_mixer_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
|
||||
DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
|
||||
{
|
||||
FIXME("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
|
||||
TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
|
||||
|
||||
return E_NOTIMPL;
|
||||
*input_minimum = 1;
|
||||
*input_maximum = 16;
|
||||
*output_minimum = 1;
|
||||
*output_maximum = 1;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
|
||||
{
|
||||
FIXME("%p, %p, %p.\n", iface, inputs, outputs);
|
||||
struct video_mixer *mixer = impl_from_IMFTransform(iface);
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %p, %p.\n", iface, inputs, outputs);
|
||||
|
||||
EnterCriticalSection(&mixer->cs);
|
||||
if (inputs) *inputs = mixer->input_count;
|
||||
if (outputs) *outputs = 1;
|
||||
LeaveCriticalSection(&mixer->cs);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
|
||||
DWORD output_size, DWORD *outputs)
|
||||
{
|
||||
FIXME("%p, %u, %p, %u, %p.\n", iface, input_size, inputs, output_size, outputs);
|
||||
struct video_mixer *mixer = impl_from_IMFTransform(iface);
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %u, %p, %u, %p.\n", iface, input_size, inputs, output_size, outputs);
|
||||
|
||||
EnterCriticalSection(&mixer->cs);
|
||||
if (mixer->input_count > input_size || !output_size)
|
||||
hr = MF_E_BUFFERTOOSMALL;
|
||||
else if (inputs)
|
||||
memcpy(inputs, mixer->input_ids, mixer->input_count * sizeof(*inputs));
|
||||
if (outputs) *outputs = 0;
|
||||
LeaveCriticalSection(&mixer->cs);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
|
||||
{
|
||||
FIXME("%p, %u, %p.\n", iface, id, info);
|
||||
struct video_mixer *mixer = impl_from_IMFTransform(iface);
|
||||
struct input_stream *input;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %u, %p.\n", iface, id, info);
|
||||
|
||||
EnterCriticalSection(&mixer->cs);
|
||||
if (!(input = video_mixer_get_input(mixer, id)))
|
||||
hr = MF_E_INVALIDSTREAMNUMBER;
|
||||
else
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
if (id)
|
||||
info->dwFlags |= MFT_INPUT_STREAM_REMOVABLE | MFT_INPUT_STREAM_OPTIONAL;
|
||||
}
|
||||
LeaveCriticalSection(&mixer->cs);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
|
||||
{
|
||||
FIXME("%p, %u, %p.\n", iface, id, info);
|
||||
TRACE("%p, %u, %p.\n", iface, id, info);
|
||||
|
||||
return E_NOTIMPL;
|
||||
if (id)
|
||||
return MF_E_INVALIDSTREAMNUMBER;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
|
||||
|
@ -157,23 +231,93 @@ static HRESULT WINAPI video_mixer_transform_GetInputStreamAttributes(IMFTransfor
|
|||
static HRESULT WINAPI video_mixer_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
|
||||
IMFAttributes **attributes)
|
||||
{
|
||||
FIXME("%p, %u, %p.\n", iface, id, attributes);
|
||||
TRACE("%p, %u, %p.\n", iface, id, attributes);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_DeleteInputStream(IMFTransform *iface, DWORD id)
|
||||
{
|
||||
FIXME("%p, %u.\n", iface, id);
|
||||
struct video_mixer *mixer = impl_from_IMFTransform(iface);
|
||||
struct input_stream *input;
|
||||
HRESULT hr = S_OK;
|
||||
unsigned int idx;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %u.\n", iface, id);
|
||||
|
||||
EnterCriticalSection(&mixer->cs);
|
||||
|
||||
/* Can't delete reference stream. */
|
||||
if (!id || !(input = video_mixer_get_input(mixer, id)))
|
||||
hr = MF_E_INVALIDSTREAMNUMBER;
|
||||
else
|
||||
{
|
||||
mixer->input_count--;
|
||||
idx = input - mixer->inputs;
|
||||
if (idx < mixer->input_count)
|
||||
{
|
||||
memmove(&mixer->inputs[idx], &mixer->inputs[idx + 1], (mixer->input_count - idx) * sizeof(*mixer->inputs));
|
||||
memmove(&mixer->input_ids[idx], &mixer->input_ids[idx + 1], (mixer->input_count - idx) *
|
||||
sizeof(*mixer->input_ids));
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&mixer->cs);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
|
||||
static int video_mixer_add_input_sort_compare(const void *a, const void *b)
|
||||
{
|
||||
FIXME("%p, %u, %p.\n", iface, streams, ids);
|
||||
const struct input_stream *left = a, *right = b;
|
||||
return left->id != right->id ? (left->id < right->id ? -1 : 1) : 0;
|
||||
};
|
||||
|
||||
return E_NOTIMPL;
|
||||
static HRESULT WINAPI video_mixer_transform_AddInputStreams(IMFTransform *iface, DWORD count, DWORD *ids)
|
||||
{
|
||||
struct video_mixer *mixer = impl_from_IMFTransform(iface);
|
||||
struct input_stream inputs[MAX_MIXER_INPUT_STREAMS] = { {0} };
|
||||
unsigned int i, len;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("%p, %u, %p.\n", iface, count, ids);
|
||||
|
||||
if (!ids)
|
||||
return E_POINTER;
|
||||
|
||||
EnterCriticalSection(&mixer->cs);
|
||||
if (count > ARRAY_SIZE(mixer->inputs) - mixer->input_count)
|
||||
hr = E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
/* Test for collisions. */
|
||||
memcpy(inputs, mixer->inputs, mixer->input_count * sizeof(*inputs));
|
||||
for (i = 0; i < count; ++i)
|
||||
inputs[i + mixer->input_count].id = ids[i];
|
||||
|
||||
len = mixer->input_count + count;
|
||||
|
||||
qsort(inputs, len, sizeof(*inputs), video_mixer_add_input_sort_compare);
|
||||
|
||||
for (i = 1; i < len; ++i)
|
||||
{
|
||||
if (inputs[i - 1].id == inputs[i].id)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
memcpy(&mixer->input_ids[mixer->input_count], ids, count * sizeof(*ids));
|
||||
memcpy(mixer->inputs, inputs, len * sizeof(*inputs));
|
||||
mixer->input_count += count;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&mixer->cs);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI video_mixer_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
|
||||
|
@ -407,6 +551,8 @@ HRESULT evr_mixer_create(IUnknown *outer, void **out)
|
|||
object->IMFVideoDeviceID_iface.lpVtbl = &video_mixer_device_id_vtbl;
|
||||
object->IMFTopologyServiceLookupClient_iface.lpVtbl = &video_mixer_service_client_vtbl;
|
||||
object->refcount = 1;
|
||||
object->input_count = 1;
|
||||
InitializeCriticalSection(&object->cs);
|
||||
|
||||
*out = &object->IMFTransform_iface;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "evr.h"
|
||||
#include "initguid.h"
|
||||
#include "dxva2api.h"
|
||||
#include "mferror.h"
|
||||
|
||||
static const WCHAR sink_id[] = {'E','V','R',' ','I','n','p','u','t','0',0};
|
||||
|
||||
|
@ -340,8 +341,16 @@ static void test_pin_info(void)
|
|||
|
||||
static void test_default_mixer(void)
|
||||
{
|
||||
DWORD input_min, input_max, output_min, output_max;
|
||||
MFT_OUTPUT_STREAM_INFO output_info;
|
||||
MFT_INPUT_STREAM_INFO input_info;
|
||||
DWORD input_count, output_count;
|
||||
IMFVideoDeviceID *deviceid;
|
||||
DWORD input_id, output_id;
|
||||
IMFAttributes *attributes, *attributes2;
|
||||
IMFTransform *transform;
|
||||
unsigned int i;
|
||||
DWORD ids[16];
|
||||
IUnknown *unk;
|
||||
HRESULT hr;
|
||||
IID iid;
|
||||
|
@ -365,6 +374,111 @@ static void test_default_mixer(void)
|
|||
|
||||
IMFVideoDeviceID_Release(deviceid);
|
||||
|
||||
/* Stream configuration. */
|
||||
input_count = output_count = 0;
|
||||
hr = IMFTransform_GetStreamCount(transform, &input_count, &output_count);
|
||||
ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr);
|
||||
ok(input_count == 1 && output_count == 1, "Unexpected stream count %u/%u.\n", input_count, output_count);
|
||||
|
||||
hr = IMFTransform_GetStreamLimits(transform, &input_min, &input_max, &output_min, &output_max);
|
||||
ok(hr == S_OK, "Failed to get stream limits, hr %#x.\n", hr);
|
||||
ok(input_min == 1 && input_max == 16 && output_min == 1 && output_max == 1, "Unexpected stream limits %u/%u, %u/%u.\n",
|
||||
input_min, input_max, output_min, output_max);
|
||||
|
||||
hr = IMFTransform_GetInputStreamInfo(transform, 1, &input_info);
|
||||
ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTransform_GetOutputStreamInfo(transform, 1, &output_info);
|
||||
ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
memset(&input_info, 0xcc, sizeof(input_info));
|
||||
hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info);
|
||||
ok(hr == S_OK, "Failed to get input info, hr %#x.\n", hr);
|
||||
|
||||
memset(&output_info, 0xcc, sizeof(output_info));
|
||||
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info);
|
||||
ok(hr == S_OK, "Failed to get input info, hr %#x.\n", hr);
|
||||
ok(!(output_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)),
|
||||
"Unexpected output flags %#x.\n", output_info.dwFlags);
|
||||
|
||||
hr = IMFTransform_GetStreamIDs(transform, 1, &input_id, 1, &output_id);
|
||||
ok(hr == S_OK, "Failed to get input info, hr %#x.\n", hr);
|
||||
ok(input_id == 0 && output_id == 0, "Unexpected stream ids.\n");
|
||||
|
||||
hr = IMFTransform_GetInputStreamAttributes(transform, 1, &attributes);
|
||||
todo_wine
|
||||
ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTransform_GetOutputStreamAttributes(transform, 1, &attributes);
|
||||
ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTransform_GetOutputStreamAttributes(transform, 0, &attributes);
|
||||
ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTransform_AddInputStreams(transform, 16, NULL);
|
||||
ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTransform_AddInputStreams(transform, 16, ids);
|
||||
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
memset(ids, 0, sizeof(ids));
|
||||
hr = IMFTransform_AddInputStreams(transform, 15, ids);
|
||||
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ids); ++i)
|
||||
ids[i] = i + 1;
|
||||
|
||||
hr = IMFTransform_AddInputStreams(transform, 15, ids);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
input_count = output_count = 0;
|
||||
hr = IMFTransform_GetStreamCount(transform, &input_count, &output_count);
|
||||
ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr);
|
||||
ok(input_count == 16 && output_count == 1, "Unexpected stream count %u/%u.\n", input_count, output_count);
|
||||
|
||||
memset(&input_info, 0, sizeof(input_info));
|
||||
hr = IMFTransform_GetInputStreamInfo(transform, 1, &input_info);
|
||||
ok(hr == S_OK, "Failed to get input info, hr %#x.\n", hr);
|
||||
ok((input_info.dwFlags & (MFT_INPUT_STREAM_REMOVABLE | MFT_INPUT_STREAM_OPTIONAL)) ==
|
||||
(MFT_INPUT_STREAM_REMOVABLE | MFT_INPUT_STREAM_OPTIONAL), "Unexpected flags %#x.\n", input_info.dwFlags);
|
||||
|
||||
attributes = NULL;
|
||||
hr = IMFTransform_GetInputStreamAttributes(transform, 0, &attributes);
|
||||
todo_wine {
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
ok(!!attributes, "Unexpected attributes.\n");
|
||||
}
|
||||
attributes2 = NULL;
|
||||
hr = IMFTransform_GetInputStreamAttributes(transform, 0, &attributes2);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
ok(attributes == attributes2, "Unexpected instance.\n");
|
||||
|
||||
if (attributes2)
|
||||
IMFAttributes_Release(attributes2);
|
||||
if (attributes)
|
||||
IMFAttributes_Release(attributes);
|
||||
|
||||
attributes = NULL;
|
||||
hr = IMFTransform_GetInputStreamAttributes(transform, 1, &attributes);
|
||||
todo_wine {
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
ok(!!attributes, "Unexpected attributes.\n");
|
||||
}
|
||||
if (attributes)
|
||||
IMFAttributes_Release(attributes);
|
||||
|
||||
hr = IMFTransform_DeleteInputStream(transform, 0);
|
||||
ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTransform_DeleteInputStream(transform, 1);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
input_count = output_count = 0;
|
||||
hr = IMFTransform_GetStreamCount(transform, &input_count, &output_count);
|
||||
ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr);
|
||||
ok(input_count == 15 && output_count == 1, "Unexpected stream count %u/%u.\n", input_count, output_count);
|
||||
|
||||
IMFTransform_Release(transform);
|
||||
|
||||
hr = MFCreateVideoMixer(NULL, &IID_IMFTransform, &IID_IMFTransform, (void **)&transform);
|
||||
|
|
Loading…
Reference in New Issue