[PATCH 1/7] mfplat: Implement MFCreateDXSurfaceBuffer().

Nikolay Sivov nsivov at codeweavers.com
Fri Oct 30 08:50:41 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/buffer.c       | 308 +++++++++++++++++++++++++++++++++++++
 dlls/mfplat/mfplat.spec    |   1 +
 dlls/mfplat/tests/mfplat.c |  11 +-
 3 files changed, 319 insertions(+), 1 deletion(-)

diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index 5e969e14ec9..3d1d2abdf88 100644
--- a/dlls/mfplat/buffer.c
+++ b/dlls/mfplat/buffer.c
@@ -21,6 +21,10 @@
 #include "mfplat_private.h"
 #include "rtworkq.h"
 
+#include "initguid.h"
+#include "d3d9.h"
+#include "evr.h"
+
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -50,6 +54,11 @@ struct memory_buffer
 
         unsigned int locks;
     } _2d;
+    struct
+    {
+        IDirect3DSurface9 *surface;
+        D3DLOCKED_RECT rect;
+    } d3d9_surface;
 
     CRITICAL_SECTION cs;
 };
@@ -142,6 +151,8 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
 
     if (!refcount)
     {
+        if (buffer->d3d9_surface.surface)
+            IDirect3DSurface9_Release(buffer->d3d9_surface.surface);
         DeleteCriticalSection(&buffer->cs);
         heap_free(buffer->_2d.linear_buffer);
         heap_free(buffer->data);
@@ -333,6 +344,97 @@ static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl =
     memory_buffer_GetMaxLength,
 };
 
+static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length)
+{
+    struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length);
+
+    if (!data)
+        return E_POINTER;
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (!buffer->_2d.linear_buffer && buffer->_2d.locks)
+        hr = MF_E_INVALIDREQUEST;
+    else if (!buffer->_2d.linear_buffer)
+    {
+        D3DLOCKED_RECT rect;
+
+        if (!(buffer->_2d.linear_buffer = heap_alloc(ALIGN_SIZE(buffer->_2d.plane_size, MF_64_BYTE_ALIGNMENT))))
+            hr = E_OUTOFMEMORY;
+
+        if (SUCCEEDED(hr))
+        {
+            hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0);
+            if (SUCCEEDED(hr))
+            {
+                MFCopyImage(buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch,
+                        buffer->_2d.width, buffer->_2d.height);
+                IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
+            }
+        }
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        ++buffer->_2d.locks;
+        *data = buffer->_2d.linear_buffer;
+        if (max_length)
+            *max_length = buffer->_2d.plane_size;
+        if (current_length)
+            *current_length = buffer->_2d.plane_size;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3d9_surface_buffer_Unlock(IMFMediaBuffer *iface)
+{
+    struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p.\n", iface);
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (!buffer->_2d.linear_buffer)
+        hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
+    else if (!--buffer->_2d.locks)
+    {
+        D3DLOCKED_RECT rect;
+
+        if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0)))
+        {
+            MFCopyImage(rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width,
+                    buffer->_2d.width, buffer->_2d.height);
+            IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
+        }
+
+        heap_free(buffer->_2d.linear_buffer);
+        buffer->_2d.linear_buffer = NULL;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
+}
+
+static const IMFMediaBufferVtbl d3d9_surface_1d_buffer_vtbl =
+{
+    memory_1d_2d_buffer_QueryInterface,
+    memory_buffer_AddRef,
+    memory_buffer_Release,
+    d3d9_surface_buffer_Lock,
+    d3d9_surface_buffer_Unlock,
+    memory_buffer_GetCurrentLength,
+    memory_buffer_SetCurrentLength,
+    memory_buffer_GetMaxLength,
+};
+
 static HRESULT WINAPI memory_2d_buffer_QueryInterface(IMF2DBuffer2 *iface, REFIID riid, void **obj)
 {
     struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
@@ -521,6 +623,144 @@ static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl =
     memory_2d_buffer_Copy2DTo,
 };
 
