[PATCH 5/5] mfplat: Implement locking methods for 2D memory buffers.

Nikolay Sivov nsivov at codeweavers.com
Mon Mar 16 04:17:08 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/buffer.c         | 229 +++++++++++++++++++++++++++++++----
 dlls/mfplat/mediatype.c      |  54 +++++----
 dlls/mfplat/mfplat_private.h |   2 +-
 dlls/mfplat/tests/mfplat.c   | 193 ++++++++++++++++++++++++++++-
 4 files changed, 427 insertions(+), 51 deletions(-)

diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index b1d353a59b..69633134f5 100644
--- a/dlls/mfplat/buffer.c
+++ b/dlls/mfplat/buffer.c
@@ -35,6 +35,21 @@ struct memory_buffer
     BYTE *data;
     DWORD max_length;
     DWORD current_length;
+
+    struct
+    {
+        BYTE *linear_buffer;
+        unsigned int plane_size;
+
+        BYTE *scanline0;
+        unsigned int width;
+        unsigned int height;
+        int pitch;
+
+        unsigned int locks;
+    } _2d;
+
+    CRITICAL_SECTION cs;
 };
 
 enum sample_prop_flags
@@ -113,6 +128,8 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
 
     if (!refcount)
     {
+        DeleteCriticalSection(&buffer->cs);
+        heap_free(buffer->_2d.linear_buffer);
         heap_free(buffer->data);
         heap_free(buffer);
     }
@@ -226,13 +243,73 @@ static HRESULT WINAPI memory_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface,
     return S_OK;
 }
 
