Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 4c878c9f8c..b3fbc46126 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2347,6 +2347,79 @@ static void test_MFInvokeCallback(void) ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr); }
+static void test_stream_descriptor(void) +{ + IMFMediaType *media_types[2], *media_type; + IMFMediaTypeHandler *type_handler; + IMFStreamDescriptor *stream_desc; + GUID major_type; + DWORD id, count; + unsigned int i; + HRESULT hr; + + hr = MFCreateStreamDescriptor(123, 0, NULL, &stream_desc); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + for (i = 0; i < ARRAY_SIZE(media_types); ++i) + { + hr = MFCreateMediaType(&media_types[i]); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + } + + hr = MFCreateStreamDescriptor(123, 0, media_types, &stream_desc); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = MFCreateStreamDescriptor(123, ARRAY_SIZE(media_types), media_types, &stream_desc); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFStreamDescriptor_GetStreamIdentifier(stream_desc, &id); + ok(hr == S_OK, "Failed to get descriptor id, hr %#x.\n", hr); + ok(id == 123, "Unexpected id %#x.\n", id); + + hr = IMFStreamDescriptor_GetMediaTypeHandler(stream_desc, &type_handler); + ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMediaTypeCount(type_handler, &count); + ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); + ok(count == ARRAY_SIZE(media_types), "Unexpected type count.\n"); + + hr = IMFMediaTypeHandler_GetCurrentMediaType(type_handler, &media_type); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMajorType(type_handler, &major_type); +todo_wine + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + for (i = 0; i < ARRAY_SIZE(media_types); ++i) + { + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i, &media_type); + ok(hr == S_OK, "Failed to get media type, hr %#x.\n", hr); + ok(media_type == media_types[i], "Unexpected object.\n"); + + if (SUCCEEDED(hr)) + IMFMediaType_Release(media_type); + } + + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, 2, &media_type); + ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#x.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, media_type); + ok(hr == S_OK, "Failed to set current type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMediaTypeCount(type_handler, &count); + ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); + ok(count == ARRAY_SIZE(media_types), "Unexpected type count.\n"); + + IMFMediaType_Release(media_type); + + IMFMediaTypeHandler_Release(type_handler); + + IMFStreamDescriptor_Release(stream_desc); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -2375,6 +2448,7 @@ START_TEST(mfplat) test_presentation_descriptor(); test_system_time_source(); test_MFInvokeCallback(); + test_stream_descriptor();
CoUninitialize(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 14 ++++++++++++-- dlls/mfplat/tests/mfplat.c | 11 ++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index b526509ab3..bdc476005a 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -931,9 +931,19 @@ static HRESULT WINAPI mediatype_handler_GetCurrentMediaType(IMFMediaTypeHandler
static HRESULT WINAPI mediatype_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) { - FIXME("%p, %p.\n", iface, type); + struct stream_desc *stream_desc = impl_from_IMFMediaTypeHandler(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, type); + + EnterCriticalSection(&stream_desc->cs); + if (stream_desc->current_type) + hr = IMFMediaType_GetGUID(stream_desc->current_type, &MF_MT_MAJOR_TYPE, type); + else + hr = MF_E_ATTRIBUTENOTFOUND; + LeaveCriticalSection(&stream_desc->cs); + + return hr; }
static const IMFMediaTypeHandlerVtbl mediatypehandlervtbl = diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b3fbc46126..9985f59172 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2387,7 +2387,6 @@ static void test_stream_descriptor(void) ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
hr = IMFMediaTypeHandler_GetMajorType(type_handler, &major_type); -todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr);
for (i = 0; i < ARRAY_SIZE(media_types); ++i) @@ -2409,6 +2408,16 @@ todo_wine hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, media_type); ok(hr == S_OK, "Failed to set current type, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetMajorType(type_handler, &major_type); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set major type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMajorType(type_handler, &major_type); + ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); + ok(IsEqualGUID(&major_type, &MFMediaType_Audio), "Unexpected major type.\n"); + hr = IMFMediaTypeHandler_GetMediaTypeCount(type_handler, &count); ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); ok(count == ARRAY_SIZE(media_types), "Unexpected type count.\n");
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index bdc476005a..272b1c2c87 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -1249,9 +1249,8 @@ static HRESULT WINAPI presentation_descriptor_GetItemByIndex(IMFPresentationDesc
static HRESULT WINAPI presentation_descriptor_CopyAllItems(IMFPresentationDescriptor *iface, IMFAttributes *dest) { - FIXME("%p, %p.\n", iface, dest); - - return E_NOTIMPL; + struct presentation_desc *presentation_desc = impl_from_IMFPresentationDescriptor(iface); + return IMFAttributes_CopyAllItems(&presentation_desc->attributes.IMFAttributes_iface, dest); }
static HRESULT WINAPI presentation_descriptor_GetStreamDescriptorCount(IMFPresentationDescriptor *iface, DWORD *count)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 47 ++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 52 ++++++++++++++++++++++++++++++++++++++ include/mfapi.h | 21 ++++++++++++--- 4 files changed, 118 insertions(+), 4 deletions(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 272b1c2c87..4e6fa80f9c 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -1449,3 +1449,50 @@ HRESULT WINAPI MFCreatePresentationDescriptor(DWORD count, IMFStreamDescriptor *
return S_OK; } + +struct uncompressed_video_format +{ + const GUID *subtype; + unsigned int bytes_per_pixel; +}; + +static int uncompressed_video_format_compare(const void *a, const void *b) +{ + const GUID *guid = a; + const struct uncompressed_video_format *format = b; + return memcmp(guid, format->subtype, sizeof(*guid)); +} + +/*********************************************************************** + * MFCalculateImageSize (mfplat.@) + */ +HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size) +{ + 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; + + TRACE("%s, %u, %u, %p.\n", debugstr_guid(subtype), width, height, size); + + 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 + { + *size = 0; + } + + return format ? S_OK : E_INVALIDARG; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index be5d8b2205..d8ed5f90e5 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -26,7 +26,7 @@ @ stub MFBeginUnregisterWorkQueueWithMMCSS @ stub MFBlockThread @ stub MFCalculateBitmapImageSize -@ stub MFCalculateImageSize +@ stdcall MFCalculateImageSize(ptr long long ptr) @ stub MFCancelCreateFile @ stdcall MFCancelWorkItem(int64) @ stub MFCompareFullToPartialMediaType diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 9985f59172..b420513e3f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2429,6 +2429,57 @@ static void test_stream_descriptor(void) IMFStreamDescriptor_Release(stream_desc); }
+static void test_MFCalculateImageSize(void) +{ + static const struct image_size_test + { + const GUID *subtype; + UINT32 width; + UINT32 height; + UINT32 size; + } + image_size_tests[] = + { + { &MFVideoFormat_RGB8, 3, 5, 20 }, + { &MFVideoFormat_RGB8, 1, 1, 4 }, + { &MFVideoFormat_RGB555, 3, 5, 40 }, + { &MFVideoFormat_RGB555, 1, 1, 4 }, + { &MFVideoFormat_RGB565, 3, 5, 40 }, + { &MFVideoFormat_RGB565, 1, 1, 4 }, + { &MFVideoFormat_RGB24, 3, 5, 60 }, + { &MFVideoFormat_RGB24, 1, 1, 4 }, + { &MFVideoFormat_RGB32, 3, 5, 60 }, + { &MFVideoFormat_RGB32, 1, 1, 4 }, + { &MFVideoFormat_ARGB32, 3, 5, 60 }, + { &MFVideoFormat_ARGB32, 1, 1, 4 }, + { &MFVideoFormat_A2R10G10B10, 3, 5, 60 }, + { &MFVideoFormat_A2R10G10B10, 1, 1, 4 }, + { &MFVideoFormat_A16B16G16R16F, 3, 5, 120 }, + { &MFVideoFormat_A16B16G16R16F, 1, 1, 8 }, + }; + unsigned int i; + UINT32 size; + HRESULT hr; + + size = 1; + hr = MFCalculateImageSize(&IID_IUnknown, 1, 1, &size); + ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Unexpected hr %#x.\n", hr); + ok(size == 0, "Unexpected size %u.\n", size); + + for (i = 0; i < ARRAY_SIZE(image_size_tests); ++i) + { + /* Those are supported since Win10. */ + BOOL is_broken = IsEqualGUID(image_size_tests[i].subtype, &MFVideoFormat_A16B16G16R16F) || + IsEqualGUID(image_size_tests[i].subtype, &MFVideoFormat_A2R10G10B10); + + hr = MFCalculateImageSize(image_size_tests[i].subtype, image_size_tests[i].width, + 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); + } +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -2458,6 +2509,7 @@ START_TEST(mfplat) test_system_time_source(); test_MFInvokeCallback(); test_stream_descriptor(); + test_MFCalculateImageSize();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index b38953c855..1b8eafa9ad 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -48,11 +48,25 @@ extern "C" { DEFINE_GUID(name, format, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
#ifndef DIRECT3D_VERSION -#define D3DFMT_X8R8G8B8 22 +#define D3DFMT_R8G8B8 20 +#define D3DFMT_A8R8G8B8 21 +#define D3DFMT_X8R8G8B8 22 +#define D3DFMT_R5G6B5 23 +#define D3DFMT_X1R5G5B5 24 +#define D3DFMT_A2B10G10R10 31 +#define D3DFMT_P8 41 +#define D3DFMT_A16B16G16R16F 113 #endif
-DEFINE_MEDIATYPE_GUID(MFVideoFormat_WMV3, MAKEFOURCC('W','M','V','3')); -DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB32, D3DFMT_X8R8G8B8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_WMV3, MAKEFOURCC('W','M','V','3')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB8, D3DFMT_P8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB555, D3DFMT_X1R5G5B5); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB565, D3DFMT_R5G6B5); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB24, D3DFMT_R8G8B8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB32, D3DFMT_X8R8G8B8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ARGB32, D3DFMT_A8R8G8B8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_A2R10G10B10, D3DFMT_A2B10G10R10); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_A16B16G16R16F, D3DFMT_A16B16G16R16F);
#if defined(__cplusplus) && !defined(CINTERFACE) typedef struct tagMFASYNCRESULT : public IMFAsyncResult { @@ -172,6 +186,7 @@ typedef void (CALLBACK *MFPERIODICCALLBACK)(IUnknown *context); HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key); HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue); HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue); +HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size); HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines); HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer);
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=49675
Your paranoid android.
=== debian9 (32 bit Japanese:Japan report) ===
mfplat: mfplat.c:2344: Test failed: Unexpected refcount 1. Unhandled exception: page fault on read access to 0x00000009 in 32-bit code (0x7e7e62aa).
Report errors: mfplat:mfplat crashed (c0000005)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 19 ++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 41 ++++++++++++++++++++++++++++++++++++++ include/mfapi.h | 1 + 4 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 4e6fa80f9c..a2e3a96902 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -1496,3 +1496,22 @@ HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height
return format ? S_OK : E_INVALIDARG; } + +/*********************************************************************** + * MFCompareFullToPartialMediaType (mfplat.@) + */ +BOOL WINAPI MFCompareFullToPartialMediaType(IMFMediaType *full_type, IMFMediaType *partial_type) +{ + BOOL result; + GUID major; + + TRACE("%p, %p.\n", full_type, partial_type); + + if (FAILED(IMFMediaType_GetMajorType(partial_type, &major))) + return FALSE; + + if (FAILED(IMFMediaType_Compare(partial_type, (IMFAttributes *)full_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result))) + return FALSE; + + return result; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index d8ed5f90e5..8b340a2136 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -29,7 +29,7 @@ @ stdcall MFCalculateImageSize(ptr long long ptr) @ stub MFCancelCreateFile @ stdcall MFCancelWorkItem(int64) -@ stub MFCompareFullToPartialMediaType +@ stdcall MFCompareFullToPartialMediaType(ptr ptr) @ stub MFCompareSockaddrAddresses @ stub MFConvertColorInfoFromDXVA @ stub MFConvertColorInfoToDXVA diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b420513e3f..2f8b1aaa3e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2480,6 +2480,46 @@ static void test_MFCalculateImageSize(void) } }
+static void test_MFCompareFullToPartialMediaType(void) +{ + IMFMediaType *full_type, *partial_type; + HRESULT hr; + BOOL ret; + + hr = MFCreateMediaType(&full_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = MFCreateMediaType(&partial_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + ret = MFCompareFullToPartialMediaType(full_type, partial_type); + ok(!ret, "Unexpected result %d.\n", ret); + + hr = IMFMediaType_SetGUID(full_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set major type, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(partial_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set major type, hr %#x.\n", hr); + + ret = MFCompareFullToPartialMediaType(full_type, partial_type); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IMFMediaType_SetGUID(full_type, &MF_MT_SUBTYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set major type, hr %#x.\n", hr); + + ret = MFCompareFullToPartialMediaType(full_type, partial_type); + ok(ret, "Unexpected result %d.\n", ret); + + hr = IMFMediaType_SetGUID(partial_type, &MF_MT_SUBTYPE, &MFMediaType_Video); + ok(hr == S_OK, "Failed to set major type, hr %#x.\n", hr); + + ret = MFCompareFullToPartialMediaType(full_type, partial_type); + ok(!ret, "Unexpected result %d.\n", ret); + + IMFMediaType_Release(full_type); + IMFMediaType_Release(partial_type); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -2510,6 +2550,7 @@ START_TEST(mfplat) test_MFInvokeCallback(); test_stream_descriptor(); test_MFCalculateImageSize(); + test_MFCompareFullToPartialMediaType();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 1b8eafa9ad..d8738d5ae1 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -188,6 +188,7 @@ HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue); HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue); HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size); 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 MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 197 ++++++++++++++++++++++++++++++++++++- dlls/mfplat/mfplat.spec | 4 +- dlls/mfplat/tests/mfplat.c | 29 ++++++ include/mfapi.h | 2 + 4 files changed, 229 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index ae94645ef1..69746f2a68 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -1364,7 +1364,8 @@ static HRESULT WINAPI mfattributes_GetItemByIndex(IMFAttributes *iface, UINT32 i if (index < attributes->count) { *key = attributes->attributes[index].key; - PropVariantCopy(value, &attributes->attributes[index].value); + if (value) + PropVariantCopy(value, &attributes->attributes[index].value); } else hr = E_INVALIDARG; @@ -1493,6 +1494,200 @@ HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size) return S_OK; }
+#define ATTRIBUTES_STORE_MAGIC 0x494d4641 /* IMFA */ + +struct attributes_store_header +{ + DWORD magic; + UINT32 count; +}; + +struct attributes_store_item +{ + GUID key; + QWORD type; + union + { + double f; + UINT64 i64; + struct + { + DWORD size; + DWORD offset; + } subheader; + } u; +}; + +/*********************************************************************** + * MFGetAttributesAsBlobSize (mfplat.@) + */ +HRESULT WINAPI MFGetAttributesAsBlobSize(IMFAttributes *attributes, UINT32 *size) +{ + unsigned int i, count, length; + HRESULT hr; + GUID key; + + TRACE("%p, %p.\n", attributes, size); + + IMFAttributes_LockStore(attributes); + + hr = IMFAttributes_GetCount(attributes, &count); + + *size = sizeof(struct attributes_store_header); + + for (i = 0; i < count; ++i) + { + MF_ATTRIBUTE_TYPE type; + + hr = IMFAttributes_GetItemByIndex(attributes, i, &key, NULL); + if (FAILED(hr)) + break; + + *size += sizeof(struct attributes_store_item); + + IMFAttributes_GetItemType(attributes, &key, &type); + + switch (type) + { + case MF_ATTRIBUTE_GUID: + *size += sizeof(GUID); + break; + case MF_ATTRIBUTE_STRING: + IMFAttributes_GetStringLength(attributes, &key, &length); + *size += (length + 1) * sizeof(WCHAR); + break; + case MF_ATTRIBUTE_BLOB: + IMFAttributes_GetBlobSize(attributes, &key, &length); + *size += length; + break; + case MF_ATTRIBUTE_UINT32: + case MF_ATTRIBUTE_UINT64: + case MF_ATTRIBUTE_DOUBLE: + case MF_ATTRIBUTE_IUNKNOWN: + default: + ; + } + } + + IMFAttributes_UnlockStore(attributes); + + return hr; +} + +struct attr_serialize_context +{ + UINT8 *buffer; + UINT8 *ptr; + UINT32 size; +}; + +static void attributes_serialize_write(struct attr_serialize_context *context, const void *value, unsigned int size) +{ + memcpy(context->ptr, value, size); + context->ptr += size; +} + +static void attributes_serialize_write_item(struct attr_serialize_context *context, struct attributes_store_item *item, + const void *value) +{ + switch (item->type) + { + case MF_ATTRIBUTE_UINT32: + case MF_ATTRIBUTE_UINT64: + case MF_ATTRIBUTE_DOUBLE: + attributes_serialize_write(context, item, sizeof(*item)); + break; + case MF_ATTRIBUTE_GUID: + case MF_ATTRIBUTE_STRING: + case MF_ATTRIBUTE_BLOB: + item->u.subheader.offset = context->size - item->u.subheader.size; + attributes_serialize_write(context, item, sizeof(*item)); + memcpy(context->buffer + item->u.subheader.offset, value, item->u.subheader.size); + context->size -= item->u.subheader.size; + break; + default: + ; + } +} + +/*********************************************************************** + * MFGetAttributesAsBlob (mfplat.@) + */ +HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size) +{ + struct attributes_store_header header; + struct attr_serialize_context context; + unsigned int required_size, i; + PROPVARIANT value; + HRESULT hr; + + TRACE("%p, %p, %u.\n", attributes, buffer, size); + + if (FAILED(hr = MFGetAttributesAsBlobSize(attributes, &required_size))) + return hr; + + if (required_size > size) + return MF_E_BUFFERTOOSMALL; + + context.buffer = buffer; + context.ptr = buffer; + context.size = required_size; + + IMFAttributes_LockStore(attributes); + + header.magic = ATTRIBUTES_STORE_MAGIC; + IMFAttributes_GetCount(attributes, &header.count); + + attributes_serialize_write(&context, &header, sizeof(header)); + + for (i = 0; i < header.count; ++i) + { + struct attributes_store_item item; + const void *data = NULL; + + hr = IMFAttributes_GetItemByIndex(attributes, i, &item.key, &value); + if (FAILED(hr)) + break; + + item.type = value.vt; + + switch (value.vt) + { + case MF_ATTRIBUTE_UINT32: + case MF_ATTRIBUTE_UINT64: + item.u.i64 = value.u.uhVal.QuadPart; + break; + case MF_ATTRIBUTE_DOUBLE: + item.u.f = value.u.dblVal; + break; + case MF_ATTRIBUTE_GUID: + item.u.subheader.size = sizeof(*value.u.puuid); + data = value.u.puuid; + break; + case MF_ATTRIBUTE_STRING: + item.u.subheader.size = (strlenW(value.u.pwszVal) + 1) * sizeof(WCHAR); + data = value.u.pwszVal; + break; + case MF_ATTRIBUTE_BLOB: + item.u.subheader.size = value.u.caub.cElems; + data = value.u.caub.pElems; + break; + case MF_ATTRIBUTE_IUNKNOWN: + break; + default: + WARN("Unknown attribute type %#x.\n", value.vt); + } + + attributes_serialize_write_item(&context, &item, data); + + PropVariantClear(&value); + } + + IMFAttributes_UnlockStore(attributes); + + return S_OK; +} + typedef struct _mfbytestream { mfattributes attributes; diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 8b340a2136..730e64b675 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -85,8 +85,8 @@ @ stub MFFrameRateToAverageTimePerFrame @ stub MFFreeAdaptersAddresses @ stub MFGetAdaptersAddresses -@ stub MFGetAttributesAsBlob -@ stub MFGetAttributesAsBlobSize +@ stdcall MFGetAttributesAsBlob(ptr ptr long) +@ stdcall MFGetAttributesAsBlobSize(ptr ptr) @ stub MFGetConfigurationDWORD @ stub MFGetConfigurationPolicy @ stub MFGetConfigurationStore diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 2f8b1aaa3e..258895f3be 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -47,6 +47,7 @@ DEFINE_GUID(DUMMY_GUID3, 0x12345678,0x1234,0x1234,0x23,0x23,0x23,0x23,0x23,0x23, #include "strsafe.h"
#include "wine/test.h" +#include "wine/heap.h"
static BOOL is_win8_plus;
@@ -2520,6 +2521,33 @@ static void test_MFCompareFullToPartialMediaType(void) IMFMediaType_Release(partial_type); }
+static void test_attributes_serialization(void) +{ + IMFAttributes *attributes; + UINT8 *buffer; + UINT32 size; + HRESULT hr; + + hr = MFCreateAttributes(&attributes, 0); + ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr); + + hr = MFGetAttributesAsBlobSize(attributes, &size); + ok(hr == S_OK, "Failed to get blob size, hr %#x.\n", hr); + ok(size == 8, "Got size %u.\n", size); + + buffer = heap_alloc(size); + + hr = MFGetAttributesAsBlob(attributes, buffer, size); + ok(hr == S_OK, "Failed to serialize, hr %#x.\n", hr); + + hr = MFGetAttributesAsBlob(attributes, buffer, size - 1); + ok(hr == MF_E_BUFFERTOOSMALL, "Unexpected hr %#x.\n", hr); + + heap_free(buffer); + + IMFAttributes_Release(attributes); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -2551,6 +2579,7 @@ START_TEST(mfplat) test_stream_descriptor(); test_MFCalculateImageSize(); test_MFCompareFullToPartialMediaType(); + test_attributes_serialization();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index d8738d5ae1..5d6d1e79d7 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -204,6 +204,8 @@ HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer); void * WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type); void WINAPI MFHeapFree(void *ptr); +HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size); +HRESULT WINAPI MFGetAttributesAsBlobSize(IMFAttributes *attributes, UINT32 *size); HRESULT WINAPI MFGetTimerPeriodicity(DWORD *periodicity); HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type, MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 117 +++++++++++++++++++++++++++++++++++-- dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 72 ++++++++++++++++++++++- include/mfapi.h | 1 + 4 files changed, 184 insertions(+), 8 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 69746f2a68..899aca73d9 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -1509,6 +1509,7 @@ struct attributes_store_item union { double f; + UINT32 i32; UINT64 i64; struct { @@ -1587,7 +1588,7 @@ static void attributes_serialize_write(struct attr_serialize_context *context, c context->ptr += size; }
-static void attributes_serialize_write_item(struct attr_serialize_context *context, struct attributes_store_item *item, +static BOOL attributes_serialize_write_item(struct attr_serialize_context *context, struct attributes_store_item *item, const void *value) { switch (item->type) @@ -1606,8 +1607,10 @@ static void attributes_serialize_write_item(struct attr_serialize_context *conte context->size -= item->u.subheader.size; break; default: - ; + return FALSE; } + + return TRUE; }
/*********************************************************************** @@ -1619,6 +1622,7 @@ HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, U struct attr_serialize_context context; unsigned int required_size, i; PROPVARIANT value; + UINT32 count; HRESULT hr;
TRACE("%p, %p, %u.\n", attributes, buffer, size); @@ -1636,11 +1640,12 @@ HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, U IMFAttributes_LockStore(attributes);
header.magic = ATTRIBUTES_STORE_MAGIC; - IMFAttributes_GetCount(attributes, &header.count); + header.count = 0; /* Will be updated later */ + IMFAttributes_GetCount(attributes, &count);
attributes_serialize_write(&context, &header, sizeof(header));
- for (i = 0; i < header.count; ++i) + for (i = 0; i < count; ++i) { struct attributes_store_item item; const void *data = NULL; @@ -1678,16 +1683,118 @@ HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, U WARN("Unknown attribute type %#x.\n", value.vt); }
- attributes_serialize_write_item(&context, &item, data); + if (attributes_serialize_write_item(&context, &item, data)) + header.count++;
PropVariantClear(&value); }
+ memcpy(context.buffer, &header, sizeof(header)); + IMFAttributes_UnlockStore(attributes);
return S_OK; }
+static HRESULT attributes_deserialize_read(struct attr_serialize_context *context, void *value, unsigned int size) +{ + if (context->size < (context->ptr - context->buffer) + size) + return E_INVALIDARG; + + memcpy(value, context->ptr, size); + context->ptr += size; + + return S_OK; +} + +/*********************************************************************** + * MFInitAttributesFromBlob (mfplat.@) + */ +HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *dest, const UINT8 *buffer, UINT size) +{ + struct attr_serialize_context context; + struct attributes_store_header header; + struct attributes_store_item item; + IMFAttributes *attributes; + unsigned int i; + HRESULT hr; + + TRACE("%p, %p, %u.\n", dest, buffer, size); + + context.buffer = (UINT8 *)buffer; + context.ptr = (UINT8 *)buffer; + context.size = size; + + /* Validate buffer structure. */ + if (FAILED(hr = attributes_deserialize_read(&context, &header, sizeof(header)))) + return hr; + + if (header.magic != ATTRIBUTES_STORE_MAGIC) + return E_UNEXPECTED; + + if (FAILED(hr = MFCreateAttributes(&attributes, header.count))) + return hr; + + for (i = 0; i < header.count; ++i) + { + if (FAILED(hr = attributes_deserialize_read(&context, &item, sizeof(item)))) + break; + + hr = E_UNEXPECTED; + + switch (item.type) + { + case MF_ATTRIBUTE_UINT32: + hr = IMFAttributes_SetUINT32(attributes, &item.key, item.u.i32); + break; + case MF_ATTRIBUTE_UINT64: + hr = IMFAttributes_SetUINT64(attributes, &item.key, item.u.i64); + break; + case MF_ATTRIBUTE_DOUBLE: + hr = IMFAttributes_SetDouble(attributes, &item.key, item.u.f); + break; + case MF_ATTRIBUTE_GUID: + if (item.u.subheader.size == sizeof(GUID) && + item.u.subheader.offset + item.u.subheader.size <= context.size) + { + hr = IMFAttributes_SetGUID(attributes, &item.key, + (const GUID *)(context.buffer + item.u.subheader.offset)); + } + break; + case MF_ATTRIBUTE_STRING: + if (item.u.subheader.size >= sizeof(WCHAR) && + item.u.subheader.offset + item.u.subheader.size <= context.size) + { + hr = IMFAttributes_SetString(attributes, &item.key, + (const WCHAR *)(context.buffer + item.u.subheader.offset)); + } + break; + case MF_ATTRIBUTE_BLOB: + if (item.u.subheader.size > 0 && item.u.subheader.offset + item.u.subheader.size <= context.size) + { + hr = IMFAttributes_SetBlob(attributes, &item.key, context.buffer + item.u.subheader.offset, + item.u.subheader.size); + } + break; + default: + ; + } + + if (FAILED(hr)) + break; + } + + if (SUCCEEDED(hr)) + { + IMFAttributes_DeleteAllItems(dest); + hr = IMFAttributes_CopyAllItems(attributes, dest); + } + + IMFAttributes_Release(attributes); + + return hr; +} + typedef struct _mfbytestream { mfattributes attributes; diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 730e64b675..4272a206e6 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -107,7 +107,7 @@ @ stdcall MFHeapAlloc(long long str long long) @ stdcall MFHeapFree(ptr) @ stub MFInitAMMediaTypeFromMFMediaType -@ stub MFInitAttributesFromBlob +@ stdcall MFInitAttributesFromBlob(ptr ptr long) @ stub MFInitMediaTypeFromAMMediaType @ stub MFInitMediaTypeFromMFVideoFormat @ stub MFInitMediaTypeFromMPEG1VideoInfo diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 258895f3be..85fc176046 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2523,14 +2523,24 @@ static void test_MFCompareFullToPartialMediaType(void)
static void test_attributes_serialization(void) { - IMFAttributes *attributes; + static const WCHAR textW[] = {'T','e','x','t',0}; + static const UINT8 blob[] = {1,2,3}; + IMFAttributes *attributes, *dest; + UINT32 size, count, value32; + double value_dbl; + UINT64 value64; UINT8 *buffer; - UINT32 size; + IUnknown *obj; HRESULT hr; + WCHAR *str; + GUID guid;
hr = MFCreateAttributes(&attributes, 0); ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
+ hr = MFCreateAttributes(&dest, 0); + ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr); + hr = MFGetAttributesAsBlobSize(attributes, &size); ok(hr == S_OK, "Failed to get blob size, hr %#x.\n", hr); ok(size == 8, "Got size %u.\n", size); @@ -2543,9 +2553,67 @@ static void test_attributes_serialization(void) hr = MFGetAttributesAsBlob(attributes, buffer, size - 1); ok(hr == MF_E_BUFFERTOOSMALL, "Unexpected hr %#x.\n", hr);
+ hr = MFInitAttributesFromBlob(dest, buffer, size - 1); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFAttributes_SetUINT32(dest, &MF_MT_MAJOR_TYPE, 1); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = MFInitAttributesFromBlob(dest, buffer, size); + ok(hr == S_OK, "Failed to deserialize, hr %#x.\n", hr); + + /* Previous items are cleared. */ + hr = IMFAttributes_GetCount(dest, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + heap_free(buffer);
+ /* Set some attributes of various types. */ + IMFAttributes_SetUINT32(attributes, &MF_MT_MAJOR_TYPE, 456); + IMFAttributes_SetUINT64(attributes, &MF_MT_SUBTYPE, 123); + IMFAttributes_SetDouble(attributes, &IID_IUnknown, 0.5); + IMFAttributes_SetUnknown(attributes, &IID_IMFAttributes, (IUnknown *)attributes); + IMFAttributes_SetGUID(attributes, &GUID_NULL, &IID_IUnknown); + IMFAttributes_SetString(attributes, &DUMMY_CLSID, textW); + IMFAttributes_SetBlob(attributes, &DUMMY_GUID1, blob, sizeof(blob)); + + hr = MFGetAttributesAsBlobSize(attributes, &size); + ok(hr == S_OK, "Failed to get blob size, hr %#x.\n", hr); + ok(size > 8, "Got unexpected size %u.\n", size); + + buffer = heap_alloc(size); + hr = MFGetAttributesAsBlob(attributes, buffer, size); + ok(hr == S_OK, "Failed to serialize, hr %#x.\n", hr); + hr = MFInitAttributesFromBlob(dest, buffer, size); + ok(hr == S_OK, "Failed to deserialize, hr %#x.\n", hr); + heap_free(buffer); + + hr = IMFAttributes_GetUINT32(dest, &MF_MT_MAJOR_TYPE, &value32); + ok(hr == S_OK, "Failed to get get uint32 value, hr %#x.\n", hr); + ok(value32 == 456, "Unexpected value %u.\n", value32); + hr = IMFAttributes_GetUINT64(dest, &MF_MT_SUBTYPE, &value64); + ok(hr == S_OK, "Failed to get get uint64 value, hr %#x.\n", hr); + ok(value64 == 123, "Unexpected value.\n"); + hr = IMFAttributes_GetDouble(dest, &IID_IUnknown, &value_dbl); + ok(hr == S_OK, "Failed to get get double value, hr %#x.\n", hr); + ok(value_dbl == 0.5, "Unexpected value.\n"); + hr = IMFAttributes_GetUnknown(dest, &IID_IMFAttributes, &IID_IUnknown, (void **)&obj); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + hr = IMFAttributes_GetGUID(dest, &GUID_NULL, &guid); + ok(hr == S_OK, "Failed to get guid value, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &IID_IUnknown), "Unexpected guid.\n"); + hr = IMFAttributes_GetAllocatedString(dest, &DUMMY_CLSID, &str, &size); + ok(hr == S_OK, "Failed to get string value, hr %#x.\n", hr); + ok(!lstrcmpW(str, textW), "Unexpected string.\n"); + CoTaskMemFree(str); + hr = IMFAttributes_GetAllocatedBlob(dest, &DUMMY_GUID1, &buffer, &size); + ok(hr == S_OK, "Failed to get blob value, hr %#x.\n", hr); + ok(!memcmp(buffer, blob, sizeof(blob)), "Unexpected blob.\n"); + CoTaskMemFree(buffer); + IMFAttributes_Release(attributes); + IMFAttributes_Release(dest); }
START_TEST(mfplat) diff --git a/include/mfapi.h b/include/mfapi.h index 5d6d1e79d7..b082f9c2dd 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -213,6 +213,7 @@ HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *inpu HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type, const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate, UINT32 *pcount); +HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *attributes, const UINT8 *buffer, UINT size); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); HRESULT WINAPI MFLockPlatform(void); HRESULT WINAPI MFPutWorkItem(DWORD queue, IMFAsyncCallback *callback, IUnknown *state);
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=49678
Your paranoid android.
=== debian9b (32 bit WoW report) ===
mfplat: mfplat.c:2345: Test failed: Unexpected refcount 1. Unhandled exception: page fault on execute access to 0x6567206f in 32-bit code (0x6567206f).
Report errors: mfplat:mfplat crashed (c0000005)
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=49670
Your paranoid android.
=== w2008s64 (task log) ===
Task errors: Unable to set the VM system time: network read timed out (settime/connect:AgentVersion.h:0/9). Maybe the TestAgentd process is missing the required privileges.
=== debian9 (32 bit Chinese:China report) ===
mfplat: mfplat.c:2344: Test failed: Unexpected refcount 1. Unhandled exception: page fault on read access to 0x00000009 in 32-bit code (0x7e7cf0aa).
Report errors: mfplat:mfplat crashed (c0000005)