[PATCH 1/3] evr: Implement stream managment methods for default mixer.

Nikolay Sivov nsivov at codeweavers.com
Thu Jun 18 06:43:44 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/evr/mixer.c     | 178 +++++++++++++++++++++++++++++++++++++++----
 dlls/evr/tests/evr.c | 114 +++++++++++++++++++++++++++
 2 files changed, 276 insertions(+), 16 deletions(-)

diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c
index 3101d17ffdb..54ea156b35f 100644
--- a/dlls/evr/mixer.c
+++ b/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;
 
diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c
index 56fb1680b07..db20fa76643 100644
--- a/dlls/evr/tests/evr.c
+++ b/dlls/evr/tests/evr.c
@@ -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);
-- 
2.27.0




More information about the wine-devel mailing list