From db549a680e900d28bed2ba95cb9da683e8ed9beb Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Wed, 27 Jan 2021 17:37:00 +0300 Subject: [PATCH] mfmediaengine: Add partial implementation of a time range object. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mfmediaengine/main.c | 212 ++++++++++++++++++++++- dlls/mfmediaengine/tests/mfmediaengine.c | 98 +++++++++++ 2 files changed, 307 insertions(+), 3 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 5981548c9f8..0573ea844c1 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -34,6 +34,33 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +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) @@ -106,6 +133,27 @@ struct media_engine CRITICAL_SECTION cs; }; +struct range +{ + double start; + double end; +}; + +struct time_range +{ + IMFMediaTimeRange IMFMediaTimeRange_iface; + LONG refcount; + + struct range *ranges; + size_t count; + size_t capacity; +}; + +static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface) +{ + return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface); +} + struct media_error { IMFMediaError IMFMediaError_iface; @@ -226,6 +274,164 @@ static HRESULT create_media_error(IMFMediaError **ret) return S_OK; } +static HRESULT WINAPI time_range_QueryInterface(IMFMediaTimeRange *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFMediaTimeRange) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFMediaTimeRange_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + ULONG refcount = InterlockedIncrement(&range->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + ULONG refcount = InterlockedDecrement(&range->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(range->ranges); + heap_free(range); + } + + return refcount; +} + +static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + + TRACE("%p.\n", iface); + + return range->count; +} + +static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, double *start) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + + TRACE("%p, %u, %p.\n", iface, idx, start); + + if (idx >= range->count) + return E_INVALIDARG; + + *start = range->ranges[idx].start; + + return S_OK; +} + +static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, double *end) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + + TRACE("%p, %u, %p.\n", iface, idx, end); + + if (idx >= range->count) + return E_INVALIDARG; + + *end = range->ranges[idx].end; + + return S_OK; +} + +static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + size_t i; + + TRACE("%p, %.8e.\n", iface, time); + + for (i = 0; i < range->count; ++i) + { + if (time >= range->ranges[i].start && time <= range->ranges[i].end) + return TRUE; + } + + return FALSE; +} + +static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + + TRACE("%p, %.8e, %.8e.\n", iface, start, end); + + if (range->count) + { + FIXME("Range merging is not implemented.\n"); + return E_NOTIMPL; + } + + if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges))) + return E_OUTOFMEMORY; + + range->ranges[range->count].start = start; + range->ranges[range->count].end = end; + range->count++; + + return S_OK; +} + +static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface) +{ + struct time_range *range = impl_from_IMFMediaTimeRange(iface); + + TRACE("%p.\n", iface); + + range->count = 0; + + return S_OK; +} + +static const IMFMediaTimeRangeVtbl time_range_vtbl = +{ + time_range_QueryInterface, + time_range_AddRef, + time_range_Release, + time_range_GetLength, + time_range_GetStart, + time_range_GetEnd, + time_range_ContainsTime, + time_range_AddRange, + time_range_Clear, +}; + +static HRESULT create_time_range(IMFMediaTimeRange **range) +{ + struct time_range *object; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl; + object->refcount = 1; + + *range = &object->IMFMediaTimeRange_iface; + + return S_OK; +} + static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value) { if (value) @@ -1718,11 +1924,11 @@ static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFac } static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface, - IMFMediaTimeRange **range) + IMFMediaTimeRange **range) { - FIXME("(%p, %p): stub.\n", iface, range); + TRACE("%p, %p.\n", iface, range); - return E_NOTIMPL; + return create_time_range(range); } static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index f9f8fed4a74..1cc88420568 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -590,6 +590,103 @@ static void test_error(void) IMFMediaError_Release(eo); } +static void test_time_range(void) +{ + IMFMediaTimeRange *range; + double start, end; + DWORD count; + HRESULT hr; + BOOL ret; + + hr = IMFMediaEngineClassFactory_CreateTimeRange(factory, &range); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + /* Empty ranges. */ + hr = IMFMediaTimeRange_Clear(range); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + ret = IMFMediaTimeRange_ContainsTime(range, 10.0); + ok(!ret, "Unexpected return value %d.\n", ret); + + count = IMFMediaTimeRange_GetLength(range); + ok(!count, "Unexpected range count.\n"); + + hr = IMFMediaTimeRange_GetStart(range, 0, &start); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaTimeRange_GetEnd(range, 0, &end); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + /* Add a range. */ + hr = IMFMediaTimeRange_AddRange(range, 10.0, 1.0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + count = IMFMediaTimeRange_GetLength(range); + ok(count == 1, "Unexpected range count.\n"); + + hr = IMFMediaTimeRange_GetStart(range, 0, &start); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(start == 10.0, "Unexpected start %.e.\n", start); + + hr = IMFMediaTimeRange_GetEnd(range, 0, &end); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(end == 1.0, "Unexpected end %.e.\n", end); + + hr = IMFMediaTimeRange_AddRange(range, 2.0, 3.0); +todo_wine + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + count = IMFMediaTimeRange_GetLength(range); + ok(count == 1, "Unexpected range count.\n"); + + hr = IMFMediaTimeRange_GetStart(range, 0, &start); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine + ok(start == 2.0, "Unexpected start %.8e.\n", start); + + hr = IMFMediaTimeRange_GetEnd(range, 0, &end); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine + ok(end == 3.0, "Unexpected end %.8e.\n", end); + + hr = IMFMediaTimeRange_AddRange(range, 10.0, 9.0); +todo_wine + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + count = IMFMediaTimeRange_GetLength(range); +todo_wine + ok(count == 2, "Unexpected range count.\n"); + + hr = IMFMediaTimeRange_GetStart(range, 0, &start); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine + ok(start == 2.0, "Unexpected start %.8e.\n", start); + + hr = IMFMediaTimeRange_GetEnd(range, 0, &end); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine + ok(end == 3.0, "Unexpected end %.8e.\n", end); + + start = 0.0; + hr = IMFMediaTimeRange_GetStart(range, 1, &start); +todo_wine { + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(start == 10.0, "Unexpected start %.8e.\n", start); +} + hr = IMFMediaTimeRange_GetEnd(range, 1, &end); +todo_wine { + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(end == 9.0, "Unexpected end %.8e.\n", end); +} + hr = IMFMediaTimeRange_Clear(range); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + count = IMFMediaTimeRange_GetLength(range); + ok(!count, "Unexpected range count.\n"); + + IMFMediaTimeRange_Release(range); +} + START_TEST(mfmediaengine) { HRESULT hr; @@ -617,6 +714,7 @@ START_TEST(mfmediaengine) test_playback_rate(); test_mute(); test_error(); + test_time_range(); IMFMediaEngineClassFactory_Release(factory);