+static HRESULT WINAPI memory_1d_2d_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;
+
+    /* Allocate linear buffer and return it as a copy of current content. Maximum and current length are
+       unrelated to 2D buffer maximum allocate length, or maintained current length. */
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (!buffer->_2d.linear_buffer && buffer->_2d.locks)
+        hr = MF_E_INVALIDREQUEST;
+    else if (!buffer->_2d.linear_buffer)
+    {
+        if (!(buffer->_2d.linear_buffer = heap_alloc(ALIGN_SIZE(buffer->_2d.plane_size, 64))))
+            hr = E_OUTOFMEMORY;
+    }
+
+    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 memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface)
+{
+    struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
+
+    TRACE("%p.\n", iface);
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (buffer->_2d.linear_buffer && !--buffer->_2d.locks)
+    {
+        MFCopyImage(buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width,
+                buffer->_2d.width, buffer->_2d.height);
+
+        heap_free(buffer->_2d.linear_buffer);
+        buffer->_2d.linear_buffer = NULL;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return S_OK;
+}
+
 static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl =
 {
     memory_1d_2d_buffer_QueryInterface,
     memory_buffer_AddRef,
     memory_buffer_Release,
-    memory_buffer_Lock,
-    memory_buffer_Unlock,
+    memory_1d_2d_buffer_Lock,
+    memory_1d_2d_buffer_Unlock,
     memory_buffer_GetCurrentLength,
     memory_buffer_SetCurrentLength,
     memory_buffer_GetMaxLength,
@@ -256,39 +333,117 @@ static ULONG WINAPI memory_2d_buffer_Release(IMF2DBuffer2 *iface)
     return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
 }
 
+static HRESULT memory_2d_buffer_lock(struct memory_buffer *buffer, BYTE **scanline0, LONG *pitch,
+        BYTE **buffer_start, DWORD *buffer_length)
+{
+    HRESULT hr = S_OK;
+
+    if (buffer->_2d.linear_buffer)
+        hr = MF_E_UNEXPECTED;
+    else
+    {
+        ++buffer->_2d.locks;
+        *scanline0 = buffer->data;
+        *pitch = buffer->_2d.pitch;
+        if (buffer_start)
+            *buffer_start = buffer->data;
+        if (buffer_length)
+            *buffer_length = buffer->max_length;
+    }
+
+    return hr;
+}
+
 static HRESULT WINAPI memory_2d_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
 {
-    FIXME("%p, %p, %p.\n", iface, scanline0, pitch);
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
+
+    if (!scanline0 || !pitch)
+        return E_POINTER;
+
+    EnterCriticalSection(&buffer->cs);
+
+    hr = memory_2d_buffer_lock(buffer, scanline0, pitch, NULL, NULL);
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI memory_2d_buffer_Unlock2D(IMF2DBuffer2 *iface)
 {
-    FIXME("%p.\n", iface);
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr = S_OK;
 
-    return E_NOTIMPL;
+    TRACE("%p.\n", iface);
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (!buffer->_2d.linear_buffer)
+    {
+        if (buffer->_2d.locks)
+            --buffer->_2d.locks;
+        else
+            hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI memory_2d_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
 {
-    FIXME("%p, %p, %p.\n", iface, scanline0, pitch);
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr = S_OK;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
+
+    if (!scanline0 || !pitch)
+        return E_POINTER;
+
+    EnterCriticalSection(&buffer->cs);
+
+    if (buffer->_2d.linear_buffer || !buffer->_2d.locks)
+        hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
+    else
+    {
+        *scanline0 = buffer->_2d.scanline0;
+        *pitch = buffer->_2d.pitch;
+    }
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI memory_2d_buffer_IsContiguousFormat(IMF2DBuffer2 *iface, BOOL *is_contiguous)
 {
-    FIXME("%p, %p.\n", iface, is_contiguous);
+    TRACE("%p, %p.\n", iface, is_contiguous);
 
-    return E_NOTIMPL;
+    if (!is_contiguous)
+        return E_POINTER;
+
+    *is_contiguous = FALSE;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI memory_2d_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length)
 {
-    FIXME("%p, %p.\n", iface, length);
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, length);
+
+    if (!length)
+        return E_POINTER;
+
+    *length = buffer->_2d.plane_size;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYTE *dest_buffer, DWORD dest_length)
@@ -308,9 +463,21 @@ static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, c
 static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0,
         LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
 {
-    FIXME("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length);
+    struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    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);
+
+    hr = memory_2d_buffer_lock(buffer, scanline0, pitch, buffer_start, buffer_length);
+
+    LeaveCriticalSection(&buffer->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dest_buffer)
@@ -347,6 +514,7 @@ static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length
     buffer->refcount = 1;
     buffer->max_length = max_length;
     buffer->current_length = 0;
+    InitializeCriticalSection(&buffer->cs);
 
     return S_OK;
 }
@@ -377,12 +545,14 @@ static HRESULT create_1d_buffer(DWORD max_length, DWORD alignment, IMFMediaBuffe
     return S_OK;
 }
 
-static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, IMFMediaBuffer **buffer)
+static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
 {
+    unsigned int bpp, max_length, plane_size;
     struct memory_buffer *object;
-    unsigned int bpp, max_length;
     GUID subtype;
+    BOOL is_yuv;
     HRESULT hr;
+    int pitch;
 
     if (!buffer)
         return E_POINTER;
@@ -392,30 +562,43 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, IMFMedi
     memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
     subtype.Data1 = fourcc;
 
-    if (!(bpp = mf_format_get_bpp(&subtype)))
+    if (!(bpp = mf_format_get_bpp(&subtype, &is_yuv)))
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (is_yuv && bottom_up)
         return MF_E_INVALIDMEDIATYPE;
 
+    if (FAILED(hr = MFGetPlaneSize(fourcc, width, height, &plane_size)))
+        return hr;
+
     object = heap_alloc_zero(sizeof(*object));
     if (!object)
         return E_OUTOFMEMORY;
 
+    pitch = ALIGN_SIZE(width * bpp, 64);
+
     switch (fourcc)
     {
         case MAKEFOURCC('N','V','1','2'):
-            max_length = ALIGN_SIZE(width * bpp, 64) * height * 3 / 2;
+            max_length = pitch * height * 3 / 2;
             break;
         default:
-            max_length = ALIGN_SIZE(width * bpp, 64) * height;
+            max_length = pitch * height;
     }
 
-    hr = memory_buffer_init(object, max_length, MF_1_BYTE_ALIGNMENT, &memory_1d_2d_buffer_vtbl);
-    object->IMF2DBuffer2_iface.lpVtbl = &memory_2d_buffer_vtbl;
-    if (FAILED(hr))
+    if (FAILED(hr = memory_buffer_init(object, max_length, MF_1_BYTE_ALIGNMENT, &memory_1d_2d_buffer_vtbl)))
     {
         heap_free(object);
         return hr;
     }
 
+    object->IMF2DBuffer2_iface.lpVtbl = &memory_2d_buffer_vtbl;
+    object->_2d.plane_size = plane_size;
+    object->_2d.width = width * bpp;
+    object->_2d.height = height;
+    object->_2d.pitch = bottom_up ? -pitch : pitch;
+    object->_2d.scanline0 = bottom_up ? object->data + object->_2d.width * (object->_2d.height - 1) : object->data;
+
     *buffer = &object->IMFMediaBuffer_iface;
 
     return S_OK;
@@ -445,7 +628,7 @@ HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BO
 {
     TRACE("%u, %u, %#x, %d, %p.\n", width, height, fourcc, bottom_up, buffer);
 
-    return create_2d_buffer(width, height, fourcc, buffer);
+    return create_2d_buffer(width, height, fourcc, bottom_up, buffer);
 }
 
 static unsigned int buffer_get_aligned_length(unsigned int length, unsigned int alignment)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c
index d764baf0b9..142ee69cf6 100644
--- a/dlls/mfplat/mediatype.c
+++ b/dlls/mfplat/mediatype.c
@@ -1768,9 +1768,10 @@ HRESULT WINAPI MFCreatePresentationDescriptor(DWORD count, IMFStreamDescriptor *
 struct uncompressed_video_format
 {
     const GUID *subtype;
-    unsigned int bytes_per_pixel;
-    unsigned int alignment;
-    BOOL bottom_up;
+    unsigned char bytes_per_pixel;
+    unsigned char alignment;
+    unsigned char bottom_up;
+    unsigned char yuv;
 };
 
 static int __cdecl uncompressed_video_format_compare(const void *a, const void *b)
@@ -1782,24 +1783,24 @@ static int __cdecl uncompressed_video_format_compare(const void *a, const void *
 
 static const struct uncompressed_video_format video_formats[] =
 {
-    { &MFVideoFormat_RGB24,         3, 3, 1 },
-    { &MFVideoFormat_ARGB32,        4, 3, 1 },
-    { &MFVideoFormat_RGB32,         4, 3, 1 },
-    { &MFVideoFormat_RGB565,        2, 3, 1 },
-    { &MFVideoFormat_RGB555,        2, 3, 1 },
-    { &MFVideoFormat_A2R10G10B10,   4, 3, 1 },
-    { &MFVideoFormat_RGB8,          1, 3, 1 },
-    { &MFVideoFormat_L8,            1, 3, 1 },
-    { &MFVideoFormat_AYUV,          4, 3, 0 },
-    { &MFVideoFormat_IMC1,          2, 3, 0 },
-    { &MFVideoFormat_IMC2,          1, 0, 0 },
-    { &MFVideoFormat_IMC3,          2, 3, 0 },
-    { &MFVideoFormat_IMC4,          1, 0, 0 },
-    { &MFVideoFormat_NV12,          1, 0, 0 },
-    { &MFVideoFormat_D16,           2, 3, 0 },
-    { &MFVideoFormat_L16,           2, 3, 0 },
-    { &MFVideoFormat_YV12,          1, 0, 0 },
-    { &MFVideoFormat_A16B16G16R16F, 8, 3, 1 },
+    { &MFVideoFormat_RGB24,         3, 3, 1, 0 },
+    { &MFVideoFormat_ARGB32,        4, 3, 1, 0 },
+    { &MFVideoFormat_RGB32,         4, 3, 1, 0 },
+    { &MFVideoFormat_RGB565,        2, 3, 1, 0 },
+    { &MFVideoFormat_RGB555,        2, 3, 1, 0 },
+    { &MFVideoFormat_A2R10G10B10,   4, 3, 1, 0 },
+    { &MFVideoFormat_RGB8,          1, 3, 1, 0 },
+    { &MFVideoFormat_L8,            1, 3, 1, 0 },
+    { &MFVideoFormat_AYUV,          4, 3, 0, 1 },
+    { &MFVideoFormat_IMC1,          2, 3, 0, 1 },
+    { &MFVideoFormat_IMC2,          1, 0, 0, 1 },
+    { &MFVideoFormat_IMC3,          2, 3, 0, 1 },
+    { &MFVideoFormat_IMC4,          1, 0, 0, 1 },
+    { &MFVideoFormat_NV12,          1, 0, 0, 1 },
+    { &MFVideoFormat_D16,           2, 3, 0, 0 },
+    { &MFVideoFormat_L16,           2, 3, 0, 0 },
+    { &MFVideoFormat_YV12,          1, 0, 0, 1 },
+    { &MFVideoFormat_A16B16G16R16F, 8, 3, 1, 0 },
 };
 
 static struct uncompressed_video_format *mf_get_video_format(const GUID *subtype)
@@ -1813,10 +1814,17 @@ static unsigned int mf_get_stride_for_format(const struct uncompressed_video_for
     return (width * format->bytes_per_pixel + format->alignment) & ~format->alignment;
 }
 
-unsigned int mf_format_get_bpp(const GUID *subtype)
+unsigned int mf_format_get_bpp(const GUID *subtype, BOOL *is_yuv)
 {
     struct uncompressed_video_format *format = mf_get_video_format(subtype);
-    return format ? format->bytes_per_pixel : 0;
+
+    if (format)
+    {
+        *is_yuv = format->yuv;
+        return format->bytes_per_pixel;
+    }
+
+    return 0;
 }
 
 /***********************************************************************
diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h
index d68a8ed550..0c374f116b 100644
--- a/dlls/mfplat/mfplat_private.h
+++ b/dlls/mfplat/mfplat_private.h
@@ -114,7 +114,7 @@ static inline BOOL mf_array_reserve(void **elements, size_t *capacity, size_t co
     return TRUE;
 }
 
-extern unsigned int mf_format_get_bpp(const GUID *subtype) DECLSPEC_HIDDEN;
+extern unsigned int mf_format_get_bpp(const GUID *subtype, BOOL *is_yuv) DECLSPEC_HIDDEN;
 
 static inline const char *debugstr_propvar(const PROPVARIANT *v)
 {
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 621b5b4393..bf63337b60 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -41,6 +41,7 @@
 #define D3D11_INIT_GUID
 #include "initguid.h"
 #include "d3d11_4.h"
+#include "d3d9types.h"
 
 DEFINE_GUID(DUMMY_CLSID, 0x12345678,0x1234,0x1234,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19);
 DEFINE_GUID(DUMMY_GUID1, 0x12345678,0x1234,0x1234,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21);
@@ -4599,11 +4600,31 @@ static void test_MFGetStrideForBitmapInfoHeader(void)
 
 static void test_MFCreate2DMediaBuffer(void)
 {
+    static const struct _2d_buffer_test
+    {
+        unsigned int width;
+        unsigned int height;
+        unsigned int fourcc;
+        unsigned int contiguous_length;
+    } _2d_buffer_tests[] =
+    {
+        { 2, 2, MAKEFOURCC('N','V','1','2'), 6 },
+        { 4, 2, MAKEFOURCC('N','V','1','2'), 12 },
+        { 2, 4, MAKEFOURCC('N','V','1','2'), 12 },
+        { 1, 3, MAKEFOURCC('N','V','1','2'), 4 },
+
+        { 2, 4, D3DFMT_A8R8G8B8, 32 },
+        { 1, 4, D3DFMT_A8R8G8B8, 16 },
+        { 4, 1, D3DFMT_A8R8G8B8, 16 },
+    };
+    unsigned int max_length, length, length2;
+    BYTE *buffer_start, *data, *data2;
     IMF2DBuffer2 *_2dbuffer2;
     IMF2DBuffer *_2dbuffer;
     IMFMediaBuffer *buffer;
-    DWORD length;
+    int i, pitch;
     HRESULT hr;
+    BOOL ret;
 
     if (!pMFCreate2DMediaBuffer)
     {
@@ -4617,26 +4638,190 @@ static void test_MFCreate2DMediaBuffer(void)
     hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('N','V','1','2'), FALSE, NULL);
     ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
 
+    /* YUV formats can't be bottom-up. */
+    hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('N','V','1','2'), TRUE, &buffer);
+    ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr);
+
     hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('N','V','1','2'), FALSE, &buffer);
     ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
 
-    hr = IMFMediaBuffer_GetMaxLength(buffer, &length);
+    /* Full backing buffer size, with 64 bytes per row alignment.  */
+    hr = IMFMediaBuffer_GetMaxLength(buffer, &max_length);
     ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
-    ok(length > 0, "Unexpected length.\n");
+    ok(max_length > 0, "Unexpected length %u.\n", max_length);
+
+    hr = IMFMediaBuffer_GetCurrentLength(buffer, &length);
+    ok(hr == S_OK, "Failed to get current length, hr %#x.\n", hr);
+    ok(!length, "Unexpected length.\n");
+
+    hr = IMFMediaBuffer_SetCurrentLength(buffer, 10);
+    ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr);
+
+    hr = IMFMediaBuffer_GetCurrentLength(buffer, &length);
+    ok(hr == S_OK, "Failed to get current length, hr %#x.\n", hr);
+    ok(length == 10, "Unexpected length.\n");
+
+    /* Linear lock/unlock. */
+
+    hr = IMFMediaBuffer_Lock(buffer, NULL, &max_length, &length);
+    ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+
+    /* Linear locking call returns plane size.*/
+    hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &length);
+    ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+    ok(max_length == length, "Unexpected length.\n");
+
+    length = 0;
+    pMFGetPlaneSize(MAKEFOURCC('N','V','1','2'), 2, 3, &length);
+    ok(max_length == length && length == 9, "Unexpected length %u.\n", length);
+
+    /* Already locked */
+    hr = IMFMediaBuffer_Lock(buffer, &data2, NULL, NULL);
+    ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+    ok(data2 == data, "Unexpected pointer.\n");
+
+    hr = IMFMediaBuffer_Unlock(buffer);
+    ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
 
     hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2dbuffer);
     ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
