Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 120 +++++++++++++++++++++++++++++-------- dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 73 +++++++++++++++++++++- include/mfapi.h | 1 + 4 files changed, 166 insertions(+), 30 deletions(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 8378e24196..c3e3133b8f 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -19,6 +19,7 @@ #define COBJMACROS
#include "mfplat_private.h" +#include "d3d9types.h"
#include "initguid.h" #include "ks.h" @@ -1763,6 +1764,8 @@ struct uncompressed_video_format { const GUID *subtype; unsigned int bytes_per_pixel; + unsigned int alignment; + BOOL bottom_up; };
static int __cdecl uncompressed_video_format_compare(const void *a, const void *b) @@ -1772,33 +1775,57 @@ static int __cdecl uncompressed_video_format_compare(const void *a, const void * return memcmp(guid, format->subtype, sizeof(*guid)); }
-static HRESULT mf_get_image_size(REFGUID subtype, unsigned int width, unsigned int height, unsigned int *size) +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_NV12, 1, 0, 0 }, + { &MFVideoFormat_D16, 2, 3, 0 }, + { &MFVideoFormat_L16, 2, 3, 0 }, + { &MFVideoFormat_A16B16G16R16F, 8, 3, 1 }, +}; + +static struct uncompressed_video_format *mf_get_video_format(const GUID *subtype) +{ + return bsearch(subtype, video_formats, ARRAY_SIZE(video_formats), sizeof(*video_formats), + uncompressed_video_format_compare); +} + +static unsigned int mf_get_stride_for_format(const struct uncompressed_video_format *format, unsigned int width) +{ + return (width * format->bytes_per_pixel + format->alignment) & ~format->alignment; +} + +/*********************************************************************** + * MFGetStrideForBitmapInfoHeader (mfplat.@) + */ +HRESULT WINAPI MFGetStrideForBitmapInfoHeader(DWORD fourcc, DWORD width, LONG *stride) { - static const struct uncompressed_video_format video_formats[] = - { - { &MFVideoFormat_RGB24, 3 }, - { &MFVideoFormat_ARGB32, 4 }, - { &MFVideoFormat_RGB32, 4 }, - { &MFVideoFormat_RGB565, 2 }, - { &MFVideoFormat_RGB555, 2 }, - { &MFVideoFormat_A2R10G10B10, 4 }, - { &MFVideoFormat_RGB8, 1 }, - { &MFVideoFormat_A16B16G16R16F, 8 }, - }; struct uncompressed_video_format *format; + GUID subtype;
- format = bsearch(subtype, video_formats, ARRAY_SIZE(video_formats), sizeof(*video_formats), - uncompressed_video_format_compare); - if (format) - { - *size = ((width * format->bytes_per_pixel + 3) & ~3) * height; - } - else + TRACE("%#x, %u, %p.\n", fourcc, width, stride); + + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); + subtype.Data1 = fourcc; + + if (!(format = mf_get_video_format(&subtype))) { - *size = 0; + *stride = 0; + return MF_E_INVALIDMEDIATYPE; }
- return format ? S_OK : E_INVALIDARG; + *stride = mf_get_stride_for_format(format, width); + if (format->bottom_up) + *stride *= -1; + + return S_OK; }
/*********************************************************************** @@ -1806,24 +1833,65 @@ static HRESULT mf_get_image_size(REFGUID subtype, unsigned int width, unsigned i */ HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size) { + struct uncompressed_video_format *format; + unsigned int stride; + TRACE("%s, %u, %u, %p.\n", debugstr_mf_guid(subtype), width, height, size);
- return mf_get_image_size(subtype, width, height, size); + if (!(format = mf_get_video_format(subtype))) + { + *size = 0; + return E_INVALIDARG; + } + + switch (subtype->Data1) + { + case MAKEFOURCC('N','V','1','2'): + /* 2 x 2 block, interleaving UV for half the height */ + *size = ((width + 1) & ~1) * height * 3 / 2; + break; + case D3DFMT_L8: + case D3DFMT_L16: + case D3DFMT_D16: + *size = width * format->bytes_per_pixel * height; + break; + default: + stride = mf_get_stride_for_format(format, width); + *size = stride * height; + } + + return S_OK; }
/*********************************************************************** * MFGetPlaneSize (mfplat.@) */ -HRESULT WINAPI MFGetPlaneSize(DWORD format, DWORD width, DWORD height, DWORD *size) +HRESULT WINAPI MFGetPlaneSize(DWORD fourcc, DWORD width, DWORD height, DWORD *size) { + struct uncompressed_video_format *format; + unsigned int stride; GUID subtype;
- TRACE("%#x, %u, %u, %p.\n", format, width, height, size); + TRACE("%#x, %u, %u, %p.\n", fourcc, width, height, size);
memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); - subtype.Data1 = format; + subtype.Data1 = fourcc; + + if (!(format = mf_get_video_format(&subtype))) + return MF_E_INVALIDMEDIATYPE; + + stride = mf_get_stride_for_format(format, width);
- return mf_get_image_size(&subtype, width, height, size); + switch (fourcc) + { + case MAKEFOURCC('N','V','1','2'): + *size = stride * height * 3 / 2; + break; + default: + *size = stride * height; + } + + return S_OK; }
/*********************************************************************** diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 1e11a1fc2a..338e8f8eff 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -101,7 +101,7 @@ @ stdcall MFGetPluginControl(ptr) @ stub MFGetPrivateWorkqueues @ stub MFGetSockaddrFromNumericName -@ stub MFGetStrideForBitmapInfoHeader +@ stdcall MFGetStrideForBitmapInfoHeader(long long ptr) @ stdcall MFGetSystemTime() @ stdcall MFGetTimerPeriodicity(ptr) @ stub MFGetUncompressedVideoFormat diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 97108e1478..0fd55c6fa1 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -92,6 +92,7 @@ static HRESULT (WINAPI *pMFAllocateWorkQueueEx)(MFASYNC_WORKQUEUE_TYPE queue_typ static HRESULT (WINAPI *pMFTEnumEx)(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type, const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate, UINT32 *count); static HRESULT (WINAPI *pMFGetPlaneSize)(DWORD format, DWORD width, DWORD height, DWORD *size); +static HRESULT (WINAPI *pMFGetStrideForBitmapInfoHeader)(DWORD format, DWORD width, LONG *stride);
static const WCHAR fileschemeW[] = L"file://";
@@ -664,6 +665,7 @@ static void init_functions(void) X(MFCreateMFByteStreamOnStream); X(MFCreateTransformActivate); X(MFGetPlaneSize); + X(MFGetStrideForBitmapInfoHeader); X(MFHeapAlloc); X(MFHeapFree); X(MFPutWaitingWorkItem); @@ -3376,6 +3378,7 @@ static void test_MFCalculateImageSize(void) UINT32 width; UINT32 height; UINT32 size; + UINT32 plane_size; /* Matches image size when 0. */ } image_size_tests[] = { @@ -3395,6 +3398,13 @@ static void test_MFCalculateImageSize(void) { &MFVideoFormat_A2R10G10B10, 1, 1, 4 }, { &MFVideoFormat_A16B16G16R16F, 3, 5, 120 }, { &MFVideoFormat_A16B16G16R16F, 1, 1, 8 }, + + /* YUV */ + { &MFVideoFormat_NV12, 1, 3, 9, 4 }, + { &MFVideoFormat_NV12, 1, 2, 6, 3 }, + { &MFVideoFormat_NV12, 2, 2, 6, 6 }, + { &MFVideoFormat_NV12, 3, 2, 12, 9 }, + { &MFVideoFormat_NV12, 4, 2, 12, 12 }, }; unsigned int i; UINT32 size; @@ -3418,15 +3428,17 @@ static void test_MFCalculateImageSize(void) image_size_tests[i].height, &size); ok(hr == S_OK || (is_broken && hr == E_INVALIDARG), "%u: failed to calculate image size, hr %#x.\n", i, hr); ok(size == image_size_tests[i].size, "%u: unexpected image size %u, expected %u.\n", i, size, - image_size_tests[i].size); + image_size_tests[i].size);
if (pMFGetPlaneSize) { + unsigned int plane_size = image_size_tests[i].plane_size ? image_size_tests[i].plane_size : + image_size_tests[i].size; + hr = pMFGetPlaneSize(image_size_tests[i].subtype->Data1, image_size_tests[i].width, image_size_tests[i].height, &size); ok(hr == S_OK, "%u: failed to get plane size, hr %#x.\n", i, hr); - ok(size == image_size_tests[i].size, "%u: unexpected plane size %u, expected %u.\n", i, size, - image_size_tests[i].size); + ok(size == plane_size, "%u: unexpected plane size %u, expected %u.\n", i, size, plane_size); } } } @@ -4473,6 +4485,60 @@ static void test_queue_com_state(const char *name) ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr); }
+static void test_MFGetStrideForBitmapInfoHeader(void) +{ + static const struct stride_test + { + const GUID *subtype; + unsigned int width; + LONG stride; + } + stride_tests[] = + { + { &MFVideoFormat_RGB8, 3, -4 }, + { &MFVideoFormat_RGB8, 1, -4 }, + { &MFVideoFormat_RGB555, 3, -8 }, + { &MFVideoFormat_RGB555, 1, -4 }, + { &MFVideoFormat_RGB565, 3, -8 }, + { &MFVideoFormat_RGB565, 1, -4 }, + { &MFVideoFormat_RGB24, 3, -12 }, + { &MFVideoFormat_RGB24, 1, -4 }, + { &MFVideoFormat_RGB32, 3, -12 }, + { &MFVideoFormat_RGB32, 1, -4 }, + { &MFVideoFormat_ARGB32, 3, -12 }, + { &MFVideoFormat_ARGB32, 1, -4 }, + { &MFVideoFormat_A2R10G10B10, 3, -12 }, + { &MFVideoFormat_A2R10G10B10, 1, -4 }, + { &MFVideoFormat_A16B16G16R16F, 3, -24 }, + { &MFVideoFormat_A16B16G16R16F, 1, -8 }, + + /* YUV */ + { &MFVideoFormat_NV12, 1, 1 }, + { &MFVideoFormat_NV12, 2, 2 }, + { &MFVideoFormat_NV12, 3, 3 }, + }; + unsigned int i; + LONG stride; + HRESULT hr; + + if (!pMFGetStrideForBitmapInfoHeader) + { + win_skip("MFGetStrideForBitmapInfoHeader() is not available.\n"); + return; + } + + hr = pMFGetStrideForBitmapInfoHeader(MAKEFOURCC('H','2','6','4'), 1, &stride); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr); + + for (i = 0; i < ARRAY_SIZE(stride_tests); ++i) + { + hr = pMFGetStrideForBitmapInfoHeader(stride_tests[i].subtype->Data1, stride_tests[i].width, &stride); + ok(hr == S_OK, "%u: failed to get stride, hr %#x.\n", i, hr); + ok(stride == stride_tests[i].stride, "%u: format %s, unexpected stride %d, expected %d.\n", i, + wine_dbgstr_an((char *)&stride_tests[i].subtype->Data1, 4), stride, stride_tests[i].stride); + } +} + START_TEST(mfplat) { char **argv; @@ -4524,6 +4590,7 @@ START_TEST(mfplat) test_MFCreateTransformActivate(); test_MFTRegisterLocal(); test_queue_com(); + test_MFGetStrideForBitmapInfoHeader();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 38577cfe62..1f01dbe0c8 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -421,6 +421,7 @@ void * WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllo void WINAPI MFHeapFree(void *ptr); HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size); HRESULT WINAPI MFGetAttributesAsBlobSize(IMFAttributes *attributes, UINT32 *size); +HRESULT WINAPI MFGetStrideForBitmapInfoHeader(DWORD format, DWORD width, LONG *stride); HRESULT WINAPI MFGetPlaneSize(DWORD format, DWORD width, DWORD height, DWORD *size); HRESULT WINAPI MFGetTimerPeriodicity(DWORD *periodicity); HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 8ebfd0ddee..d799446676 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1230,8 +1230,6 @@ static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl = static void test_topology_loader(void) { IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl }; - static const WCHAR wavW[] = {'a','u','d','i','o','/','w','a','v',0}; - static const WCHAR nameW[] = {'t','e','s','t','.','w','a','v',0}; IMFTopology *topology, *topology2, *full_topology; IMFTopologyNode *src_node, *sink_node; IMFPresentationDescriptor *pd; @@ -1271,13 +1269,13 @@ todo_wine hr = MFCreateSourceResolver(&resolver); ok(hr == S_OK, "Failed to create source resolver, hr %#x.\n", hr);
- filename = load_resource(nameW); + filename = load_resource(L"test.wav");
hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream); ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attr); - IMFAttributes_SetString(attr, &MF_BYTESTREAM_CONTENT_TYPE, wavW); + IMFAttributes_SetString(attr, &MF_BYTESTREAM_CONTENT_TYPE, L"audio/wav"); IMFAttributes_Release(attr);
hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/buffer.c | 233 +++++++++++++++++++++++++++++++++-- dlls/mfplat/mediatype.c | 6 + dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/mfplat_private.h | 2 + dlls/mfplat/tests/mfplat.c | 49 ++++++++ include/mfapi.h | 1 + include/mfobjects.idl | 26 ++++ 7 files changed, 306 insertions(+), 12 deletions(-)
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 07c2517788..590288e344 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -24,9 +24,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+#define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1))) + struct memory_buffer { IMFMediaBuffer IMFMediaBuffer_iface; + IMF2DBuffer2 IMF2DBuffer2_iface; LONG refcount;
BYTE *data; @@ -59,6 +62,11 @@ static inline struct memory_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *ifa return CONTAINING_RECORD(iface, struct memory_buffer, IMFMediaBuffer_iface); }
+static struct memory_buffer *impl_from_IMF2DBuffer2(IMF2DBuffer2 *iface) +{ + return CONTAINING_RECORD(iface, struct memory_buffer, IMF2DBuffer2_iface); +} + static inline struct sample *impl_from_IMFSample(IMFSample *iface) { return CONTAINING_RECORD(iface, struct sample, IMFSample_iface); @@ -179,7 +187,7 @@ static HRESULT WINAPI memory_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *m return S_OK; }
-static const IMFMediaBufferVtbl memorybuffervtbl = +static const IMFMediaBufferVtbl memory_1d_buffer_vtbl = { memory_buffer_QueryInterface, memory_buffer_AddRef, @@ -191,28 +199,222 @@ static const IMFMediaBufferVtbl memorybuffervtbl = memory_buffer_GetMaxLength, };
-static HRESULT create_memory_buffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer) +static HRESULT WINAPI memory_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaBuffer) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &buffer->IMFMediaBuffer_iface; + } + else if (IsEqualIID(riid, &IID_IMF2DBuffer2) || + IsEqualIID(riid, &IID_IMF2DBuffer)) + { + *out = &buffer->IMF2DBuffer2_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + 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_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); + return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj); +} + +static ULONG WINAPI memory_2d_buffer_AddRef(IMF2DBuffer2 *iface) +{ + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface); +} + +static ULONG WINAPI memory_2d_buffer_Release(IMF2DBuffer2 *iface) +{ + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface); +} + +static HRESULT WINAPI memory_2d_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) +{ + FIXME("%p, %p, %p.\n", iface, scanline0, pitch); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_Unlock2D(IMF2DBuffer2 *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) +{ + FIXME("%p, %p, %p.\n", iface, scanline0, pitch); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_IsContiguousFormat(IMF2DBuffer2 *iface, BOOL *is_contiguous) +{ + FIXME("%p, %p.\n", iface, is_contiguous); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length) +{ + FIXME("%p, %p.\n", iface, length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYTE *dest_buffer, DWORD dest_length) +{ + FIXME("%p, %p, %u.\n", iface, dest_buffer, dest_length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length) +{ + FIXME("%p, %p, %u.\n", iface, src_buffer, src_length); + + return E_NOTIMPL; +} + +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); + + return E_NOTIMPL; +} + +static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dest_buffer) +{ + FIXME("%p, %p.\n", iface, dest_buffer); + + return E_NOTIMPL; +} + +static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl = +{ + memory_2d_buffer_QueryInterface, + memory_2d_buffer_AddRef, + memory_2d_buffer_Release, + memory_2d_buffer_Lock2D, + memory_2d_buffer_Unlock2D, + memory_2d_buffer_GetScanline0AndPitch, + memory_2d_buffer_IsContiguousFormat, + memory_2d_buffer_GetContiguousLength, + memory_2d_buffer_ContiguousCopyTo, + memory_2d_buffer_ContiguousCopyFrom, + memory_2d_buffer_Lock2DSize, + memory_2d_buffer_Copy2DTo, +}; + +static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment, + const IMFMediaBufferVtbl *vtbl) +{ + buffer->data = heap_alloc(ALIGN_SIZE(max_length, alignment)); + if (!buffer->data) + return E_OUTOFMEMORY; + + buffer->IMFMediaBuffer_iface.lpVtbl = vtbl; + buffer->refcount = 1; + buffer->max_length = max_length; + buffer->current_length = 0; + + return S_OK; +} + +static HRESULT create_1d_buffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer) { struct memory_buffer *object; + HRESULT hr;
if (!buffer) - return E_INVALIDARG; + return E_POINTER; + + *buffer = NULL;
- object = heap_alloc(sizeof(*object)); + object = heap_alloc_zero(sizeof(*object)); if (!object) return E_OUTOFMEMORY;
- object->data = heap_alloc((max_length + alignment) & ~alignment); - if (!object->data) + hr = memory_buffer_init(object, max_length, alignment, &memory_1d_buffer_vtbl); + if (FAILED(hr)) { heap_free(object); + return hr; + } + + *buffer = &object->IMFMediaBuffer_iface; + + return S_OK; +} + +static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, IMFMediaBuffer **buffer) +{ + struct memory_buffer *object; + unsigned int bpp, max_length; + GUID subtype; + HRESULT hr; + + if (!buffer) + return E_POINTER; + + *buffer = NULL; + + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); + subtype.Data1 = fourcc; + + if (!(bpp = mf_format_get_bpp(&subtype))) + return MF_E_INVALIDMEDIATYPE; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) return E_OUTOFMEMORY; + + switch (fourcc) + { + case MAKEFOURCC('N','V','1','2'): + max_length = ALIGN_SIZE(width * bpp, 64) * height * 3 / 2; + break; + default: + max_length = ALIGN_SIZE(width * bpp, 64) * height; }
- object->IMFMediaBuffer_iface.lpVtbl = &memorybuffervtbl; - object->refcount = 1; - object->max_length = max_length; - object->current_length = 0; + 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)) + { + heap_free(object); + return hr; + }
*buffer = &object->IMFMediaBuffer_iface;
@@ -226,7 +428,7 @@ HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer) { TRACE("%u, %p.\n", max_length, buffer);
- return create_memory_buffer(max_length, MF_1_BYTE_ALIGNMENT, buffer); + return create_1d_buffer(max_length, MF_1_BYTE_ALIGNMENT, buffer); }
/*********************************************************************** @@ -236,7 +438,14 @@ HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IM { TRACE("%u, %u, %p.\n", max_length, alignment, buffer);
- return create_memory_buffer(max_length, alignment, buffer); + return create_1d_buffer(max_length, alignment, buffer); +} + +HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer) +{ + TRACE("%u, %u, %#x, %d, %p.\n", width, height, fourcc, bottom_up, buffer); + + return create_2d_buffer(width, height, fourcc, buffer); }
static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index c3e3133b8f..6958421826 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -1802,6 +1802,12 @@ 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) +{ + struct uncompressed_video_format *format = mf_get_video_format(subtype); + return format ? format->bytes_per_pixel : 0; +} + /*********************************************************************** * MFGetStrideForBitmapInfoHeader (mfplat.@) */ diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 338e8f8eff..2fb6388a31 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -37,6 +37,7 @@ @ stub MFConvertFromFP16Array @ stub MFConvertToFP16Array @ stdcall MFCopyImage(ptr long ptr long long long) +@ stdcall MFCreate2DMediaBuffer(long long long long ptr) @ stub MFCreateAMMediaTypeFromMFMediaType @ stdcall MFCreateAlignedMemoryBuffer(long long ptr) @ stdcall MFCreateAsyncResult(ptr ptr ptr ptr) diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h index af8583daee..d68a8ed550 100644 --- a/dlls/mfplat/mfplat_private.h +++ b/dlls/mfplat/mfplat_private.h @@ -114,6 +114,8 @@ 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; + static inline const char *debugstr_propvar(const PROPVARIANT *v) { if (!v) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 0fd55c6fa1..31194db77f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -93,6 +93,8 @@ static HRESULT (WINAPI *pMFTEnumEx)(GUID category, UINT32 flags, const MFT_REGIS const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate, UINT32 *count); static HRESULT (WINAPI *pMFGetPlaneSize)(DWORD format, DWORD width, DWORD height, DWORD *size); static HRESULT (WINAPI *pMFGetStrideForBitmapInfoHeader)(DWORD format, DWORD width, LONG *stride); +static HRESULT (WINAPI *pMFCreate2DMediaBuffer)(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, + IMFMediaBuffer **buffer);
static const WCHAR fileschemeW[] = L"file://";
@@ -660,6 +662,7 @@ static void init_functions(void) X(MFAllocateSerialWorkQueue); X(MFAllocateWorkQueueEx); X(MFCopyImage); + X(MFCreate2DMediaBuffer); X(MFCreateDXGIDeviceManager); X(MFCreateSourceResolver); X(MFCreateMFByteStreamOnStream); @@ -1726,6 +1729,9 @@ static void test_system_memory_buffer(void) IMFMediaBuffer_Release(buffer);
/* Aligned buffer. */ + hr = MFCreateAlignedMemoryBuffer(16, MF_8_BYTE_ALIGNMENT, NULL); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + hr = MFCreateAlignedMemoryBuffer(201, MF_8_BYTE_ALIGNMENT, &buffer); ok(hr == S_OK, "Failed to create memory buffer, hr %#x.\n", hr);
@@ -4539,6 +4545,48 @@ static void test_MFGetStrideForBitmapInfoHeader(void) } }
+static void test_MFCreate2DMediaBuffer(void) +{ + IMF2DBuffer2 *_2dbuffer2; + IMF2DBuffer *_2dbuffer; + IMFMediaBuffer *buffer; + DWORD length; + HRESULT hr; + + if (!pMFCreate2DMediaBuffer) + { + win_skip("MFCreate2DMediaBuffer() is not available.\n"); + return; + } + + hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('H','2','6','4'), FALSE, &buffer); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr); + + hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('N','V','1','2'), FALSE, NULL); + ok(FAILED(hr), "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); + ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); + ok(length > 0, "Unexpected length.\n"); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2dbuffer); + ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); + IMF2DBuffer_Release(_2dbuffer); + + 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)) + IMF2DBuffer2_Release(_2dbuffer2); + else + win_skip("IMF2DBuffer2 is not supported.\n"); + + IMFMediaBuffer_Release(buffer); +} + START_TEST(mfplat) { char **argv; @@ -4591,6 +4639,7 @@ START_TEST(mfplat) test_MFTRegisterLocal(); test_queue_com(); test_MFGetStrideForBitmapInfoHeader(); + test_MFCreate2DMediaBuffer();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 1f01dbe0c8..9f4db44d1e 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -402,6 +402,7 @@ HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie); HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); BOOL WINAPI MFCompareFullToPartialMediaType(IMFMediaType *full_type, IMFMediaType *partial_type); HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines); +HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size); HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **result); diff --git a/include/mfobjects.idl b/include/mfobjects.idl index 758fd82cb1..8e3d65c77c 100644 --- a/include/mfobjects.idl +++ b/include/mfobjects.idl @@ -141,6 +141,32 @@ interface IMF2DBuffer : IUnknown HRESULT ContiguousCopyFrom([in, size_is(cbSrcBuffer)] const BYTE *pbSrcBuffer, [in] DWORD cbSrcBuffer); }
+typedef enum _MF2DBuffer_LockFlags +{ + MF2DBuffer_LockFlags_LockTypeMask = 0x1 | 0x2 | 0x3, + MF2DBuffer_LockFlags_Read = 0x1, + MF2DBuffer_LockFlags_Write = 0x2, + MF2DBuffer_LockFlags_ReadWrite = 0x3, + MF2DBuffer_LockFlags_ForceDWORD = 0x7fffffff +} MF2DBuffer_LockFlags; + +[ + object, + uuid(33ae5ea6-4316-436f-8ddd-d73d22f829ec), + local +] +interface IMF2DBuffer2 : IMF2DBuffer +{ + HRESULT Lock2DSize( + [in] MF2DBuffer_LockFlags flags, + [out] BYTE **scanline0, + [out] LONG *pitch, + [out] BYTE **buffer_start, + [out] DWORD *buffer_length); + + HRESULT Copy2DTo([in] IMF2DBuffer2 *dest_buffer); +} + [ object, uuid(44ae0fa8-ea31-4109-8d2e-4cae4997c555),
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=67005
Your paranoid android.
=== w1064v1809_ja (32 bit report) ===
mfplat: mfplat.c:2685: Test failed: Unexpected return value 0x102. mfplat.c:2036: Test failed: Failed to get event, hr 0xc00d3e85. mfplat.c:2039: Test failed: Failed to get event, hr 0xc00d3e85. mfplat.c:2042: Test failed: Failed to finalize GetEvent, hr 0xc00d3e85. mfplat.c:2045: Test failed: Unexpected result, hr 0xc00d3e85. 13f0:mfplat: unhandled exception c0000005 at 00401AFB
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=67003
Your paranoid android.
=== w1064v1809 (32 bit report) ===
mfplat: mfplat.c:2679: Test failed: Unexpected return value 0x102. mfplat.c:2030: Test failed: Failed to get event, hr 0xc00d3e85. mfplat.c:2033: Test failed: Failed to get event, hr 0xc00d3e85. mfplat.c:2036: Test failed: Failed to finalize GetEvent, hr 0xc00d3e85. mfplat.c:2039: Test failed: Unexpected result, hr 0xc00d3e85. 1664:mfplat: unhandled exception c0000005 at 00401AFB