+static HRESULT WINAPI d3d9_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
+{
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
+
+    if (!scanline0 || !pitch)
+        return E_POINTER;
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (buffer->_2d.linear_buffer)
+        hr = MF_E_UNEXPECTED;
+    else if (!buffer->_2d.locks++)
+    {
+        hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        *scanline0 = buffer->d3d9_surface.rect.pBits;
+        *pitch = buffer->d3d9_surface.rect.Pitch;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3d9_surface_buffer_Unlock2D(IMF2DBuffer2 *iface)
+{
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p.\n", iface);
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (buffer->_2d.locks)
+    {
+        if (!--buffer->_2d.locks)
+        {
+            IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
+            memset(&buffer->d3d9_surface.rect, 0, sizeof(buffer->d3d9_surface.rect));
+        }
+    }
+    else
+        hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3d9_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
+{
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
+
+    if (!scanline0 || !pitch)
+        return E_POINTER;
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (!buffer->_2d.locks)
+        hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
+    else
+    {
+        *scanline0 = buffer->d3d9_surface.rect.pBits;
+        *pitch = buffer->d3d9_surface.rect.Pitch;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3d9_surface_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length)
+{
+    FIXME("%p, %p.\n", iface, length);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3d9_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0,
+        LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
+{
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length);
+
+    if (!scanline0 || !pitch || !buffer_start || !buffer_length)
+        return E_POINTER;
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (buffer->_2d.linear_buffer)
+        hr = MF_E_UNEXPECTED;
+    else if (!buffer->_2d.locks++)
+    {
+        hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        *scanline0 = buffer->d3d9_surface.rect.pBits;
+        *pitch = buffer->d3d9_surface.rect.Pitch;
+        if (buffer_start)
+            *buffer_start = *scanline0;
+        if (buffer_length)
+            *buffer_length = buffer->d3d9_surface.rect.Pitch * buffer->_2d.height;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
+}
+
+static const IMF2DBuffer2Vtbl d3d9_surface_buffer_vtbl =
+{
+    memory_2d_buffer_QueryInterface,
+    memory_2d_buffer_AddRef,
+    memory_2d_buffer_Release,
+    d3d9_surface_buffer_Lock2D,
+    d3d9_surface_buffer_Unlock2D,
+    d3d9_surface_buffer_GetScanline0AndPitch,
+    memory_2d_buffer_IsContiguousFormat,
+    d3d9_surface_buffer_GetContiguousLength,
+    memory_2d_buffer_ContiguousCopyTo,
+    memory_2d_buffer_ContiguousCopyFrom,
+    d3d9_surface_buffer_Lock2DSize,
+    memory_2d_buffer_Copy2DTo,
+};
+
 static HRESULT WINAPI memory_2d_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
 {
     struct memory_buffer *buffer = impl_from_IMFGetService(iface);
@@ -554,6 +794,28 @@ static const IMFGetServiceVtbl memory_2d_buffer_gs_vtbl =
     memory_2d_buffer_gs_GetService,
 };
 
+static HRESULT WINAPI d3d9_surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
+{
+    struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+
+    TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
+
+    if (IsEqualGUID(service, &MR_BUFFER_SERVICE))
+    {
+        return IDirect3DSurface9_QueryInterface(buffer->d3d9_surface.surface, riid, obj);
+    }
+
+    return E_NOTIMPL;
+}
+
+static const IMFGetServiceVtbl d3d9_surface_buffer_gs_vtbl =
+{
+    memory_2d_buffer_gs_QueryInterface,
+    memory_2d_buffer_gs_AddRef,
+    memory_2d_buffer_gs_Release,
+    d3d9_surface_buffer_gs_GetService,
+};
+
 static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment,
         const IMFMediaBufferVtbl *vtbl)
 {
@@ -675,6 +937,36 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo
     return S_OK;
 }
 
+static HRESULT create_d3d9_surface_buffer(IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer)
+{
+    struct memory_buffer *object;
+    D3DSURFACE_DESC desc;
+
+    object = heap_alloc_zero(sizeof(*object));
+    if (!object)
+        return E_OUTOFMEMORY;
+
+    object->IMFMediaBuffer_iface.lpVtbl = &d3d9_surface_1d_buffer_vtbl;
+    object->IMF2DBuffer2_iface.lpVtbl = &d3d9_surface_buffer_vtbl;
+    object->IMFGetService_iface.lpVtbl = &d3d9_surface_buffer_gs_vtbl;
+    object->refcount = 1;
+    InitializeCriticalSection(&object->cs);
+    object->d3d9_surface.surface = (IDirect3DSurface9 *)surface;
+    IUnknown_AddRef(surface);
+
+    IDirect3DSurface9_GetDesc(object->d3d9_surface.surface, &desc);
+    TRACE("format %#x, %u x %u.\n", desc.Format, desc.Width, desc.Height);
+
+    MFGetPlaneSize(desc.Format, desc.Width, desc.Height, &object->_2d.plane_size);
+    object->_2d.width = desc.Width;
+    object->_2d.height = desc.Height;
+    object->max_length = object->_2d.plane_size;
+
+    *buffer = &object->IMFMediaBuffer_iface;
+
+    return S_OK;
+}
+
 /***********************************************************************
  *      MFCreateMemoryBuffer (mfplat.@)
  */
@@ -695,6 +987,9 @@ HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IM
     return create_1d_buffer(max_length, alignment, buffer);
 }
 
+/***********************************************************************
+ *      MFCreate2DMediaBuffer (mfplat.@)
+ */
 HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
 {
     TRACE("%u, %u, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer);
@@ -702,6 +997,19 @@ HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BO
     return create_2d_buffer(width, height, fourcc, bottom_up, buffer);
 }
 
+/***********************************************************************
+ *      MFCreateDXSurfaceBuffer (mfplat.@)
+ */
+HRESULT WINAPI MFCreateDXSurfaceBuffer(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer)
+{
+    TRACE("%s, %p, %d, %p.\n", debugstr_guid(riid), surface, bottom_up, buffer);
+
+    if (!IsEqualIID(riid, &IID_IDirect3DSurface9))
+        return E_INVALIDARG;
+
+    return create_d3d9_surface_buffer(surface, bottom_up, buffer);
+}
+
 static unsigned int buffer_get_aligned_length(unsigned int length, unsigned int alignment)
 {
     length = (length + alignment) / alignment;
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 5f4735cd6f7..80064e1980e 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -46,6 +46,7 @@
 @ stub MFCreateAudioMediaType
 @ stdcall MFCreateCollection(ptr)
 @ stdcall MFCreateDXGIDeviceManager(ptr ptr)
+@ stdcall MFCreateDXSurfaceBuffer(ptr ptr long ptr)
 @ stdcall MFCreateEventQueue(ptr)
 @ stdcall MFCreateFile(long long long wstr ptr)
 @ stub MFCreateLegacyMediaBufferOnMFMediaBuffer
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 8c6cbf74661..711a712da0d 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -5649,7 +5649,7 @@ static void test_MFCreateDXSurfaceBuffer(void)
 
     if (!pMFCreateDXSurfaceBuffer)
     {
-        skip("MFCreateDXSurfaceBuffer is not available.\n");
+        win_skip("MFCreateDXSurfaceBuffer is not available.\n");
         return;
     }
 
@@ -5671,6 +5671,9 @@ static void test_MFCreateDXSurfaceBuffer(void)
 
     IDirect3DSwapChain9_Release(swapchain);
 
+    hr = pMFCreateDXSurfaceBuffer(&IID_IUnknown, (IUnknown *)backbuffer, FALSE, &buffer);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
     hr = pMFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)backbuffer, FALSE, &buffer);
     ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
 
@@ -5764,6 +5767,12 @@ static void test_MFCreateDXSurfaceBuffer(void)
     ok(data[0] == 0xab, "Unexpected leading byte.\n");
     IMF2DBuffer2_Unlock2D(_2dbuffer2);
 
+    hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(data[0] == 0xab, "Unexpected leading byte.\n");
+    hr = IMFMediaBuffer_Unlock(buffer);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
     hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length);
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
     IMF2DBuffer2_Unlock2D(_2dbuffer2);
-- 
2.28.0




More information about the wine-devel mailing list