-    IMF2DBuffer_Release(_2dbuffer);
+
+    hr = IMF2DBuffer_GetContiguousLength(_2dbuffer, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_GetContiguousLength(_2dbuffer, &length);
+    ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
+    ok(length == 9, "Unexpected length %u.\n", length);
+
+    hr = IMF2DBuffer_IsContiguousFormat(_2dbuffer, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    /* 2D lock. */
+    hr = IMF2DBuffer_Lock2D(_2dbuffer, &data, &pitch);
+    ok(hr == MF_E_UNEXPECTED, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_GetScanline0AndPitch(_2dbuffer, &data, &pitch);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#x.\n", hr);
+
+    hr = IMFMediaBuffer_Unlock(buffer);
+    ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_GetScanline0AndPitch(_2dbuffer, &data, &pitch);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Lock2D(_2dbuffer, NULL, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Lock2D(_2dbuffer, &data, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Lock2D(_2dbuffer, NULL, &pitch);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Lock2D(_2dbuffer, &data, &pitch);
+    ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+    ok(!!data, "Expected data pointer.\n");
+    ok(pitch == 64, "Unexpected pitch %d.\n", pitch);
+
+    hr = IMF2DBuffer_Lock2D(_2dbuffer, &data2, &pitch);
+    ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+    ok(data == data2, "Expected data pointer.\n");
+
+    hr = IMF2DBuffer_GetScanline0AndPitch(_2dbuffer, NULL, &pitch);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_GetScanline0AndPitch(_2dbuffer, &data, NULL);
+    ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+    /* Active 2D lock */
+    hr = IMFMediaBuffer_Lock(buffer, &data2, NULL, NULL);
+    ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+    ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+    hr = IMFMediaBuffer_Lock(buffer, &data2, NULL, NULL);
+    ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+    ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+    hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#x.\n", hr);
 
     hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2);
     ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Failed to get interface, hr %#x.\n", hr);
 
     if (SUCCEEDED(hr))
+    {
+        hr = IMF2DBuffer_Lock2D(_2dbuffer, &data, &pitch);
+        ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data2, &pitch, &buffer_start, &length);
+        ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+        ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+        ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+        /* Flags are ignored. */
+        hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data2, &pitch, &buffer_start, &length);
+        ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data2, &pitch, &buffer_start, &length);
+        ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+        ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer_Unlock2D(_2dbuffer);
+        ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data2, &pitch, NULL, &length);
+        ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+        hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data2, &pitch, &buffer_start, NULL);
+        ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
         IMF2DBuffer2_Release(_2dbuffer2);
