[PATCH 4/4] mfmediaengine: Initial impementation of TransferVideoFrame() for ID3D11Texture2D destination.

Nikolay Sivov nsivov at codeweavers.com
Mon May 17 04:26:51 CDT 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfmediaengine/Makefile.in |   2 +-
 dlls/mfmediaengine/main.c      | 535 ++++++++++++++++++++++++++++++++-
 2 files changed, 531 insertions(+), 6 deletions(-)

diff --git a/dlls/mfmediaengine/Makefile.in b/dlls/mfmediaengine/Makefile.in
index 0a498a00bcd..7bcb274e335 100644
--- a/dlls/mfmediaengine/Makefile.in
+++ b/dlls/mfmediaengine/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = mfmediaengine.dll
 IMPORTLIB = mfmediaengine
-IMPORTS = oleaut32 ole32 mfplat mf mfuuid uuid
+IMPORTS = oleaut32 ole32 mfplat mf mfuuid dxguid uuid
 
 EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native
 
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c
index 086886ab255..4f01f6ddada 100644
--- a/dlls/mfmediaengine/main.c
+++ b/dlls/mfmediaengine/main.c
@@ -28,6 +28,7 @@
 #include "mfmediaengine.h"
 #include "mferror.h"
 #include "dxgi.h"
+#include "d3d11.h"
 
 #include "wine/debug.h"
 
@@ -82,6 +83,30 @@ enum media_engine_flags
     FLAGS_ENGINE_HAS_VIDEO = 0x1000,
     FLAGS_ENGINE_FIRST_FRAME = 0x2000,
     FLAGS_ENGINE_IS_ENDED = 0x4000,
+    FLAGS_ENGINE_NEW_FRAME = 0x8000,
+};
+
+struct vec3
+{
+    float x, y, z;
+};
+
+struct color
+{
+    float r, g, b, a;
+};
+
+static const struct vec3 fullquad[] =
+{
+    {-1.0f, -1.0f, 0.0f},
+    {-1.0f,  1.0f, 0.0f},
+    { 1.0f, -1.0f, 0.0f},
+    { 1.0f,  1.0f, 0.0f},
+};
+
+struct rect
+{
+    float left, top, right, bottom;
 };
 
 struct media_engine
@@ -118,10 +143,270 @@ struct media_engine
         BYTE *buffer;
         UINT buffer_size;
         DXGI_FORMAT output_format;
+
+        struct
+        {
+            ID3D11Buffer *vb;
+            ID3D11Buffer *ps_cb;
+            ID3D11Texture2D *source;
+            ID3D11ShaderResourceView *srv;
+            ID3D11SamplerState *sampler;
+            ID3D11InputLayout *input_layout;
+            ID3D11VertexShader *vs;
+            ID3D11PixelShader *ps;
+            struct vec3 quad[4];
+            struct
+            {
+                struct rect dst;
+                struct rect src;
+                struct color backcolor;
+            } cb;
+        } d3d11;
     } video_frame;
     CRITICAL_SECTION cs;
 };
 
