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,