+    }
     else
         win_skip("IMF2DBuffer2 is not supported.\n");
 
+    IMF2DBuffer_Release(_2dbuffer);
+
     IMFMediaBuffer_Release(buffer);
+
+    for (i = 0; i < ARRAY_SIZE(_2d_buffer_tests); ++i)
+    {
+        const struct _2d_buffer_test *ptr = &_2d_buffer_tests[i];
+
+        hr = pMFCreate2DMediaBuffer(ptr->width, ptr->height, ptr->fourcc, FALSE, &buffer);
+        ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
+
+        hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2dbuffer);
+        ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+
+        hr = IMF2DBuffer_GetContiguousLength(_2dbuffer, &length);
+        ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
+        ok(length == ptr->contiguous_length, "%d: unexpected contiguous length %u for %u x %u, format %s.\n",
+                i, length, ptr->width, ptr->height, wine_dbgstr_an((char *)&ptr->fourcc, 4));
+
+        hr = pMFGetPlaneSize(ptr->fourcc, ptr->width, ptr->height, &length2);
+        ok(hr == S_OK, "Failed to get plane size, hr %#x.\n", hr);
+        ok(length2 == length, "%d: contiguous length %u does not match plane size %u.\n", i, length, length2);
+
+        ret = TRUE;
+        hr = IMF2DBuffer_IsContiguousFormat(_2dbuffer, &ret);
+        ok(hr == S_OK, "Failed to get format flag, hr %#x.\n", hr);
+        ok(!ret, "%d: unexpected format flag %d.\n", i, ret);
+
+        IMF2DBuffer_Release(_2dbuffer);
+
+        IMFMediaBuffer_Release(buffer);
+    }
 }
 
 static void test_MFCreateMediaBufferFromMediaType(void)
-- 
2.25.1




More information about the wine-devel mailing list