From 851113b06fcde958782eeb342631794299bed924 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 5 Mar 2019 10:49:42 +0300 Subject: [PATCH] mfplat: Implement buffer collection for sample. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mfplat/buffer.c | 127 ++++++++++++++++++++++++++++++----- dlls/mfplat/main.c | 28 -------- dlls/mfplat/mediatype.c | 1 - dlls/mfplat/mfplat_private.h | 29 ++++++++ dlls/mfplat/queue.c | 1 - dlls/mfplat/tests/mfplat.c | 74 +++++++++++++++++++- 6 files changed, 209 insertions(+), 51 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index f60c015c6c2..833ec041a95 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -21,7 +21,6 @@ #include "mfplat_private.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -39,6 +38,12 @@ struct sample { struct attributes attributes; IMFSample IMFSample_iface; + + IMFMediaBuffer **buffers; + size_t buffer_count; + size_t capacity; + DWORD flags; + CRITICAL_SECTION cs; }; static inline struct memory_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) @@ -258,11 +263,16 @@ static ULONG WINAPI sample_Release(IMFSample *iface) { struct sample *sample = impl_from_IMFSample(iface); ULONG refcount = InterlockedDecrement(&sample->attributes.ref); + size_t i; TRACE("%p, refcount %u.\n", iface, refcount); if (!refcount) { + for (i = 0; i < sample->buffer_count; ++i) + IMFMediaBuffer_Release(sample->buffers[i]); + DeleteCriticalSection(&sample->cs); + heap_free(sample->buffers); heap_free(sample); } @@ -453,9 +463,15 @@ static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest) static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags) { - FIXME("%p, %p.\n", iface, flags); + struct sample *sample = impl_from_IMFSample(iface); - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, flags); + + EnterCriticalSection(&sample->cs); + *flags = sample->flags; + LeaveCriticalSection(&sample->cs); + + return S_OK; } static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags) @@ -495,19 +511,38 @@ static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG durati static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count) { - FIXME("%p, %p.\n", iface, count); + struct sample *sample = impl_from_IMFSample(iface); - if (*count) - *count = 0; + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_INVALIDARG; + + EnterCriticalSection(&sample->cs); + *count = sample->buffer_count; + EnterCriticalSection(&sample->cs); return S_OK; } static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer) { - FIXME("%p, %u, %p.\n", iface, index, buffer); + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, buffer); + + EnterCriticalSection(&sample->cs); + if (index < sample->buffer_count) + { + *buffer = sample->buffers[index]; + IMFMediaBuffer_AddRef(*buffer); + } + else + hr = E_INVALIDARG; + LeaveCriticalSection(&sample->cs); + + return hr; } static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer) @@ -519,30 +554,85 @@ static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMedi static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer) { - FIXME("%p, %p.\n", iface, buffer); + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, buffer); + + EnterCriticalSection(&sample->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->cs); + + return hr; } static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index) { - FIXME("%p, %u.\n", iface, index); + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %u.\n", iface, index); + + EnterCriticalSection(&sample->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->cs); + + return hr; } static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface) { - FIXME("%p.\n", iface); + struct sample *sample = impl_from_IMFSample(iface); + size_t i; - return E_NOTIMPL; + TRACE("%p.\n", iface); + + EnterCriticalSection(&sample->cs); + for (i = 0; i < sample->buffer_count; ++i) + IMFMediaBuffer_Release(sample->buffers[i]); + sample->buffer_count = 0; + LeaveCriticalSection(&sample->cs); + + return S_OK; } -static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *length) +static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length) { - FIXME("%p, %p.\n", iface, length); + struct sample *sample = impl_from_IMFSample(iface); + DWORD length; + size_t i; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, total_length); + + *total_length = 0; + + EnterCriticalSection(&sample->cs); + for (i = 0; i < sample->buffer_count; ++i) + { + if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length))) + *total_length += length; + } + LeaveCriticalSection(&sample->cs); + + return S_OK; } static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer) @@ -612,12 +702,13 @@ HRESULT WINAPI MFCreateSample(IMFSample **sample) TRACE("%p.\n", sample); - object = heap_alloc(sizeof(*object)); + object = heap_alloc_zero(sizeof(*object)); if (!object) return E_OUTOFMEMORY; init_attribute_object(&object->attributes, 0); object->IMFSample_iface.lpVtbl = &samplevtbl; + InitializeCriticalSection(&object->cs); *sample = &object->IMFSample_iface; diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 787c40c6b60..2d7e02e4730 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -29,7 +29,6 @@ #include "initguid.h" -#include "wine/heap.h" #include "wine/debug.h" #include "wine/unicode.h" #include "wine/list.h" @@ -129,33 +128,6 @@ static BOOL GUIDFromString(LPCWSTR s, GUID *id) return FALSE; } -static BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) -{ - size_t new_capacity, max_capacity; - void *new_elements; - - if (count <= *capacity) - return TRUE; - - max_capacity = ~(SIZE_T)0 / size; - if (count > max_capacity) - return FALSE; - - new_capacity = max(4, *capacity); - while (new_capacity < count && new_capacity <= max_capacity / 2) - new_capacity *= 2; - if (new_capacity < count) - new_capacity = max_capacity; - - if (!(new_elements = heap_realloc(*elements, new_capacity * size))) - return FALSE; - - *elements = new_elements; - *capacity = new_capacity; - - return TRUE; -} - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { switch (reason) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 195ab38da57..7abbf317968 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -21,7 +21,6 @@ #include "mfplat_private.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h index e5b0647e63b..72f8f684f66 100644 --- a/dlls/mfplat/mfplat_private.h +++ b/dlls/mfplat/mfplat_private.h @@ -20,6 +20,8 @@ #include "mfidl.h" #include "mferror.h" +#include "wine/heap.h" + typedef struct attributes { IMFAttributes IMFAttributes_iface; @@ -31,3 +33,30 @@ extern void init_attribute_object(mfattributes *object, UINT32 size) DECLSPEC_HI extern void init_system_queues(void) DECLSPEC_HIDDEN; extern void shutdown_system_queues(void) DECLSPEC_HIDDEN; extern BOOL is_platform_locked(void) DECLSPEC_HIDDEN; + +static inline BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) +{ + size_t new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return TRUE; + + max_capacity = ~(SIZE_T)0 / size; + if (count > max_capacity) + return FALSE; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = heap_realloc(*elements, new_capacity * size))) + return FALSE; + + *elements = new_elements; + *capacity = new_capacity; + + return TRUE; +} diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c index 4d3322840c6..1b9ef38a4ee 100644 --- a/dlls/mfplat/queue.c +++ b/dlls/mfplat/queue.c @@ -21,7 +21,6 @@ #define COBJMACROS #include "wine/debug.h" -#include "wine/heap.h" #include "wine/list.h" #include "mfplat_private.h" diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 674bcf418e0..19ec6ec6d13 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -714,19 +714,87 @@ static void test_system_memory_buffer(void) IMFMediaBuffer_Release(buffer); } -static void test_MFSample(void) +static void test_sample(void) { + IMFMediaBuffer *buffer, *buffer2; + DWORD count, flags, length; IMFSample *sample; + LONGLONG time; HRESULT hr; - UINT32 count; hr = MFCreateSample( &sample ); ok(hr == S_OK, "got 0x%08x\n", hr); + hr = IMFSample_GetBufferCount(sample, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + hr = IMFSample_GetBufferCount(sample, &count); ok(hr == S_OK, "got 0x%08x\n", hr); ok(count == 0, "got %d\n", count); + hr = IMFSample_GetSampleFlags(sample, &flags); + ok(hr == S_OK, "Failed to get sample flags, hr %#x.\n", hr); + ok(!flags, "Unexpected flags %#x.\n", flags); + + hr = IMFSample_GetSampleTime(sample, &time); +todo_wine + ok(hr == MF_E_NO_SAMPLE_TIMESTAMP, "Unexpected hr %#x.\n", hr); + + hr = IMFSample_GetSampleDuration(sample, &time); +todo_wine + ok(hr == MF_E_NO_SAMPLE_DURATION, "Unexpected hr %#x.\n", hr); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFSample_RemoveBufferByIndex(sample, 0); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFSample_RemoveAllBuffers(sample); + ok(hr == S_OK, "Failed to remove all, hr %#x.\n", hr); + + hr = IMFSample_GetTotalLength(sample, &length); + ok(hr == S_OK, "Failed to get total length, hr %#x.\n", hr); + ok(!length, "Unexpected total length %u.\n", length); + + hr = MFCreateMemoryBuffer(16, &buffer); + ok(hr == S_OK, "Failed to create buffer, hr %#x.\n", hr); + + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Failed to add buffer, hr %#x.\n", hr); + + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Failed to add buffer, hr %#x.\n", hr); + + hr = IMFSample_GetBufferCount(sample, &count); + ok(hr == S_OK, "Failed to get buffer count, hr %#x.\n", hr); + ok(count == 2, "Unexpected buffer count %u.\n", count); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer2); + ok(hr == S_OK, "Failed to get buffer, hr %#x.\n", hr); + ok(buffer2 == buffer, "Unexpected object.\n"); + IMFMediaBuffer_Release(buffer2); + + hr = IMFSample_GetTotalLength(sample, &length); + ok(hr == S_OK, "Failed to get total length, hr %#x.\n", hr); + ok(!length, "Unexpected total length %u.\n", length); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 2); + ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr); + + hr = IMFSample_GetTotalLength(sample, &length); + ok(hr == S_OK, "Failed to get total length, hr %#x.\n", hr); + ok(length == 4, "Unexpected total length %u.\n", length); + + hr = IMFSample_RemoveBufferByIndex(sample, 1); + ok(hr == S_OK, "Failed to remove buffer, hr %#x.\n", hr); + + hr = IMFSample_GetTotalLength(sample, &length); + ok(hr == S_OK, "Failed to get total length, hr %#x.\n", hr); + ok(length == 2, "Unexpected total length %u.\n", length); + + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); } @@ -1541,7 +1609,7 @@ START_TEST(mfplat) test_MFCreateMediaType(); test_MFCreateMediaEvent(); test_MFCreateAttributes(); - test_MFSample(); + test_sample(); test_MFCreateFile(); test_MFCreateMFByteStreamOnStream(); test_system_memory_buffer();