[PATCH 1/9] mfplat: Move sample implementation to a separate file.

Nikolay Sivov nsivov at codeweavers.com
Wed Feb 3 05:27:54 CST 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/Makefile.in |    3 +-
 dlls/mfplat/buffer.c    |  982 --------------------------------------
 dlls/mfplat/sample.c    | 1007 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 1009 insertions(+), 983 deletions(-)
 create mode 100644 dlls/mfplat/sample.c

diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in
index cdb2b813340..bc04a440826 100644
--- a/dlls/mfplat/Makefile.in
+++ b/dlls/mfplat/Makefile.in
@@ -8,4 +8,5 @@ C_SRCS = \
 	buffer.c \
 	main.c \
 	mediatype.c \
-	queue.c
+	queue.c \
+	sample.c
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index b47d2a9ba16..adfa2d867c1 100644
--- a/dlls/mfplat/buffer.c
+++ b/dlls/mfplat/buffer.c
@@ -63,31 +63,6 @@ struct memory_buffer
     CRITICAL_SECTION cs;
 };
 
-enum sample_prop_flags
-{
-    SAMPLE_PROP_HAS_DURATION  = 1 << 0,
-    SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
-};
-
-struct sample
-{
-    struct attributes attributes;
-    IMFSample IMFSample_iface;
-    IMFTrackedSample IMFTrackedSample_iface;
-
-    IMFMediaBuffer **buffers;
-    size_t buffer_count;
-    size_t capacity;
-    DWORD flags;
-    DWORD prop_flags;
-    LONGLONG duration;
-    LONGLONG timestamp;
-
-    /* Tracked sample functionality. */
-    IRtwqAsyncResult *tracked_result;
-    LONG tracked_refcount;
-};
-
 static inline struct memory_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface)
 {
     return CONTAINING_RECORD(iface, struct memory_buffer, IMFMediaBuffer_iface);
@@ -103,16 +78,6 @@ static struct memory_buffer *impl_from_IMFGetService(IMFGetService *iface)
     return CONTAINING_RECORD(iface, struct memory_buffer, IMFGetService_iface);
 }
 
-static inline struct sample *impl_from_IMFSample(IMFSample *iface)
-{
-    return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
-}
-
-static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
-{
-    return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface);
-}
-
 static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out)
 {
     struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
@@ -1080,950 +1045,3 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
 
     return E_NOTIMPL;
 }
