[PATCH 6/7] mfplat: Implement attributes serialization.

Nikolay Sivov nsivov at codeweavers.com
Thu Mar 21 02:42:57 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at 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,
-- 
2.20.1




More information about the wine-devel mailing list