From 50af05674ce8959411a96a442800dd706939afe8 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 9 Mar 2020 19:39:24 +0300 Subject: [PATCH] mf: Partially implement sample copier transform. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mf/main.c | 544 +++++++++++++++++++++++++++++++++++++++++++++ dlls/mf/mf.spec | 2 +- dlls/mf/tests/mf.c | 271 ++++++++++++++++++++++ include/mfidl.idl | 1 + 4 files changed, 817 insertions(+), 1 deletion(-) diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 1700b179e56..f38558f82e4 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -1461,3 +1461,547 @@ HRESULT WINAPI MFCreateSimpleTypeHandler(IMFMediaTypeHandler **handler) return S_OK; } + +enum sample_copier_flags +{ + SAMPLE_COPIER_INPUT_TYPE_SET = 0x1, + SAMPLE_COPIER_OUTPUT_TYPE_SET = 0x2 +}; + +struct sample_copier +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFAttributes *attributes; + IMFMediaType *buffer_type; + DWORD buffer_size; + IMFSample *sample; + DWORD flags; + CRITICAL_SECTION cs; +}; + +static struct sample_copier *impl_copier_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct sample_copier, IMFTransform_iface); +} + +static HRESULT WINAPI sample_copier_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFTransform) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFTransform_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI sample_copier_transform_AddRef(IMFTransform *iface) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&transform->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI sample_copier_transform_Release(IMFTransform *iface) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + IMFAttributes_Release(transform->attributes); + if (transform->buffer_type) + IMFMediaType_Release(transform->buffer_type); + DeleteCriticalSection(&transform->cs); + heap_free(transform); + } + + return refcount; +} + +static HRESULT WINAPI sample_copier_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); + + *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; + + return S_OK; +} + +static HRESULT WINAPI sample_copier_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("%p, %p, %p.\n", iface, inputs, outputs); + + *inputs = 1; + *outputs = 1; + + return S_OK; +} + +static HRESULT WINAPI sample_copier_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + TRACE("%p, %u, %p, %u, %p.\n", iface, input_size, inputs, output_size, outputs); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %u, %p.\n", iface, id, info); + + memset(info, 0, sizeof(*info)); + + EnterCriticalSection(&transform->cs); + info->cbSize = transform->buffer_size; + LeaveCriticalSection(&transform->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_copier_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, + MFT_OUTPUT_STREAM_INFO *info) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %u, %p.\n", iface, id, info); + + memset(info, 0, sizeof(*info)); + + EnterCriticalSection(&transform->cs); + info->cbSize = transform->buffer_size; + LeaveCriticalSection(&transform->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_copier_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %p.\n", iface, attributes); + + *attributes = transform->attributes; + IMFAttributes_AddRef(*attributes); + + return S_OK; +} + +static HRESULT WINAPI sample_copier_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, + IMFAttributes **attributes) +{ + TRACE("%p, %u, %p.\n", iface, id, attributes); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, + IMFAttributes **attributes) +{ + TRACE("%p, %u, %p.\n", iface, id, attributes); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + TRACE("%p, %u.\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + TRACE("%p, %u, %p.\n", iface, streams, ids); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + static const GUID *types[] = { &MFMediaType_Video, &MFMediaType_Audio }; + HRESULT hr; + + TRACE("%p, %u, %u, %p.\n", iface, id, index, type); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + if (index > ARRAY_SIZE(types) - 1) + return MF_E_NO_MORE_TYPES; + + if (SUCCEEDED(hr = MFCreateMediaType(type))) + hr = IMFMediaType_SetGUID(*type, &MF_MT_MAJOR_TYPE, types[index]); + + return hr; +} + +static HRESULT WINAPI sample_copier_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + IMFMediaType *cloned_type = NULL; + HRESULT hr = S_OK; + + TRACE("%p, %u, %u, %p.\n", iface, id, index, type); + + EnterCriticalSection(&transform->cs); + if (transform->buffer_type) + { + if (SUCCEEDED(hr = MFCreateMediaType(&cloned_type))) + hr = IMFMediaType_CopyAllItems(transform->buffer_type, (IMFAttributes *)cloned_type); + } + else if (id) + hr = MF_E_INVALIDSTREAMNUMBER; + else + hr = MF_E_NO_MORE_TYPES; + LeaveCriticalSection(&transform->cs); + + if (SUCCEEDED(hr)) + *type = cloned_type; + else if (cloned_type) + IMFMediaType_Release(cloned_type); + + return hr; +} + +static HRESULT sample_copier_get_buffer_size(IMFMediaType *type, DWORD *size) +{ + GUID major, subtype; + UINT64 frame_size; + HRESULT hr; + + *size = 0; + + if (FAILED(hr = IMFMediaType_GetMajorType(type, &major))) + return hr; + + if (IsEqualGUID(&major, &MFMediaType_Video)) + { + if (SUCCEEDED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + { + if (SUCCEEDED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + if (FAILED(hr = MFCalculateImageSize(&subtype, (UINT32)(frame_size >> 32), (UINT32)frame_size, size))) + WARN("Failed to get image size for video format %s.\n", debugstr_guid(&subtype)); + } + } + } + else if (IsEqualGUID(&major, &MFMediaType_Audio)) + { + FIXME("Audio formats are not handled.\n"); + hr = E_NOTIMPL; + } + + return hr; +} + +static HRESULT sample_copier_set_media_type(struct sample_copier *transform, BOOL input, DWORD id, IMFMediaType *type, + DWORD flags) +{ + DWORD buffer_size; + HRESULT hr = S_OK; + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + EnterCriticalSection(&transform->cs); + if (type) + { + hr = sample_copier_get_buffer_size(type, &buffer_size); + if (!(flags & MFT_SET_TYPE_TEST_ONLY) && SUCCEEDED(hr)) + { + if (!transform->buffer_type) + hr = MFCreateMediaType(&transform->buffer_type); + if (SUCCEEDED(hr)) + hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)transform->buffer_type); + if (SUCCEEDED(hr)) + transform->buffer_size = buffer_size; + + if (SUCCEEDED(hr)) + { + if (input) + { + transform->flags |= SAMPLE_COPIER_INPUT_TYPE_SET; + transform->flags &= ~SAMPLE_COPIER_OUTPUT_TYPE_SET; + } + else + transform->flags |= SAMPLE_COPIER_OUTPUT_TYPE_SET; + } + } + } + else if (transform->buffer_type) + { + IMFMediaType_Release(transform->buffer_type); + transform->buffer_type = NULL; + } + LeaveCriticalSection(&transform->cs); + + return hr; +} + +static HRESULT WINAPI sample_copier_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); + + return sample_copier_set_media_type(transform, TRUE, id, type, flags); +} + +static HRESULT WINAPI sample_copier_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); + + return sample_copier_set_media_type(transform, FALSE, id, type, flags); +} + +static HRESULT sample_copier_get_current_type(struct sample_copier *transform, DWORD id, DWORD flags, + IMFMediaType **ret) +{ + IMFMediaType *cloned_type = NULL; + HRESULT hr; + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + EnterCriticalSection(&transform->cs); + if (transform->flags & flags) + { + if (SUCCEEDED(hr = MFCreateMediaType(&cloned_type))) + hr = IMFMediaType_CopyAllItems(transform->buffer_type, (IMFAttributes *)cloned_type); + } + else + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + LeaveCriticalSection(&transform->cs); + + if (SUCCEEDED(hr)) + *ret = cloned_type; + else if (cloned_type) + IMFMediaType_Release(cloned_type); + + return hr; +} + +static HRESULT WINAPI sample_copier_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %u, %p.\n", iface, id, type); + + return sample_copier_get_current_type(transform, id, SAMPLE_COPIER_INPUT_TYPE_SET, type); +} + +static HRESULT WINAPI sample_copier_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %u, %p.\n", iface, id, type); + + return sample_copier_get_current_type(transform, id, SAMPLE_COPIER_OUTPUT_TYPE_SET, type); +} + +static HRESULT WINAPI sample_copier_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + HRESULT hr = S_OK; + + TRACE("%p, %u, %p.\n", iface, id, flags); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + EnterCriticalSection(&transform->cs); + if (!(transform->flags & SAMPLE_COPIER_INPUT_TYPE_SET)) + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + else + *flags = transform->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA; + LeaveCriticalSection(&transform->cs); + + return hr; +} + +static HRESULT WINAPI sample_copier_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, flags); + + EnterCriticalSection(&transform->cs); + if (!(transform->flags & SAMPLE_COPIER_OUTPUT_TYPE_SET)) + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + else + *flags = transform->sample ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0; + LeaveCriticalSection(&transform->cs); + + return hr; +} + +static HRESULT WINAPI sample_copier_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("%p, %u, %p.\n", iface, id, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_copier_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + + TRACE("%p, %#x, %p.\n", iface, message, (void *)param); + + EnterCriticalSection(&transform->cs); + + if (message == MFT_MESSAGE_COMMAND_FLUSH) + { + if (transform->sample) + { + IMFSample_Release(transform->sample); + transform->sample = NULL; + } + } + + LeaveCriticalSection(&transform->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_copier_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + HRESULT hr = S_OK; + + TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + EnterCriticalSection(&transform->cs); + if (!transform->buffer_type) + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + else if (transform->sample) + hr = MF_E_NOTACCEPTING; + else + { + transform->sample = sample; + IMFSample_AddRef(transform->sample); + } + LeaveCriticalSection(&transform->cs); + + return hr; +} + +static HRESULT WINAPI sample_copier_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *buffers, DWORD *status) +{ + struct sample_copier *transform = impl_copier_from_IMFTransform(iface); + DWORD sample_flags; + HRESULT hr = S_OK; + LONGLONG time; + + TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, buffers, status); + + EnterCriticalSection(&transform->cs); + if (!(transform->flags & SAMPLE_COPIER_OUTPUT_TYPE_SET)) + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + else if (!transform->sample) + hr = MF_E_TRANSFORM_NEED_MORE_INPUT; + else + { + IMFSample_CopyAllItems(transform->sample, (IMFAttributes *)buffers->pSample); + + if (SUCCEEDED(IMFSample_GetSampleDuration(transform->sample, &time))) + IMFSample_SetSampleDuration(buffers->pSample, time); + + if (SUCCEEDED(IMFSample_GetSampleTime(transform->sample, &time))) + IMFSample_SetSampleTime(buffers->pSample, time); + + if (SUCCEEDED(IMFSample_GetSampleFlags(transform->sample, &sample_flags))) + IMFSample_SetSampleFlags(buffers->pSample, sample_flags); + + FIXME("Copy buffers.\n"); + + IMFSample_Release(transform->sample); + transform->sample = NULL; + } + LeaveCriticalSection(&transform->cs); + + return hr; +} + +static const IMFTransformVtbl sample_copier_transform_vtbl = +{ + sample_copier_transform_QueryInterface, + sample_copier_transform_AddRef, + sample_copier_transform_Release, + sample_copier_transform_GetStreamLimits, + sample_copier_transform_GetStreamCount, + sample_copier_transform_GetStreamIDs, + sample_copier_transform_GetInputStreamInfo, + sample_copier_transform_GetOutputStreamInfo, + sample_copier_transform_GetAttributes, + sample_copier_transform_GetInputStreamAttributes, + sample_copier_transform_GetOutputStreamAttributes, + sample_copier_transform_DeleteInputStream, + sample_copier_transform_AddInputStreams, + sample_copier_transform_GetInputAvailableType, + sample_copier_transform_GetOutputAvailableType, + sample_copier_transform_SetInputType, + sample_copier_transform_SetOutputType, + sample_copier_transform_GetInputCurrentType, + sample_copier_transform_GetOutputCurrentType, + sample_copier_transform_GetInputStatus, + sample_copier_transform_GetOutputStatus, + sample_copier_transform_SetOutputBounds, + sample_copier_transform_ProcessEvent, + sample_copier_transform_ProcessMessage, + sample_copier_transform_ProcessInput, + sample_copier_transform_ProcessOutput, +}; + +HRESULT WINAPI MFCreateSampleCopierMFT(IMFTransform **transform) +{ + struct sample_copier *object; + + TRACE("%p.\n", transform); + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFTransform_iface.lpVtbl = &sample_copier_transform_vtbl; + object->refcount = 1; + MFCreateAttributes(&object->attributes, 0); + InitializeCriticalSection(&object->cs); + + *transform = &object->IMFTransform_iface; + + return S_OK; +} diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec index 29676005ad9..1c3fc9c953e 100644 --- a/dlls/mf/mf.spec +++ b/dlls/mf/mf.spec @@ -50,7 +50,7 @@ @ stub MFCreateProxyLocator @ stub MFCreateRemoteDesktopPlugin @ stub MFCreateSAMIByteStreamPlugin -@ stub MFCreateSampleCopierMFT +@ stdcall MFCreateSampleCopierMFT(ptr) @ stdcall MFCreateSampleGrabberSinkActivate(ptr ptr ptr) @ stub MFCreateSecureHttpSchemePlugin @ stub MFCreateSequencerSegmentOffset diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index cf98f3d03ff..2dc5ad8f50d 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2751,6 +2751,276 @@ static void test_MFGetSupportedSchemes(void) PropVariantClear(&value); } +static BOOL is_sample_copier_available_type(IMFMediaType *type) +{ + GUID major = { 0 }; + UINT32 count; + HRESULT hr; + + hr = IMFMediaType_GetMajorType(type, &major); + ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); + + hr = IMFMediaType_GetCount(type, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); + ok(count == 1, "Unexpected attribute count %u.\n", count); + + return IsEqualGUID(&major, &MFMediaType_Video) || IsEqualGUID(&major, &MFMediaType_Audio); +} + +static void test_sample_copier(void) +{ + DWORD in_min, in_max, out_min, out_max; + IMFMediaType *mediatype, *mediatype2; + MFT_OUTPUT_STREAM_INFO output_info; + IMFSample *sample, *client_sample; + MFT_INPUT_STREAM_INFO input_info; + DWORD input_count, output_count; + MFT_OUTPUT_DATA_BUFFER buffer; + IMFMediaBuffer *media_buffer; + IMFAttributes *attributes; + IMFTransform *copier; + DWORD flags, status; + HRESULT hr; + + hr = MFCreateSampleCopierMFT(&copier); + ok(hr == S_OK, "Failed to create sample copier, hr %#x.\n", hr); + + hr = IMFTransform_GetAttributes(copier, &attributes); + ok(hr == S_OK, "Failed to get transform attributes, hr %#x.\n", hr); + IMFAttributes_Release(attributes); + + hr = IMFTransform_GetInputStreamAttributes(copier, 0, &attributes); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetInputStreamAttributes(copier, 1, &attributes); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStreamAttributes(copier, 0, &attributes); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStreamAttributes(copier, 1, &attributes); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_SetOutputBounds(copier, 0, 0); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + /* No dynamic streams. */ + input_count = output_count = 0; + hr = IMFTransform_GetStreamCount(copier, &input_count, &output_count); + ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr); + ok(input_count == 1 && output_count == 1, "Unexpected streams count.\n"); + + hr = IMFTransform_GetStreamLimits(copier, &in_min, &in_max, &out_min, &out_max); + ok(hr == S_OK, "Failed to get stream limits, hr %#x.\n", hr); + ok(in_min == in_max && in_min == 1 && out_min == out_max && out_min == 1, "Unexpected stream limits.\n"); + + hr = IMFTransform_GetStreamIDs(copier, 1, &input_count, 1, &output_count); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_DeleteInputStream(copier, 0); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + /* Available types. */ + hr = IMFTransform_GetInputAvailableType(copier, 0, 0, &mediatype); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(is_sample_copier_available_type(mediatype), "Unexpected type.\n"); + IMFMediaType_Release(mediatype); + + hr = IMFTransform_GetInputAvailableType(copier, 0, 1, &mediatype); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(is_sample_copier_available_type(mediatype), "Unexpected type.\n"); + IMFMediaType_Release(mediatype); + + hr = IMFTransform_GetInputAvailableType(copier, 0, 2, &mediatype); + ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetInputAvailableType(copier, 1, 0, &mediatype); + ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputAvailableType(copier, 0, 0, &mediatype); + ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputAvailableType(copier, 1, 0, &mediatype); + ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetInputCurrentType(copier, 0, &mediatype); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetInputCurrentType(copier, 1, &mediatype); + ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputCurrentType(copier, 1, &mediatype); + ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr); + + hr = MFCreateSample(&sample); + ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr); + + hr = IMFTransform_ProcessInput(copier, 0, sample, 0); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFVideoFormat_RGB8); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = IMFMediaType_SetUINT64(mediatype, &MF_MT_FRAME_SIZE, ((UINT64)16) << 32 | 16); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(copier, 0, &output_info); + ok(hr == S_OK, "Failed to get stream info, hr %#x.\n", hr); + ok(!output_info.dwFlags, "Unexpected flags %#x.\n", output_info.dwFlags); + ok(!output_info.cbSize, "Unexpected size %u.\n", output_info.cbSize); + ok(!output_info.cbAlignment, "Unexpected alignment %u.\n", output_info.cbAlignment); + + hr = IMFTransform_GetInputStreamInfo(copier, 0, &input_info); + ok(hr == S_OK, "Failed to get stream info, hr %#x.\n", hr); + + ok(!input_info.hnsMaxLatency, "Unexpected latency %s.\n", wine_dbgstr_longlong(input_info.hnsMaxLatency)); + ok(!input_info.dwFlags, "Unexpected flags %#x.\n", input_info.dwFlags); + ok(!input_info.cbSize, "Unexpected size %u.\n", input_info.cbSize); + ok(!input_info.cbMaxLookahead, "Unexpected lookahead size %u.\n", input_info.cbMaxLookahead); + ok(!input_info.cbAlignment, "Unexpected alignment %u.\n", input_info.cbAlignment); + + hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0); + ok(hr == S_OK, "Failed to set input type, hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(copier, 0, &output_info); + ok(hr == S_OK, "Failed to get stream info, hr %#x.\n", hr); + ok(!output_info.dwFlags, "Unexpected flags %#x.\n", output_info.dwFlags); + ok(output_info.cbSize == 16 * 16, "Unexpected size %u.\n", output_info.cbSize); + ok(!output_info.cbAlignment, "Unexpected alignment %u.\n", output_info.cbAlignment); + + hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype2); + ok(hr == S_OK, "Failed to get current type, hr %#x.\n", hr); + IMFMediaType_Release(mediatype2); + + hr = IMFTransform_GetInputCurrentType(copier, 0, &mediatype2); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetInputStatus(copier, 0, &flags); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + /* Setting input type resets output type. */ + hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IMFMediaType_Release(mediatype2); + + hr = IMFTransform_SetInputType(copier, 0, mediatype, 0); + ok(hr == S_OK, "Failed to set input type, hr %#x.\n", hr); + + hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype2); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetInputAvailableType(copier, 0, 1, &mediatype2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(is_sample_copier_available_type(mediatype2), "Unexpected type.\n"); + IMFMediaType_Release(mediatype2); + + hr = IMFTransform_GetInputStreamInfo(copier, 0, &input_info); + ok(hr == S_OK, "Failed to get stream info, hr %#x.\n", hr); + ok(!input_info.hnsMaxLatency, "Unexpected latency %s.\n", wine_dbgstr_longlong(input_info.hnsMaxLatency)); + ok(!input_info.dwFlags, "Unexpected flags %#x.\n", input_info.dwFlags); + ok(input_info.cbSize == 16 * 16, "Unexpected size %u.\n", input_info.cbSize); + ok(!input_info.cbMaxLookahead, "Unexpected lookahead size %u.\n", input_info.cbMaxLookahead); + ok(!input_info.cbAlignment, "Unexpected alignment %u.\n", input_info.cbAlignment); + + hr = IMFTransform_GetOutputAvailableType(copier, 0, 0, &mediatype2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMFMediaType_IsEqual(mediatype2, mediatype, &flags); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IMFMediaType_Release(mediatype2); + + hr = IMFTransform_GetInputStatus(copier, 0, &flags); + ok(hr == S_OK, "Failed to get input status, hr %#x.\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Unexpected flags %#x.\n", flags); + + hr = IMFTransform_GetInputCurrentType(copier, 0, &mediatype2); + ok(hr == S_OK, "Failed to get current type, hr %#x.\n", hr); + IMFMediaType_Release(mediatype2); + + hr = IMFTransform_GetOutputStatus(copier, &flags); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0); + ok(hr == S_OK, "Failed to set output type, hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStatus(copier, &flags); + ok(hr == S_OK, "Failed to get output status, hr %#x.\n", hr); + ok(!flags, "Unexpected flags %#x.\n", flags); + + /* Pushing samples. */ + hr = MFCreateAlignedMemoryBuffer(output_info.cbSize, output_info.cbAlignment, &media_buffer); + ok(hr == S_OK, "Failed to create media buffer, hr %#x.\n", hr); + + hr = IMFSample_AddBuffer(sample, media_buffer); + ok(hr == S_OK, "Failed to add a buffer, hr %#x.\n", hr); + IMFMediaBuffer_Release(media_buffer); + + EXPECT_REF(sample, 1); + hr = IMFTransform_ProcessInput(copier, 0, sample, 0); + ok(hr == S_OK, "Failed to process input, hr %#x.\n", hr); + EXPECT_REF(sample, 2); + + hr = IMFTransform_GetInputStatus(copier, 0, &flags); + ok(hr == S_OK, "Failed to get input status, hr %#x.\n", hr); + ok(!flags, "Unexpected flags %#x.\n", flags); + + hr = IMFTransform_GetOutputStatus(copier, &flags); + ok(hr == S_OK, "Failed to get output status, hr %#x.\n", hr); + ok(flags == MFT_OUTPUT_STATUS_SAMPLE_READY, "Unexpected flags %#x.\n", flags); + + hr = IMFTransform_ProcessInput(copier, 0, sample, 0); + ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(copier, 0, &output_info); + ok(hr == S_OK, "Failed to get output info, hr %#x.\n", hr); + + hr = MFCreateAlignedMemoryBuffer(output_info.cbSize, output_info.cbAlignment, &media_buffer); + ok(hr == S_OK, "Failed to create media buffer, hr %#x.\n", hr); + + hr = MFCreateSample(&client_sample); + ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr); + + hr = IMFSample_AddBuffer(client_sample, media_buffer); + ok(hr == S_OK, "Failed to add a buffer, hr %#x.\n", hr); + IMFMediaBuffer_Release(media_buffer); + + status = 0; + memset(&buffer, 0, sizeof(buffer)); + buffer.pSample = client_sample; + hr = IMFTransform_ProcessOutput(copier, 0, 1, &buffer, &status); + ok(hr == S_OK, "Failed to get output, hr %#x.\n", hr); + EXPECT_REF(sample, 1); + + hr = IMFTransform_ProcessOutput(copier, 0, 1, &buffer, &status); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Failed to get output, hr %#x.\n", hr); + + /* Flushing. */ + hr = IMFTransform_ProcessInput(copier, 0, sample, 0); + ok(hr == S_OK, "Failed to process input, hr %#x.\n", hr); + EXPECT_REF(sample, 2); + + hr = IMFTransform_ProcessMessage(copier, MFT_MESSAGE_COMMAND_FLUSH, 0); + ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr); + EXPECT_REF(sample, 1); + + IMFSample_Release(sample); + IMFSample_Release(client_sample); + + IMFMediaType_Release(mediatype); + IMFTransform_Release(copier); +} + START_TEST(mf) { test_topology(); @@ -2768,4 +3038,5 @@ START_TEST(mf) test_MFCreateSimpleTypeHandler(); test_MFGetSupportedMimeTypes(); test_MFGetSupportedSchemes(); + test_sample_copier(); } diff --git a/include/mfidl.idl b/include/mfidl.idl index fc9173864a7..cf04ec17cee 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -591,6 +591,7 @@ cpp_quote("HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock cpp_quote("HRESULT WINAPI MFCreatePresentationDescriptor(DWORD count, IMFStreamDescriptor **descriptors,") cpp_quote(" IMFPresentationDescriptor **presentation_desc);") cpp_quote("HRESULT WINAPI MFCreateSimpleTypeHandler(IMFMediaTypeHandler **handler);") +cpp_quote("HRESULT WINAPI MFCreateSampleCopierMFT(IMFTransform **transform);") cpp_quote("HRESULT WINAPI MFCreateSampleGrabberSinkActivate(IMFMediaType *media_type,") cpp_quote(" IMFSampleGrabberSinkCallback *callback, IMFActivate **activate);") cpp_quote("HRESULT WINAPI MFCreateSequencerSource(IUnknown *reserved, IMFSequencerSource **seq_source);" )