mfplat: Implement locking methods for 2D memory buffers.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Nikolay Sivov 2020-03-16 12:17:08 +03:00 committed by Alexandre Julliard
parent 2e3baaed2c
commit c1e5c71467
4 changed files with 427 additions and 51 deletions

View File

@ -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)

View File

@ -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;
}
/***********************************************************************

View File

@ -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)
{

View File

@ -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)