+static void media_engine_release_video_frame_resources(struct media_engine *engine)
+{
+    if (engine->video_frame.d3d11.vb)
+        ID3D11Buffer_Release(engine->video_frame.d3d11.vb);
+    if (engine->video_frame.d3d11.ps_cb)
+        ID3D11Buffer_Release(engine->video_frame.d3d11.ps_cb);
+    if (engine->video_frame.d3d11.source)
+        ID3D11Texture2D_Release(engine->video_frame.d3d11.source);
+    if (engine->video_frame.d3d11.srv)
+        ID3D11ShaderResourceView_Release(engine->video_frame.d3d11.srv);
+    if (engine->video_frame.d3d11.sampler)
+        ID3D11SamplerState_Release(engine->video_frame.d3d11.sampler);
+    if (engine->video_frame.d3d11.input_layout)
+        ID3D11InputLayout_Release(engine->video_frame.d3d11.input_layout);
+    if (engine->video_frame.d3d11.vs)
+        ID3D11VertexShader_Release(engine->video_frame.d3d11.vs);
+    if (engine->video_frame.d3d11.ps)
+        ID3D11PixelShader_Release(engine->video_frame.d3d11.ps);
+
+    memset(&engine->video_frame.d3d11, 0, sizeof(engine->video_frame.d3d11));
+    memcpy(engine->video_frame.d3d11.quad, fullquad, sizeof(fullquad));
+}
+
+static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11Device **device)
+{
+    HRESULT hr;
+
+    if (!engine->device_manager)
+    {
+        FIXME("Device manager wasn't set.\n");
+        return E_UNEXPECTED;
+    }
+
+    if (!engine->device_handle)
+    {
+        if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
+        {
+            WARN("Failed to open device handle, hr %#x.\n", hr);
+            return hr;
+        }
+    }
+
+    hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
+            (void **)device, TRUE);
+    if (hr == MF_E_DXGI_NEW_VIDEO_DEVICE)
+    {
+        IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
+        engine->device_handle = NULL;
+
+        media_engine_release_video_frame_resources(engine);
+
+        if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
+        {
+            WARN("Failed to open a device handle, hr %#x.\n", hr);
+            return hr;
+        }
+        hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
+                (void **)device, TRUE);
+    }
+
+    return hr;
+}
+
+static void media_engine_unlock_d3d_device(struct media_engine *engine, ID3D11Device *device)
+{
+    ID3D11Device_Release(device);
+    IMFDXGIDeviceManager_UnlockDevice(engine->device_manager, engine->device_handle, FALSE);
+}
+
+static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engine *engine, ID3D11Device *device)
+{
+    static const D3D11_INPUT_ELEMENT_DESC layout_desc[] =
+    {
+        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+    };
+    static const DWORD vs_code[] =
+    {
+#if 0
+        float4 main(float4 position : POSITION) : SV_POSITION
+        {
+            return position;
+        }
+#endif
+        0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
+        0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
+        0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
+        0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
+        0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
+        0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
+        0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
+    };
+    static const DWORD ps_code[] =
+    {
+#if 0
+        Texture2D t;
+        SamplerState s;
+        float4 dst;
+        float4 src;
+        float4 backcolor;
+
+        float4 main(float4 position : SV_POSITION) : SV_TARGET
+        {
+            float2 p;
+
+            if (position.x < dst.x || position.x > dst.z) return backcolor;
+            if (position.y < dst.y || position.y > dst.w) return backcolor;
+            p.x = (position.x - dst.x) / (dst.z - dst.x);
+            p.y = 1.0f - (position.y - dst.y) / (dst.w - dst.y);
+            p.x = src.x + p.x * (src.z - src.x);
+            p.y = src.y + p.y * (src.w - src.y);
+            return t.Sample(s, p);
+        }
+#endif
+        0x43425844, 0x5892e3b1, 0x24c17f7c, 0x9999f143, 0x49667872, 0x00000001, 0x0000032c, 0x00000003,
+        0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
+        0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
+        0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
+        0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x00000290, 0x00000040,
+        0x000000a4, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
+        0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
+        0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
+        0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
+        0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
+        0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036,
+        0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031,
+        0x00100012, 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031,
+        0x00100022, 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c,
+        0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
+        0x00000000, 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e,
+        0x01000015, 0x09000000, 0x00100032, 0x00000000, 0x00101046, 0x00000000, 0x80208046, 0x00000041,
+        0x00000000, 0x00000000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041, 0x00000000,
+        0x00000000, 0x00208ea6, 0x00000000, 0x00000000, 0x0700000e, 0x00100032, 0x00000000, 0x00100046,
+        0x00000000, 0x00100ae6, 0x00000000, 0x08000000, 0x00100022, 0x00000000, 0x8010001a, 0x00000041,
+        0x00000000, 0x00004001, 0x3f800000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041,
+        0x00000000, 0x00000001, 0x00208ea6, 0x00000000, 0x00000001, 0x0a000032, 0x00100012, 0x00000001,
+        0x0010000a, 0x00000000, 0x0010002a, 0x00000000, 0x0020800a, 0x00000000, 0x00000001, 0x0a000032,
+        0x00100022, 0x00000001, 0x0010001a, 0x00000000, 0x0010003a, 0x00000000, 0x0020801a, 0x00000000,
+        0x00000001, 0x09000045, 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000,
+        0x00106000, 0x00000000, 0x0100003e,
+    };
+    D3D11_SUBRESOURCE_DATA resource_data;
+    D3D11_TEXTURE2D_DESC texture_desc;
+    D3D11_SAMPLER_DESC sampler_desc;
+    D3D11_BUFFER_DESC buffer_desc;
+    HRESULT hr;
+
+    if (engine->video_frame.d3d11.source)
+        return S_OK;
+
+    /* Default vertex buffer, updated on first transfer call. */
+    buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.quad);
+    buffer_desc.Usage = D3D11_USAGE_DEFAULT;
+    buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+    buffer_desc.CPUAccessFlags = 0;
+    buffer_desc.MiscFlags = 0;
+    buffer_desc.StructureByteStride = 0;
+
+    resource_data.pSysMem = engine->video_frame.d3d11.quad;
+    resource_data.SysMemPitch = 0;
+    resource_data.SysMemSlicePitch = 0;
+
+    if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
+    {
+        WARN("Failed to create a vertex buffer, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.cb);
+    buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+
+    if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
+    {
+        WARN("Failed to create a buffer, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    /* Source texture. */
+    texture_desc.Width = engine->video_frame.size.cx;
+    texture_desc.Height = engine->video_frame.size.cy;
+    texture_desc.MipLevels = 1;
+    texture_desc.ArraySize = 1;
+    texture_desc.Format = engine->video_frame.output_format;
+    texture_desc.SampleDesc.Count = 1;
+    texture_desc.SampleDesc.Quality = 0;
+    texture_desc.Usage = D3D11_USAGE_DEFAULT;
+    texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+    texture_desc.CPUAccessFlags = 0;
+    texture_desc.MiscFlags = 0;
+
+    if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
+    {
+        WARN("Failed to create source texture, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
+            NULL, &engine->video_frame.d3d11.srv)))
+    {
+        WARN("Failed to create SRV, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    /* Sampler state. */
+    memset(&sampler_desc, 0, sizeof(sampler_desc));
+    sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+    sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+    sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+    sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+
+    if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
+    {
+        WARN("Failed to create a sampler state, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    /* Input layout */
+    if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
+            &engine->video_frame.d3d11.input_layout)))
+    {
+        WARN("Failed to create input layout, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    /* Shaders */
+    if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
+    {
+        WARN("Failed to create the vertex shader, hr %#x.\n", hr);
+        goto failed;
+    }
+
+    if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
+    {
+        WARN("Failed to create the pixel shader, hr %#x.\n", hr);
+        goto failed;
+    }
+
+failed:
+
+    return hr;
+}
+
 struct range
 {
     double start;
@@ -762,7 +1047,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
     UINT64 duration;
     HRESULT hr;
 
-    memset(&engine->video_frame, 0, sizeof(engine->video_frame));
+    media_engine_release_video_frame_resources(engine);
 
     if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
         return hr;
@@ -979,6 +1264,7 @@ static void free_media_engine(struct media_engine *engine)
         IMFAttributes_Release(engine->attributes);
     if (engine->resolver)
         IMFSourceResolver_Release(engine->resolver);
+    media_engine_release_video_frame_resources(engine);
     if (engine->device_manager)
     {
         IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
@@ -1638,13 +1924,249 @@ static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngine *iface)
     return hr;
 }
 
+static void set_rect(struct rect *rect, float left, float top, float right, float bottom)
+{
+    rect->left = left;
+    rect->top = top;
+    rect->right = right;
+    rect->bottom = bottom;
+}
+
+static void media_engine_adjust_destination_for_ratio(const struct media_engine *engine,
+        struct rect *src_n, struct rect *dst)
+{
+    float dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
+    D3D11_TEXTURE2D_DESC source_desc;
+    float src_width, src_height;
+    struct rect src;
+
+    ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &source_desc);
+    set_rect(&src, src_n->left * source_desc.Width, src_n->top * source_desc.Height,
+            src_n->right * source_desc.Width, src_n->bottom * source_desc.Height);
+
+    src_width = src.right - src.left;
+    src_height = src.bottom - src.top;
+
+    if (src_width * dst_height > dst_width * src_height)
+    {
+        /* src is "wider" than dst. */
+        float dst_center = (dst->top + dst->bottom) / 2.0f;
+        float scaled_height = src_height * dst_width / src_width;
+
+        dst->top = dst_center - scaled_height / 2.0f;
+        dst->bottom = dst->top + scaled_height;
+    }
+    else if (src_width * dst_height < dst_width * src_height)
+    {
+        /* src is "taller" than dst. */
+        float dst_center = (dst->left + dst->right) / 2.0f;
+        float scaled_width = src_width * dst_height / src_height;
+
+        dst->left = dst_center - scaled_width / 2.0f;
+        dst->right = dst->left + scaled_width;
+    }
+}
+
+static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine)
+{
+    D3D11_TEXTURE2D_DESC surface_desc;
+
+    if (!(engine->flags & FLAGS_ENGINE_NEW_FRAME))
+        return;
+
+    ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &surface_desc);
+
+    switch (surface_desc.Format)
+    {
+    case DXGI_FORMAT_B8G8R8A8_UNORM:
+        surface_desc.Width *= 4;
+        break;
+    default:
+        FIXME("Unsupported format %#x.\n", surface_desc.Format);
+        surface_desc.Width = 0;
+    }
+
+    if (engine->video_frame.buffer_size == surface_desc.Width * surface_desc.Height)
+    {
+        ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.source,
+                0, NULL, engine->video_frame.buffer, surface_desc.Width, 0);
+    }
+
+    media_engine_set_flag(engine, FLAGS_ENGINE_NEW_FRAME, FALSE);
+}
+
+static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture,
+        const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
+{
+    static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
+    ID3D11Device *device, *dst_device;
+    ID3D11DeviceContext *context;
+    ID3D11RenderTargetView *rtv;
+    unsigned int stride, offset;
+    D3D11_TEXTURE2D_DESC desc;
+    BOOL device_mismatch;
+    struct vec3 quad[4];
+    D3D11_VIEWPORT vp;
+    struct rect src, dst;
+    struct color backcolor;
+    HRESULT hr;
+    RECT rect;
+
+    if (FAILED(hr = media_engine_lock_d3d_device(engine, &device)))
+        return hr;
+
+    if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
+    {
+        WARN("Failed to create d3d resources, hr %#x.\n", hr);
+        goto done;
+    }
+
+    ID3D11Texture2D_GetDevice(texture, &dst_device);
+    device_mismatch = device != dst_device;
+    ID3D11Device_Release(dst_device);
+
+    if (device_mismatch)
+    {
+        WARN("Destination target from different device.\n");
+        hr = E_UNEXPECTED;
+        goto done;
+    }
+
+    ID3D11Texture2D_GetDesc(texture, &desc);
+
+    if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
+    {
+        WARN("Failed to create an rtv, hr %#x.\n", hr);
+        goto done;
+    }
+
+    ID3D11Device_GetImmediateContext(device, &context);
+
+    /* Whole destination is cleared, regardless of specified rectangle. */
+    ID3D11DeviceContext_ClearRenderTargetView(context, rtv, black);
+
+    if (dst_rect)
+    {
+        rect.left = max(0, dst_rect->left);
+        rect.top = max(0, dst_rect->top);
+        rect.right = min(desc.Width, dst_rect->right);
+        rect.bottom = min(desc.Height, dst_rect->bottom);
+
+        quad[0].x = 2.0f * rect.left / desc.Width - 1.0f;
+        quad[0].y = -2.0f * rect.bottom / desc.Height + 1.0f;
+
+        quad[1].x = quad[0].x;
+        quad[1].y = -2.0f * rect.top / desc.Height + 1.0f;
+
+        quad[2].x = 2.0f * rect.right / desc.Width - 1.0f;
+        quad[2].y = quad[0].y;
+
+        quad[3].x = quad[2].x;
+        quad[3].y = quad[1].y;
+
+        set_rect(&dst, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom);
+    }
+    else
+    {
+        memcpy(quad, fullquad, sizeof(quad));
+        set_rect(&dst, 0.0f, 0.0f, desc.Width, desc.Height);
+    }
+
+    if (src_rect)
+        memcpy(&src, src_rect, sizeof(src));
+    else
+        set_rect(&src, 0.0f, 0.0f, 1.0f, 1.0f);
+
+    media_engine_adjust_destination_for_ratio(engine, &src, &dst);
+
+    if (memcmp(quad, engine->video_frame.d3d11.quad, sizeof(quad)))
+    {
+        memcpy(engine->video_frame.d3d11.quad, quad, sizeof(quad));
+        ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.vb, 0, NULL, quad, 0, 0);
+    }
+
+    if (color)
+    {
+        backcolor.r = color->rgbRed / 255.0f;
+        backcolor.g = color->rgbGreen / 255.0f;
+        backcolor.b = color->rgbBlue / 255.0f;
+        backcolor.a = color->rgbAlpha / 255.0f;
+    }
+    else
+        memcpy(&backcolor, black, sizeof(backcolor));
+
+    if (memcmp(&dst, &engine->video_frame.d3d11.cb.dst, sizeof(dst)) ||
+            memcmp(&src, &engine->video_frame.d3d11.cb.src, sizeof(src)) ||
+            memcmp(&backcolor, &engine->video_frame.d3d11.cb.backcolor, sizeof(backcolor)))
+    {
+        memcpy(&engine->video_frame.d3d11.cb.dst, &dst, sizeof(dst));
+        memcpy(&engine->video_frame.d3d11.cb.src, &src, sizeof(src));
+        memcpy(&engine->video_frame.d3d11.cb.backcolor, &backcolor, sizeof(backcolor));
+
+        ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.ps_cb, 0, NULL,
+                &engine->video_frame.d3d11.cb, 0, 0);
+    }
+
+    /* Update with new frame contents */
+    media_engine_update_d3d11_frame_surface(context, engine);
+
+    vp.TopLeftX = 0.0f;
+    vp.TopLeftY = 0.0f;
+    vp.Width = desc.Width;
+    vp.Height = desc.Height;
+    vp.MinDepth = 0.0f;
+    vp.MaxDepth = 1.0f;
+    ID3D11DeviceContext_RSSetViewports(context, 1, &vp);
+
+    ID3D11DeviceContext_IASetInputLayout(context, engine->video_frame.d3d11.input_layout);
+    ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+    stride = sizeof(*quad);
+    offset = 0;
+    ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &engine->video_frame.d3d11.vb, &stride, &offset);
+    ID3D11DeviceContext_VSSetShader(context, engine->video_frame.d3d11.vs, NULL, 0);
+    ID3D11DeviceContext_PSSetShader(context, engine->video_frame.d3d11.ps, NULL, 0);
+    ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &engine->video_frame.d3d11.srv);
+    ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &engine->video_frame.d3d11.ps_cb);
+    ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &engine->video_frame.d3d11.sampler);
+    ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rtv, NULL);
+
+    ID3D11DeviceContext_Draw(context, 4, 0);
+
+    ID3D11RenderTargetView_Release(rtv);
+    ID3D11DeviceContext_Release(context);
+
+done:
+    media_engine_unlock_d3d_device(engine, device);
+
+    return hr;
+}
+
 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngine *iface, IUnknown *surface,
-                                                      const MFVideoNormalizedRect *src,
-                                                      const RECT *dst, const MFARGB *color)
+        const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
 {
-    FIXME("(%p, %p, %p, %p, %p): stub.\n", iface, surface, src, dst, color);
+    struct media_engine *engine = impl_from_IMFMediaEngine(iface);
+    ID3D11Texture2D *texture;
+    HRESULT hr = E_NOINTERFACE;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
+            src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)",
+            wine_dbgstr_rect(dst_rect), color);
+
+    EnterCriticalSection(&engine->cs);
+
+    if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
+    {
+        hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color);
+        ID3D11Texture2D_Release(texture);
+    }
+    else
+    {
+        FIXME("Unsupported destination type.\n");
+    }
+
+    LeaveCriticalSection(&engine->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngine *iface, LONGLONG *pts)
@@ -1811,7 +2333,10 @@ static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGra
             engine->video_frame.buffer_size = buffer_size;
     }
     if (engine->video_frame.buffer)
+    {
         memcpy(engine->video_frame.buffer, buffer, buffer_size);
+        engine->flags |= FLAGS_ENGINE_NEW_FRAME;
+    }
 
     LeaveCriticalSection(&engine->cs);
 
-- 
2.30.2




More information about the wine-devel mailing list