-
-static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
-
-    if (IsEqualIID(riid, &IID_IMFSample) ||
-            IsEqualIID(riid, &IID_IMFAttributes) ||
-            IsEqualIID(riid, &IID_IUnknown))
-    {
-        *out = &sample->IMFSample_iface;
-    }
-    else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample))
-    {
-        *out = &sample->IMFTrackedSample_iface;
-    }
-    else
-    {
-        WARN("Unsupported %s.\n", debugstr_guid(riid));
-        *out = NULL;
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef((IUnknown *)*out);
-    return S_OK;
-}
-
-static ULONG WINAPI sample_AddRef(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    ULONG refcount = InterlockedIncrement(&sample->attributes.ref);
-
-    TRACE("%p, refcount %u.\n", iface, refcount);
-
-    return refcount;
-}
-
-static void release_sample_object(struct sample *sample)
-{
-    size_t i;
-
-    for (i = 0; i < sample->buffer_count; ++i)
-        IMFMediaBuffer_Release(sample->buffers[i]);
-    clear_attributes_object(&sample->attributes);
-    heap_free(sample->buffers);
-    heap_free(sample);
-}
-
-static ULONG WINAPI sample_Release(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    ULONG refcount = InterlockedDecrement(&sample->attributes.ref);
-
-    TRACE("%p, refcount %u.\n", iface, refcount);
-
-    if (!refcount)
-        release_sample_object(sample);
-
-    return refcount;
-}
-
-static ULONG WINAPI sample_tracked_Release(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    ULONG refcount;
-    HRESULT hr;
-
-    EnterCriticalSection(&sample->attributes.cs);
-    refcount = InterlockedDecrement(&sample->attributes.ref);
-    if (sample->tracked_result && sample->tracked_refcount == refcount)
-    {
-        /* Call could fail if queue system is not initialized, it's not critical. */
-        if (FAILED(hr = RtwqInvokeCallback(sample->tracked_result)))
-            WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
-        IRtwqAsyncResult_Release(sample->tracked_result);
-        sample->tracked_result = NULL;
-        sample->tracked_refcount = 0;
-    }
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    TRACE("%p, refcount %u.\n", iface, refcount);
-
-    if (!refcount)
-        release_sample_object(sample);
-
-    return refcount;
-}
-
-static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
-    return attributes_GetItem(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
-
-    return attributes_GetItemType(&sample->attributes, key, type);
-}
-
-static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
-
-    return attributes_CompareItem(&sample->attributes, key, value, result);
-}
-
-static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
-        BOOL *result)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
-
-    return attributes_Compare(&sample->attributes, theirs, type, result);
-}
-
-static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
-    return attributes_GetUINT32(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
-    return attributes_GetUINT64(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
-    return attributes_GetDouble(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
-    return attributes_GetGUID(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
-
-    return attributes_GetStringLength(&sample->attributes, key, length);
-}
-
-static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
-
-    return attributes_GetString(&sample->attributes, key, value, size, length);
-}
-
-static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
-
-    return attributes_GetAllocatedString(&sample->attributes, key, value, length);
-}
-
-static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
-
-    return attributes_GetBlobSize(&sample->attributes, key, size);
-}
-
-static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
-
-    return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
-}
-
-static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
-
-    return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
-}
-
-static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
-
-    return attributes_GetUnknown(&sample->attributes, key, riid, out);
-}
-
-static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
-
-    return attributes_SetItem(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s.\n", iface, debugstr_attr(key));
-
-    return attributes_DeleteItem(&sample->attributes, key);
-}
-
-static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p.\n", iface);
-
-    return attributes_DeleteAllItems(&sample->attributes);
-}
-
-static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
-
-    return attributes_SetUINT32(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
-
-    return attributes_SetUINT64(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
-
-    return attributes_SetDouble(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
-
-    return attributes_SetGUID(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
-
-    return attributes_SetString(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
-
-    return attributes_SetBlob(&sample->attributes, key, buf, size);
-}
-
-static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
-
-    return attributes_SetUnknown(&sample->attributes, key, unknown);
-}
-
-static HRESULT WINAPI sample_LockStore(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p.\n", iface);
-
-    return attributes_LockStore(&sample->attributes);
-}
-
-static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p.\n", iface);
-
-    return attributes_UnlockStore(&sample->attributes);
-}
-
-static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %p.\n", iface, count);
-
-    return attributes_GetCount(&sample->attributes, count);
-}
-
-static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
-
-    return attributes_GetItemByIndex(&sample->attributes, index, key, value);
-}
-
-static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %p.\n", iface, dest);
-
-    return attributes_CopyAllItems(&sample->attributes, dest);
-}
-
-static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %p.\n", iface, flags);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    *flags = sample->flags;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %#x.\n", iface, flags);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    sample->flags = flags;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %p.\n", iface, timestamp);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
-        *timestamp = sample->timestamp;
-    else
-        hr = MF_E_NO_SAMPLE_TIMESTAMP;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
-
-    EnterCriticalSection(&sample->attributes.cs);
-    sample->timestamp = timestamp;
-    sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %p.\n", iface, duration);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
-        *duration = sample->duration;
-    else
-        hr = MF_E_NO_SAMPLE_DURATION;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %s.\n", iface, debugstr_time(duration));
-
-    EnterCriticalSection(&sample->attributes.cs);
-    sample->duration = duration;
-    sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %p.\n", iface, count);
-
-    if (!count)
-        return E_INVALIDARG;
-
-    EnterCriticalSection(&sample->attributes.cs);
-    *count = sample->buffer_count;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %u, %p.\n", iface, index, buffer);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    if (index < sample->buffer_count)
-    {
-        *buffer = sample->buffers[index];
-        IMFMediaBuffer_AddRef(*buffer);
-    }
-    else
-        hr = E_INVALIDARG;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static unsigned int sample_get_total_length(struct sample *sample)
-{
-    DWORD total_length = 0, length;
-    size_t i;
-
-    for (i = 0; i < sample->buffer_count; ++i)
-    {
-        length = 0;
-        if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
-            total_length += length;
-    }
-
-    return total_length;
-}
-
-static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
-{
-    DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
-    BYTE *src_ptr, *dst_ptr;
-    BOOL locked;
-    HRESULT hr;
-    size_t i;
-
-    total_length = sample_get_total_length(sample);
-    dst_current_length = 0;
-
-    dst_ptr = NULL;
-    dst_length = current_length = 0;
-    locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
-    if (locked)
-    {
-        if (dst_length < total_length)
-            hr = MF_E_BUFFERTOOSMALL;
-        else if (dst_ptr)
-        {
-            for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
-            {
-                src_ptr = NULL;
-                src_max_length = current_length = 0;
-                if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
-                {
-                    if (src_ptr)
-                    {
-                        if (current_length > dst_length)
-                            hr = MF_E_BUFFERTOOSMALL;
-                        else if (current_length)
-                        {
-                            memcpy(dst_ptr, src_ptr, current_length);
-                            dst_length -= current_length;
-                            dst_current_length += current_length;
-                            dst_ptr += current_length;
-                        }
-                    }
-                    IMFMediaBuffer_Unlock(sample->buffers[i]);
-                }
-            }
-        }
-    }
-
-    if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
-        WARN("Failed to set buffer length.\n");
-
-    if (locked)
-        IMFMediaBuffer_Unlock(buffer);
-
-    return hr;
-}
-
-static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    unsigned int total_length, i;
-    IMFMediaBuffer *dest_buffer;
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %p.\n", iface, buffer);
-
-    EnterCriticalSection(&sample->attributes.cs);
-
-    if (sample->buffer_count == 0)
-        hr = E_UNEXPECTED;
-    else if (sample->buffer_count > 1)
-    {
-        total_length = sample_get_total_length(sample);
-        if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
-        {
-            if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
-            {
-                for (i = 0; i < sample->buffer_count; ++i)
-                    IMFMediaBuffer_Release(sample->buffers[i]);
-
-                sample->buffers[0] = dest_buffer;
-                IMFMediaBuffer_AddRef(sample->buffers[0]);
-
-                sample->buffer_count = 1;
-            }
-            IMFMediaBuffer_Release(dest_buffer);
-        }
-    }
-
-    if (SUCCEEDED(hr) && buffer)
-    {
-        *buffer = sample->buffers[0];
-        IMFMediaBuffer_AddRef(*buffer);
-    }
-
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %p.\n", iface, buffer);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
-            sizeof(*sample->buffers)))
-        hr = E_OUTOFMEMORY;
-    else
-    {
-        sample->buffers[sample->buffer_count++] = buffer;
-        IMFMediaBuffer_AddRef(buffer);
-    }
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %u.\n", iface, index);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    if (index < sample->buffer_count)
-    {
-        IMFMediaBuffer_Release(sample->buffers[index]);
-        if (index < sample->buffer_count - 1)
-        {
-            memmove(&sample->buffers[index], &sample->buffers[index+1],
-                    (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
-        }
-        sample->buffer_count--;
-    }
-    else
-        hr = E_INVALIDARG;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    size_t i;
-
-    TRACE("%p.\n", iface);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    for (i = 0; i < sample->buffer_count; ++i)
-         IMFMediaBuffer_Release(sample->buffers[i]);
-    sample->buffer_count = 0;
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-
-    TRACE("%p, %p.\n", iface, total_length);
-
-    EnterCriticalSection(&sample->attributes.cs);
-    *total_length = sample_get_total_length(sample);
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
-{
-    struct sample *sample = impl_from_IMFSample(iface);
-    DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
-    BYTE *src_ptr, *dst_ptr;
-    BOOL locked;
-    HRESULT hr;
-    size_t i;
-
-    TRACE("%p, %p.\n", iface, buffer);
-
-    EnterCriticalSection(&sample->attributes.cs);
-
-    total_length = sample_get_total_length(sample);
-    dst_current_length = 0;
-
-    dst_ptr = NULL;
-    dst_length = current_length = 0;
-    locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
-    if (locked)
-    {
-        if (dst_length < total_length)
-            hr = MF_E_BUFFERTOOSMALL;
-        else if (dst_ptr)
-        {
-            for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
-            {
-                src_ptr = NULL;
-                src_max_length = current_length = 0;
-                if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
-                {
-                    if (src_ptr)
-                    {
-                        if (current_length > dst_length)
-                            hr = MF_E_BUFFERTOOSMALL;
-                        else if (current_length)
-                        {
-                            memcpy(dst_ptr, src_ptr, current_length);
-                            dst_length -= current_length;
-                            dst_current_length += current_length;
-                            dst_ptr += current_length;
-                        }
-                    }
-                    IMFMediaBuffer_Unlock(sample->buffers[i]);
-                }
-            }
-        }
-    }
-
-    IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
-
-    if (locked)
-        IMFMediaBuffer_Unlock(buffer);
-
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static const IMFSampleVtbl samplevtbl =
-{
-    sample_QueryInterface,
-    sample_AddRef,
-    sample_Release,
-    sample_GetItem,
-    sample_GetItemType,
-    sample_CompareItem,
-    sample_Compare,
-    sample_GetUINT32,
-    sample_GetUINT64,
-    sample_GetDouble,
-    sample_GetGUID,
-    sample_GetStringLength,
-    sample_GetString,
-    sample_GetAllocatedString,
-    sample_GetBlobSize,
-    sample_GetBlob,
-    sample_GetAllocatedBlob,
-    sample_GetUnknown,
-    sample_SetItem,
-    sample_DeleteItem,
-    sample_DeleteAllItems,
-    sample_SetUINT32,
-    sample_SetUINT64,
-    sample_SetDouble,
-    sample_SetGUID,
-    sample_SetString,
-    sample_SetBlob,
-    sample_SetUnknown,
-    sample_LockStore,
-    sample_UnlockStore,
-    sample_GetCount,
-    sample_GetItemByIndex,
-    sample_CopyAllItems,
-    sample_GetSampleFlags,
-    sample_SetSampleFlags,
-    sample_GetSampleTime,
-    sample_SetSampleTime,
-    sample_GetSampleDuration,
-    sample_SetSampleDuration,
-    sample_GetBufferCount,
-    sample_GetBufferByIndex,
-    sample_ConvertToContiguousBuffer,
-    sample_AddBuffer,
-    sample_RemoveBufferByIndex,
-    sample_RemoveAllBuffers,
-    sample_GetTotalLength,
-    sample_CopyToBuffer,
-};
-
-static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
-{
-    struct sample *sample = impl_from_IMFTrackedSample(iface);
-    return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
-}
-
-static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
-{
-    struct sample *sample = impl_from_IMFTrackedSample(iface);
-    return IMFSample_AddRef(&sample->IMFSample_iface);
-}
-
-static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
-{
-    struct sample *sample = impl_from_IMFTrackedSample(iface);
-    return IMFSample_Release(&sample->IMFSample_iface);
-}
-
-static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
-        IMFAsyncCallback *sample_allocator, IUnknown *state)
-{
-    struct sample *sample = impl_from_IMFTrackedSample(iface);
-    HRESULT hr = S_OK;
-
-    TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
-
-    EnterCriticalSection(&sample->attributes.cs);
-
-    if (sample->tracked_result)
-        hr = MF_E_NOTACCEPTING;
-    else
-    {
-        if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
-                state, &sample->tracked_result)))
-        {
-            /* Account for additional refcount brought by 'state' object. This threshold is used
-               on Release() to invoke tracker callback.  */
-            sample->tracked_refcount = 1;
-            if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
-                    state == (IUnknown *)&sample->IMFSample_iface)
-            {
-                ++sample->tracked_refcount;
-            }
-        }
-    }
-
-    LeaveCriticalSection(&sample->attributes.cs);
-
-    return hr;
-}
-
-static const IMFTrackedSampleVtbl tracked_sample_vtbl =
-{
-    tracked_sample_QueryInterface,
-    tracked_sample_AddRef,
-    tracked_sample_Release,
-    tracked_sample_SetAllocator,
-};
-
-static const IMFSampleVtbl sample_tracked_vtbl =
-{
-    sample_QueryInterface,
-    sample_AddRef,
-    sample_tracked_Release,
-    sample_GetItem,
-    sample_GetItemType,
-    sample_CompareItem,
-    sample_Compare,
-    sample_GetUINT32,
-    sample_GetUINT64,
-    sample_GetDouble,
-    sample_GetGUID,
-    sample_GetStringLength,
-    sample_GetString,
-    sample_GetAllocatedString,
-    sample_GetBlobSize,
-    sample_GetBlob,
-    sample_GetAllocatedBlob,
-    sample_GetUnknown,
-    sample_SetItem,
-    sample_DeleteItem,
-    sample_DeleteAllItems,
-    sample_SetUINT32,
-    sample_SetUINT64,
-    sample_SetDouble,
-    sample_SetGUID,
-    sample_SetString,
-    sample_SetBlob,
-    sample_SetUnknown,
-    sample_LockStore,
-    sample_UnlockStore,
-    sample_GetCount,
-    sample_GetItemByIndex,
-    sample_CopyAllItems,
-    sample_GetSampleFlags,
-    sample_SetSampleFlags,
-    sample_GetSampleTime,
-    sample_SetSampleTime,
-    sample_GetSampleDuration,
-    sample_SetSampleDuration,
-    sample_GetBufferCount,
-    sample_GetBufferByIndex,
-    sample_ConvertToContiguousBuffer,
-    sample_AddBuffer,
-    sample_RemoveBufferByIndex,
-    sample_RemoveAllBuffers,
-    sample_GetTotalLength,
-    sample_CopyToBuffer,
-};
-
-
-/***********************************************************************
- *      MFCreateSample (mfplat.@)
- */
-HRESULT WINAPI MFCreateSample(IMFSample **sample)
-{
-    struct sample *object;
-    HRESULT hr;
-
-    TRACE("%p.\n", sample);
-
-    object = heap_alloc_zero(sizeof(*object));
-    if (!object)
-        return E_OUTOFMEMORY;
-
-    if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
-    {
-        heap_free(object);
-        return hr;
-    }
-
-    object->IMFSample_iface.lpVtbl = &samplevtbl;
-
-    *sample = &object->IMFSample_iface;
-
-    TRACE("Created sample %p.\n", *sample);
-
-    return S_OK;
-}
-
-/***********************************************************************
- *      MFCreateTrackedSample (mfplat.@)
- */
-HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
-{
-    struct sample *object;
-    HRESULT hr;
-
-    TRACE("%p.\n", sample);
-
-    object = heap_alloc_zero(sizeof(*object));
-    if (!object)
-        return E_OUTOFMEMORY;
-
-    if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
-    {
-        heap_free(object);
-        return hr;
-    }
-
-    object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
-    object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
-
-    *sample = &object->IMFTrackedSample_iface;
-
-    return S_OK;
-}
diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c
new file mode 100644
index 00000000000..bd67fb731fc
--- /dev/null
+++ b/dlls/mfplat/sample.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright 2021 Nikolay Sivov for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include "mfplat_private.h"
+#include "rtworkq.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+enum sample_prop_flags
+{
+    SAMPLE_PROP_HAS_DURATION  = 1 << 0,
+    SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
+};
+
+struct sample
+{
+    struct attributes attributes;
+    IMFSample IMFSample_iface;
+    IMFTrackedSample IMFTrackedSample_iface;
+
+    IMFMediaBuffer **buffers;
+    size_t buffer_count;
+    size_t capacity;
+    DWORD flags;
+    DWORD prop_flags;
+    LONGLONG duration;
+    LONGLONG timestamp;
+
+    /* Tracked sample functionality. */
+    IRtwqAsyncResult *tracked_result;
+    LONG tracked_refcount;
+};
+
+static struct sample *impl_from_IMFSample(IMFSample *iface)
+{
+    return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
+}
+
+static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
+{
+    return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface);
+}
+
+static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualIID(riid, &IID_IMFSample) ||
+            IsEqualIID(riid, &IID_IMFAttributes) ||
+            IsEqualIID(riid, &IID_IUnknown))
+    {
+        *out = &sample->IMFSample_iface;
+    }
+    else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample))
+    {
+        *out = &sample->IMFTrackedSample_iface;
+    }
+    else
+    {
+        WARN("Unsupported %s.\n", debugstr_guid(riid));
+        *out = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI sample_AddRef(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    ULONG refcount = InterlockedIncrement(&sample->attributes.ref);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static void release_sample_object(struct sample *sample)
+{
+    size_t i;
+
+    for (i = 0; i < sample->buffer_count; ++i)
+        IMFMediaBuffer_Release(sample->buffers[i]);
+    clear_attributes_object(&sample->attributes);
+    heap_free(sample->buffers);
+    heap_free(sample);
+}
+
+static ULONG WINAPI sample_Release(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    ULONG refcount = InterlockedDecrement(&sample->attributes.ref);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    if (!refcount)
+        release_sample_object(sample);
+
+    return refcount;
+}
+
+static ULONG WINAPI sample_tracked_Release(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    ULONG refcount;
+    HRESULT hr;
+
+    EnterCriticalSection(&sample->attributes.cs);
+    refcount = InterlockedDecrement(&sample->attributes.ref);
+    if (sample->tracked_result && sample->tracked_refcount == refcount)
+    {
+        /* Call could fail if queue system is not initialized, it's not critical. */
+        if (FAILED(hr = RtwqInvokeCallback(sample->tracked_result)))
+            WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
+        IRtwqAsyncResult_Release(sample->tracked_result);
+        sample->tracked_result = NULL;
+        sample->tracked_refcount = 0;
+    }
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    if (!refcount)
+        release_sample_object(sample);
+
+    return refcount;
+}
+
+static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+    return attributes_GetItem(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
+
+    return attributes_GetItemType(&sample->attributes, key, type);
+}
+
+static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
+
+    return attributes_CompareItem(&sample->attributes, key, value, result);
+}
+
+static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
+        BOOL *result)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
+
+    return attributes_Compare(&sample->attributes, theirs, type, result);
+}
+
+static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+    return attributes_GetUINT32(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+    return attributes_GetUINT64(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+    return attributes_GetDouble(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+    return attributes_GetGUID(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
+
+    return attributes_GetStringLength(&sample->attributes, key, length);
+}
+
+static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
+
+    return attributes_GetString(&sample->attributes, key, value, size, length);
+}
+
+static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
+
+    return attributes_GetAllocatedString(&sample->attributes, key, value, length);
+}
+
+static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
+
+    return attributes_GetBlobSize(&sample->attributes, key, size);
+}
+
+static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
+
+    return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
+}
+
+static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
+
+    return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
+}
+
+static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
+
+    return attributes_GetUnknown(&sample->attributes, key, riid, out);
+}
+
+static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
+
+    return attributes_SetItem(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s.\n", iface, debugstr_attr(key));
+
+    return attributes_DeleteItem(&sample->attributes, key);
+}
+
+static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p.\n", iface);
+
+    return attributes_DeleteAllItems(&sample->attributes);
+}
+
+static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
+
+    return attributes_SetUINT32(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
+
+    return attributes_SetUINT64(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
+
+    return attributes_SetDouble(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
+
+    return attributes_SetGUID(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
+
+    return attributes_SetString(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
+
+    return attributes_SetBlob(&sample->attributes, key, buf, size);
+}
+
+static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
+
+    return attributes_SetUnknown(&sample->attributes, key, unknown);
+}
+
+static HRESULT WINAPI sample_LockStore(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p.\n", iface);
+
+    return attributes_LockStore(&sample->attributes);
+}
+
+static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p.\n", iface);
+
+    return attributes_UnlockStore(&sample->attributes);
+}
+
+static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %p.\n", iface, count);
+
+    return attributes_GetCount(&sample->attributes, count);
+}
+
+static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
+
+    return attributes_GetItemByIndex(&sample->attributes, index, key, value);
+}
+
+static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %p.\n", iface, dest);
+
+    return attributes_CopyAllItems(&sample->attributes, dest);
+}
+
+static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %p.\n", iface, flags);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    *flags = sample->flags;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %#x.\n", iface, flags);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    sample->flags = flags;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p.\n", iface, timestamp);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
+        *timestamp = sample->timestamp;
+    else
+        hr = MF_E_NO_SAMPLE_TIMESTAMP;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
+
+    EnterCriticalSection(&sample->attributes.cs);
+    sample->timestamp = timestamp;
+    sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p.\n", iface, duration);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
+        *duration = sample->duration;
+    else
+        hr = MF_E_NO_SAMPLE_DURATION;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %s.\n", iface, debugstr_time(duration));
+
+    EnterCriticalSection(&sample->attributes.cs);
+    sample->duration = duration;
+    sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %p.\n", iface, count);
+
+    if (!count)
+        return E_INVALIDARG;
+
+    EnterCriticalSection(&sample->attributes.cs);
+    *count = sample->buffer_count;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %u, %p.\n", iface, index, buffer);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    if (index < sample->buffer_count)
+    {
+        *buffer = sample->buffers[index];
+        IMFMediaBuffer_AddRef(*buffer);
+    }
+    else
+        hr = E_INVALIDARG;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static unsigned int sample_get_total_length(struct sample *sample)
+{
+    DWORD total_length = 0, length;
+    size_t i;
+
+    for (i = 0; i < sample->buffer_count; ++i)
+    {
+        length = 0;
+        if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
+            total_length += length;
+    }
+
+    return total_length;
+}
+
+static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
+{
+    DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
+    BYTE *src_ptr, *dst_ptr;
+    BOOL locked;
+    HRESULT hr;
+    size_t i;
+
+    total_length = sample_get_total_length(sample);
+    dst_current_length = 0;
+
+    dst_ptr = NULL;
+    dst_length = current_length = 0;
+    locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
+    if (locked)
+    {
+        if (dst_length < total_length)
+            hr = MF_E_BUFFERTOOSMALL;
+        else if (dst_ptr)
+        {
+            for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
+            {
+                src_ptr = NULL;
+                src_max_length = current_length = 0;
+                if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
+                {
+                    if (src_ptr)
+                    {
+                        if (current_length > dst_length)
+                            hr = MF_E_BUFFERTOOSMALL;
+                        else if (current_length)
+                        {
+                            memcpy(dst_ptr, src_ptr, current_length);
+                            dst_length -= current_length;
+                            dst_current_length += current_length;
+                            dst_ptr += current_length;
+                        }
+                    }
+                    IMFMediaBuffer_Unlock(sample->buffers[i]);
+                }
+            }
+        }
+    }
+
+    if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
+        WARN("Failed to set buffer length.\n");
+
+    if (locked)
+        IMFMediaBuffer_Unlock(buffer);
+
+    return hr;
+}
+
+static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    unsigned int total_length, i;
+    IMFMediaBuffer *dest_buffer;
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p.\n", iface, buffer);
+
+    EnterCriticalSection(&sample->attributes.cs);
+
+    if (sample->buffer_count == 0)
+        hr = E_UNEXPECTED;
+    else if (sample->buffer_count > 1)
+    {
+        total_length = sample_get_total_length(sample);
+        if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
+        {
+            if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
+            {
+                for (i = 0; i < sample->buffer_count; ++i)
+                    IMFMediaBuffer_Release(sample->buffers[i]);
+
+                sample->buffers[0] = dest_buffer;
+                IMFMediaBuffer_AddRef(sample->buffers[0]);
+
+                sample->buffer_count = 1;
+            }
+            IMFMediaBuffer_Release(dest_buffer);
+        }
+    }
+
+    if (SUCCEEDED(hr) && buffer)
+    {
+        *buffer = sample->buffers[0];
+        IMFMediaBuffer_AddRef(*buffer);
+    }
+
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p.\n", iface, buffer);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
+            sizeof(*sample->buffers)))
+        hr = E_OUTOFMEMORY;
+    else
+    {
+        sample->buffers[sample->buffer_count++] = buffer;
+        IMFMediaBuffer_AddRef(buffer);
+    }
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %u.\n", iface, index);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    if (index < sample->buffer_count)
+    {
+        IMFMediaBuffer_Release(sample->buffers[index]);
+        if (index < sample->buffer_count - 1)
+        {
+            memmove(&sample->buffers[index], &sample->buffers[index+1],
+                    (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
+        }
+        sample->buffer_count--;
+    }
+    else
+        hr = E_INVALIDARG;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    size_t i;
+
+    TRACE("%p.\n", iface);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    for (i = 0; i < sample->buffer_count; ++i)
+         IMFMediaBuffer_Release(sample->buffers[i]);
+    sample->buffer_count = 0;
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+
+    TRACE("%p, %p.\n", iface, total_length);
+
+    EnterCriticalSection(&sample->attributes.cs);
+    *total_length = sample_get_total_length(sample);
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
+{
+    struct sample *sample = impl_from_IMFSample(iface);
+    DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
+    BYTE *src_ptr, *dst_ptr;
+    BOOL locked;
+    HRESULT hr;
+    size_t i;
+
+    TRACE("%p, %p.\n", iface, buffer);
+
+    EnterCriticalSection(&sample->attributes.cs);
+
+    total_length = sample_get_total_length(sample);
+    dst_current_length = 0;
+
+    dst_ptr = NULL;
+    dst_length = current_length = 0;
+    locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
+    if (locked)
+    {
+        if (dst_length < total_length)
+            hr = MF_E_BUFFERTOOSMALL;
+        else if (dst_ptr)
+        {
+            for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
+            {
+                src_ptr = NULL;
+                src_max_length = current_length = 0;
+                if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
+                {
+                    if (src_ptr)
+                    {
+                        if (current_length > dst_length)
+                            hr = MF_E_BUFFERTOOSMALL;
+                        else if (current_length)
+                        {
+                            memcpy(dst_ptr, src_ptr, current_length);
+                            dst_length -= current_length;
+                            dst_current_length += current_length;
+                            dst_ptr += current_length;
+                        }
+                    }
+                    IMFMediaBuffer_Unlock(sample->buffers[i]);
+                }
+            }
+        }
+    }
+
+    IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
+
+    if (locked)
+        IMFMediaBuffer_Unlock(buffer);
+
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static const IMFSampleVtbl samplevtbl =
+{
+    sample_QueryInterface,
+    sample_AddRef,
+    sample_Release,
+    sample_GetItem,
+    sample_GetItemType,
+    sample_CompareItem,
+    sample_Compare,
+    sample_GetUINT32,
+    sample_GetUINT64,
+    sample_GetDouble,
+    sample_GetGUID,
+    sample_GetStringLength,
+    sample_GetString,
+    sample_GetAllocatedString,
+    sample_GetBlobSize,
+    sample_GetBlob,
+    sample_GetAllocatedBlob,
+    sample_GetUnknown,
+    sample_SetItem,
+    sample_DeleteItem,
+    sample_DeleteAllItems,
+    sample_SetUINT32,
+    sample_SetUINT64,
+    sample_SetDouble,
+    sample_SetGUID,
+    sample_SetString,
+    sample_SetBlob,
+    sample_SetUnknown,
+    sample_LockStore,
+    sample_UnlockStore,
+    sample_GetCount,
+    sample_GetItemByIndex,
+    sample_CopyAllItems,
+    sample_GetSampleFlags,
+    sample_SetSampleFlags,
+    sample_GetSampleTime,
+    sample_SetSampleTime,
+    sample_GetSampleDuration,
+    sample_SetSampleDuration,
+    sample_GetBufferCount,
+    sample_GetBufferByIndex,
+    sample_ConvertToContiguousBuffer,
+    sample_AddBuffer,
+    sample_RemoveBufferByIndex,
+    sample_RemoveAllBuffers,
+    sample_GetTotalLength,
+    sample_CopyToBuffer,
+};
+
+static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
+{
+    struct sample *sample = impl_from_IMFTrackedSample(iface);
+    return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
+}
+
+static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
+{
+    struct sample *sample = impl_from_IMFTrackedSample(iface);
+    return IMFSample_AddRef(&sample->IMFSample_iface);
+}
+
+static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
+{
+    struct sample *sample = impl_from_IMFTrackedSample(iface);
+    return IMFSample_Release(&sample->IMFSample_iface);
+}
+
+static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
+        IMFAsyncCallback *sample_allocator, IUnknown *state)
+{
+    struct sample *sample = impl_from_IMFTrackedSample(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
+
+    EnterCriticalSection(&sample->attributes.cs);
+
+    if (sample->tracked_result)
+        hr = MF_E_NOTACCEPTING;
+    else
+    {
+        if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
+                state, &sample->tracked_result)))
+        {
+            /* Account for additional refcount brought by 'state' object. This threshold is used
+               on Release() to invoke tracker callback.  */
+            sample->tracked_refcount = 1;
+            if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
+                    state == (IUnknown *)&sample->IMFSample_iface)
+            {
+                ++sample->tracked_refcount;
+            }
+        }
+    }
+
+    LeaveCriticalSection(&sample->attributes.cs);
+
+    return hr;
+}
+
+static const IMFTrackedSampleVtbl tracked_sample_vtbl =
+{
+    tracked_sample_QueryInterface,
+    tracked_sample_AddRef,
+    tracked_sample_Release,
+    tracked_sample_SetAllocator,
+};
+
+static const IMFSampleVtbl sample_tracked_vtbl =
+{
+    sample_QueryInterface,
+    sample_AddRef,
+    sample_tracked_Release,
+    sample_GetItem,
+    sample_GetItemType,
+    sample_CompareItem,
+    sample_Compare,
+    sample_GetUINT32,
+    sample_GetUINT64,
+    sample_GetDouble,
+    sample_GetGUID,
+    sample_GetStringLength,
+    sample_GetString,
+    sample_GetAllocatedString,
+    sample_GetBlobSize,
+    sample_GetBlob,
+    sample_GetAllocatedBlob,
+    sample_GetUnknown,
+    sample_SetItem,
+    sample_DeleteItem,
+    sample_DeleteAllItems,
+    sample_SetUINT32,
+    sample_SetUINT64,
+    sample_SetDouble,
+    sample_SetGUID,
+    sample_SetString,
+    sample_SetBlob,
+    sample_SetUnknown,
+    sample_LockStore,
+    sample_UnlockStore,
+    sample_GetCount,
+    sample_GetItemByIndex,
+    sample_CopyAllItems,
+    sample_GetSampleFlags,
+    sample_SetSampleFlags,
+    sample_GetSampleTime,
+    sample_SetSampleTime,
+    sample_GetSampleDuration,
+    sample_SetSampleDuration,
+    sample_GetBufferCount,
+    sample_GetBufferByIndex,
+    sample_ConvertToContiguousBuffer,
+    sample_AddBuffer,
+    sample_RemoveBufferByIndex,
+    sample_RemoveAllBuffers,
+    sample_GetTotalLength,
+    sample_CopyToBuffer,
+};
+
+/***********************************************************************
+ *      MFCreateSample (mfplat.@)
+ */
+HRESULT WINAPI MFCreateSample(IMFSample **sample)
+{
+    struct sample *object;
+    HRESULT hr;
+
+    TRACE("%p.\n", sample);
+
+    object = heap_alloc_zero(sizeof(*object));
+    if (!object)
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
+    {
+        heap_free(object);
+        return hr;
+    }
+
+    object->IMFSample_iface.lpVtbl = &samplevtbl;
+
+    *sample = &object->IMFSample_iface;
+
+    TRACE("Created sample %p.\n", *sample);
+
+    return S_OK;
+}
+
+/***********************************************************************
+ *      MFCreateTrackedSample (mfplat.@)
+ */
+HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
+{
+    struct sample *object;
+    HRESULT hr;
+
+    TRACE("%p.\n", sample);
+
+    object = heap_alloc_zero(sizeof(*object));
+    if (!object)
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
+    {
+        heap_free(object);
+        return hr;
+    }
+
+    object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
+    object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
+
+    *sample = &object->IMFTrackedSample_iface;
+
+    return S_OK;
+}
-- 
2.30.0




More information about the wine-devel mailing list