Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/buffer.c | 308 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/tests/mfplat.c | 11 +- 3 files changed, 319 insertions(+), 1 deletion(-)
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 5e969e14ec9..3d1d2abdf88 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -21,6 +21,10 @@ #include "mfplat_private.h" #include "rtworkq.h"
+#include "initguid.h" +#include "d3d9.h" +#include "evr.h" + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -50,6 +54,11 @@ struct memory_buffer
unsigned int locks; } _2d; + struct + { + IDirect3DSurface9 *surface; + D3DLOCKED_RECT rect; + } d3d9_surface;
CRITICAL_SECTION cs; }; @@ -142,6 +151,8 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
if (!refcount) { + if (buffer->d3d9_surface.surface) + IDirect3DSurface9_Release(buffer->d3d9_surface.surface); DeleteCriticalSection(&buffer->cs); heap_free(buffer->_2d.linear_buffer); heap_free(buffer->data); @@ -333,6 +344,97 @@ static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl = memory_buffer_GetMaxLength, };
+static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length); + + if (!data) + return E_POINTER; + + EnterCriticalSection(&buffer->cs); + + if (!buffer->_2d.linear_buffer && buffer->_2d.locks) + hr = MF_E_INVALIDREQUEST; + else if (!buffer->_2d.linear_buffer) + { + D3DLOCKED_RECT rect; + + if (!(buffer->_2d.linear_buffer = heap_alloc(ALIGN_SIZE(buffer->_2d.plane_size, MF_64_BYTE_ALIGNMENT)))) + hr = E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + { + hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0); + if (SUCCEEDED(hr)) + { + MFCopyImage(buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch, + buffer->_2d.width, buffer->_2d.height); + IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); + } + } + } + + if (SUCCEEDED(hr)) + { + ++buffer->_2d.locks; + *data = buffer->_2d.linear_buffer; + if (max_length) + *max_length = buffer->_2d.plane_size; + if (current_length) + *current_length = buffer->_2d.plane_size; + } + + LeaveCriticalSection(&buffer->cs); + + return hr; +} + +static HRESULT WINAPI d3d9_surface_buffer_Unlock(IMFMediaBuffer *iface) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + HRESULT hr = S_OK; + + TRACE("%p.\n", iface); + + EnterCriticalSection(&buffer->cs); + + if (!buffer->_2d.linear_buffer) + hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); + else if (!--buffer->_2d.locks) + { + D3DLOCKED_RECT rect; + + if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0))) + { + MFCopyImage(rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width, + buffer->_2d.width, buffer->_2d.height); + IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); + } + + heap_free(buffer->_2d.linear_buffer); + buffer->_2d.linear_buffer = NULL; + } + + LeaveCriticalSection(&buffer->cs); + + return hr; +} + +static const IMFMediaBufferVtbl d3d9_surface_1d_buffer_vtbl = +{ + memory_1d_2d_buffer_QueryInterface, + memory_buffer_AddRef, + memory_buffer_Release, + d3d9_surface_buffer_Lock, + d3d9_surface_buffer_Unlock, + memory_buffer_GetCurrentLength, + memory_buffer_SetCurrentLength, + memory_buffer_GetMaxLength, +}; + static HRESULT WINAPI memory_2d_buffer_QueryInterface(IMF2DBuffer2 *iface, REFIID riid, void **obj) { struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); @@ -521,6 +623,144 @@ static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl = memory_2d_buffer_Copy2DTo, };
+static HRESULT WINAPI d3d9_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) +{ + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p, %p.\n", iface, scanline0, pitch); + + if (!scanline0 || !pitch) + return E_POINTER; + + EnterCriticalSection(&buffer->cs); + + if (buffer->_2d.linear_buffer) + hr = MF_E_UNEXPECTED; + else if (!buffer->_2d.locks++) + { + hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0); + } + + if (SUCCEEDED(hr)) + { + *scanline0 = buffer->d3d9_surface.rect.pBits; + *pitch = buffer->d3d9_surface.rect.Pitch; + } + + LeaveCriticalSection(&buffer->cs); + + return hr; +} + +static HRESULT WINAPI d3d9_surface_buffer_Unlock2D(IMF2DBuffer2 *iface) +{ + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + HRESULT hr = S_OK; + + TRACE("%p.\n", iface); + + EnterCriticalSection(&buffer->cs); + + if (buffer->_2d.locks) + { + if (!--buffer->_2d.locks) + { + IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); + memset(&buffer->d3d9_surface.rect, 0, sizeof(buffer->d3d9_surface.rect)); + } + } + else + hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); + + LeaveCriticalSection(&buffer->cs); + + return hr; +} + +static HRESULT WINAPI d3d9_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) +{ + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p, %p.\n", iface, scanline0, pitch); + + if (!scanline0 || !pitch) + return E_POINTER; + + EnterCriticalSection(&buffer->cs); + + if (!buffer->_2d.locks) + hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); + else + { + *scanline0 = buffer->d3d9_surface.rect.pBits; + *pitch = buffer->d3d9_surface.rect.Pitch; + } + + LeaveCriticalSection(&buffer->cs); + + return hr; +} + +static HRESULT WINAPI d3d9_surface_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length) +{ + FIXME("%p, %p.\n", iface, length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI d3d9_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0, + LONG *pitch, BYTE **buffer_start, DWORD *buffer_length) +{ + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + HRESULT hr = S_OK; + + TRACE("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length); + + if (!scanline0 || !pitch || !buffer_start || !buffer_length) + return E_POINTER; + + EnterCriticalSection(&buffer->cs); + + if (buffer->_2d.linear_buffer) + hr = MF_E_UNEXPECTED; + else if (!buffer->_2d.locks++) + { + hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0); + } + + if (SUCCEEDED(hr)) + { + *scanline0 = buffer->d3d9_surface.rect.pBits; + *pitch = buffer->d3d9_surface.rect.Pitch; + if (buffer_start) + *buffer_start = *scanline0; + if (buffer_length) + *buffer_length = buffer->d3d9_surface.rect.Pitch * buffer->_2d.height; + } + + LeaveCriticalSection(&buffer->cs); + + return hr; +} + +static const IMF2DBuffer2Vtbl d3d9_surface_buffer_vtbl = +{ + memory_2d_buffer_QueryInterface, + memory_2d_buffer_AddRef, + memory_2d_buffer_Release, + d3d9_surface_buffer_Lock2D, + d3d9_surface_buffer_Unlock2D, + d3d9_surface_buffer_GetScanline0AndPitch, + memory_2d_buffer_IsContiguousFormat, + d3d9_surface_buffer_GetContiguousLength, + memory_2d_buffer_ContiguousCopyTo, + memory_2d_buffer_ContiguousCopyFrom, + d3d9_surface_buffer_Lock2DSize, + memory_2d_buffer_Copy2DTo, +}; + static HRESULT WINAPI memory_2d_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) { struct memory_buffer *buffer = impl_from_IMFGetService(iface); @@ -554,6 +794,28 @@ static const IMFGetServiceVtbl memory_2d_buffer_gs_vtbl = memory_2d_buffer_gs_GetService, };
+static HRESULT WINAPI d3d9_surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + struct memory_buffer *buffer = impl_from_IMFGetService(iface); + + TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + + if (IsEqualGUID(service, &MR_BUFFER_SERVICE)) + { + return IDirect3DSurface9_QueryInterface(buffer->d3d9_surface.surface, riid, obj); + } + + return E_NOTIMPL; +} + +static const IMFGetServiceVtbl d3d9_surface_buffer_gs_vtbl = +{ + memory_2d_buffer_gs_QueryInterface, + memory_2d_buffer_gs_AddRef, + memory_2d_buffer_gs_Release, + d3d9_surface_buffer_gs_GetService, +}; + static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment, const IMFMediaBufferVtbl *vtbl) { @@ -675,6 +937,36 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo return S_OK; }
+static HRESULT create_d3d9_surface_buffer(IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer) +{ + struct memory_buffer *object; + D3DSURFACE_DESC desc; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFMediaBuffer_iface.lpVtbl = &d3d9_surface_1d_buffer_vtbl; + object->IMF2DBuffer2_iface.lpVtbl = &d3d9_surface_buffer_vtbl; + object->IMFGetService_iface.lpVtbl = &d3d9_surface_buffer_gs_vtbl; + object->refcount = 1; + InitializeCriticalSection(&object->cs); + object->d3d9_surface.surface = (IDirect3DSurface9 *)surface; + IUnknown_AddRef(surface); + + IDirect3DSurface9_GetDesc(object->d3d9_surface.surface, &desc); + TRACE("format %#x, %u x %u.\n", desc.Format, desc.Width, desc.Height); + + MFGetPlaneSize(desc.Format, desc.Width, desc.Height, &object->_2d.plane_size); + object->_2d.width = desc.Width; + object->_2d.height = desc.Height; + object->max_length = object->_2d.plane_size; + + *buffer = &object->IMFMediaBuffer_iface; + + return S_OK; +} + /*********************************************************************** * MFCreateMemoryBuffer (mfplat.@) */ @@ -695,6 +987,9 @@ HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IM return create_1d_buffer(max_length, alignment, buffer); }
+/*********************************************************************** + * MFCreate2DMediaBuffer (mfplat.@) + */ HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer) { TRACE("%u, %u, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer); @@ -702,6 +997,19 @@ HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BO return create_2d_buffer(width, height, fourcc, bottom_up, buffer); }
+/*********************************************************************** + * MFCreateDXSurfaceBuffer (mfplat.@) + */ +HRESULT WINAPI MFCreateDXSurfaceBuffer(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer) +{ + TRACE("%s, %p, %d, %p.\n", debugstr_guid(riid), surface, bottom_up, buffer); + + if (!IsEqualIID(riid, &IID_IDirect3DSurface9)) + return E_INVALIDARG; + + return create_d3d9_surface_buffer(surface, bottom_up, buffer); +} + static unsigned int buffer_get_aligned_length(unsigned int length, unsigned int alignment) { length = (length + alignment) / alignment; diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 5f4735cd6f7..80064e1980e 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -46,6 +46,7 @@ @ stub MFCreateAudioMediaType @ stdcall MFCreateCollection(ptr) @ stdcall MFCreateDXGIDeviceManager(ptr ptr) +@ stdcall MFCreateDXSurfaceBuffer(ptr ptr long ptr) @ stdcall MFCreateEventQueue(ptr) @ stdcall MFCreateFile(long long long wstr ptr) @ stub MFCreateLegacyMediaBufferOnMFMediaBuffer diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 8c6cbf74661..711a712da0d 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -5649,7 +5649,7 @@ static void test_MFCreateDXSurfaceBuffer(void)
if (!pMFCreateDXSurfaceBuffer) { - skip("MFCreateDXSurfaceBuffer is not available.\n"); + win_skip("MFCreateDXSurfaceBuffer is not available.\n"); return; }
@@ -5671,6 +5671,9 @@ static void test_MFCreateDXSurfaceBuffer(void)
IDirect3DSwapChain9_Release(swapchain);
+ hr = pMFCreateDXSurfaceBuffer(&IID_IUnknown, (IUnknown *)backbuffer, FALSE, &buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + hr = pMFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)backbuffer, FALSE, &buffer); ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
@@ -5764,6 +5767,12 @@ static void test_MFCreateDXSurfaceBuffer(void) ok(data[0] == 0xab, "Unexpected leading byte.\n"); IMF2DBuffer2_Unlock2D(_2dbuffer2);
+ hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(data[0] == 0xab, "Unexpected leading byte.\n"); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); IMF2DBuffer2_Unlock2D(_2dbuffer2);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/sample.c | 31 ++++++++++++++++--------------- dlls/evr/tests/evr.c | 6 +----- 2 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index b65cc45a662..39520cb6020 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -306,27 +306,28 @@ static HRESULT sample_allocator_create_samples(struct sample_allocator *allocato for (i = 0; i < sample_count; ++i) { struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample)); + IMFMediaBuffer *buffer;
- if (service) + if (SUCCEEDED(hr = MFCreateVideoSampleFromSurface(NULL, &sample))) { - if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service, width, height, 0, format, - D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL))) + if (service) { - hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); - IDirect3DSurface9_Release(surface); + if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service, width, height, + 0, format, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL))) + { + hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer); + IDirect3DSurface9_Release(surface); + } + } + else + { + hr = MFCreate2DMediaBuffer(width, height, format, FALSE, &buffer); } - } - else - { - IMFMediaBuffer *buffer;
- if (SUCCEEDED(hr = MFCreateVideoSampleFromSurface(NULL, &sample))) + if (SUCCEEDED(hr)) { - if (SUCCEEDED(hr = MFCreate2DMediaBuffer(width, height, format, FALSE, &buffer))) - { - hr = IMFSample_AddBuffer(sample, buffer); - IMFMediaBuffer_Release(buffer); - } + hr = IMFSample_AddBuffer(sample, buffer); + IMFMediaBuffer_Release(buffer); } }
diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index e4f45396ae8..a711be7ad21 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -1468,17 +1468,13 @@ todo_wine IDirect3DSurface9_Release(surface);
hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&unk); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr); - if (SUCCEEDED(hr)) - IUnknown_Release(unk); + IUnknown_Release(unk);
hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaBuffer_Unlock(buffer); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMFSample_Release(sample);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/evr.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/evr/evr.spec b/dlls/evr/evr.spec index dcf062cf5aa..67eee3122cf 100644 --- a/dlls/evr/evr.spec +++ b/dlls/evr/evr.spec @@ -7,7 +7,7 @@ @ stub MFConvertFromFP16Array @ stub MFConvertToFP16Array @ stdcall -import MFCopyImage(ptr long ptr long long long) -@ stub MFCreateDXSurfaceBuffer +@ stdcall -import MFCreateDXSurfaceBuffer(ptr ptr long ptr) @ stub MFCreateVideoMediaType @ stub MFCreateVideoMediaTypeFromBitMapInfoHeader @ stdcall -import MFCreateVideoMediaTypeFromSubtype(ptr ptr)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/presenter.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 96eaa4426fc..54ad9fee994 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -157,9 +157,31 @@ static void video_presenter_get_native_video_size(struct video_presenter *presen
static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter) { + IMFMediaType *media_type; + unsigned int idx = 0; + HRESULT hr; + video_presenter_get_native_video_size(presenter);
- return S_OK; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &media_type))) + { + /* FIXME: check that d3d device supports this format */ + + /* FIXME: potentially adjust frame size */ + + if (SUCCEEDED(IMFTransform_SetOutputType(presenter->mixer, 0, media_type, MFT_SET_TYPE_TEST_ONLY))) + { + /* FIXME: should keep a copy internally too */ + + hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0); + IMFMediaType_Release(media_type); + break; + } + + IMFMediaType_Release(media_type); + } + + return hr; }
static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=81276
Your paranoid android.
=== debiant (32 bit report) ===
mfplat: mfplat.c:2799: Test failed: Unexpected counter value 0. Unhandled exception: page fault on read access to 0x00000010 in 32-bit code (0x66741e8a).
Report validation errors: mfplat:mfplat crashed (c0000005)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/Makefile.in | 1 + dlls/mf/copier.c | 593 ++++++++++++++++++++++++++++++++++++++++++++ dlls/mf/main.c | 565 ----------------------------------------- 3 files changed, 594 insertions(+), 565 deletions(-) create mode 100644 dlls/mf/copier.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index f1d0571d143..cd50a849b7c 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -6,6 +6,7 @@ DELAYIMPORTS = evr EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + copier.c \ evr.c \ main.c \ samplegrabber.c \ diff --git a/dlls/mf/copier.c b/dlls/mf/copier.c new file mode 100644 index 00000000000..ba8e316f7e9 --- /dev/null +++ b/dlls/mf/copier.c @@ -0,0 +1,593 @@ +/* + * Copyright 2020 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 "mfapi.h" +#include "mfidl.h" +#include "mf_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +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_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_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_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + if (transform->attributes) + 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_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_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_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_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_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_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_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_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_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_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, debugstr_time(lower), debugstr_time(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_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_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_from_IMFTransform(iface); + IMFMediaBuffer *buffer; + 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); + + if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(transform->sample, NULL))) + { + if (SUCCEEDED(IMFSample_GetBufferByIndex(buffers->pSample, 0, &buffer))) + { + if (FAILED(IMFSample_CopyToBuffer(transform->sample, buffer))) + hr = MF_E_UNEXPECTED; + IMFMediaBuffer_Release(buffer); + } + } + + 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; + HRESULT hr; + + 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; + InitializeCriticalSection(&object->cs); + + if (FAILED(hr = MFCreateAttributes(&object->attributes, 0))) + goto failed; + + IMFAttributes_SetUINT32(object->attributes, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, 1); + + *transform = &object->IMFTransform_iface; + + return S_OK; + +failed: + + IMFTransform_Release(&object->IMFTransform_iface); + + return hr; +} diff --git a/dlls/mf/main.c b/dlls/mf/main.c index c48fc81a1d2..2caf50c54e0 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -1462,568 +1462,3 @@ 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) - { - if (transform->attributes) - 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, debugstr_time(lower), debugstr_time(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); - IMFMediaBuffer *buffer; - 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); - - if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(transform->sample, NULL))) - { - if (SUCCEEDED(IMFSample_GetBufferByIndex(buffers->pSample, 0, &buffer))) - { - if (FAILED(IMFSample_CopyToBuffer(transform->sample, buffer))) - hr = MF_E_UNEXPECTED; - IMFMediaBuffer_Release(buffer); - } - } - - 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; - HRESULT hr; - - 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; - InitializeCriticalSection(&object->cs); - - if (FAILED(hr = MFCreateAttributes(&object->attributes, 0))) - goto failed; - - IMFAttributes_SetUINT32(object->attributes, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, 1); - - *transform = &object->IMFTransform_iface; - - return S_OK; - -failed: - - IMFTransform_Release(&object->IMFTransform_iface); - - return hr; -}
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=81277
Your paranoid android.
=== debiant (64 bit WoW report) ===
mfplat: Unhandled exception: page fault on execute access to 0x0a2e7823 in 32-bit code (0x0a2e7823).
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/evr.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index 4dca8515c94..618bbf8924f 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -335,19 +335,36 @@ static HRESULT WINAPI video_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface static HRESULT WINAPI video_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) { struct video_stream *stream = impl_from_IMFStreamSink(iface); + LONGLONG timestamp; + HRESULT hr = S_OK;
- FIXME("%p, %p.\n", iface, sample); + TRACE("%p, %p.\n", iface, sample);
EnterCriticalSection(&stream->cs); - if (stream->flags & EVR_STREAM_PREROLLING) + + if (!stream->parent) + hr = MF_E_STREAMSINK_REMOVED; + else if (!stream->parent->clock) + hr = MF_E_NO_CLOCK; + else if (FAILED(hr = IMFSample_GetSampleTime(sample, ×tamp))) + { + WARN("No sample timestamp, hr %#x.\n", hr); + } + else if (stream->parent->state == EVR_STATE_RUNNING) { - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkPrerolled, &GUID_NULL, S_OK, NULL); - stream->flags &= ~EVR_STREAM_PREROLLING; - stream->flags |= EVR_STREAM_PREROLLED; + IMFTransform_ProcessInput(stream->parent->mixer, stream->id, sample, 0); + + if (stream->flags & EVR_STREAM_PREROLLING) + { + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkPrerolled, &GUID_NULL, S_OK, NULL); + stream->flags &= ~EVR_STREAM_PREROLLING; + stream->flags |= EVR_STREAM_PREROLLED; + } } + LeaveCriticalSection(&stream->cs);
- return E_NOTIMPL; + return hr; }
static HRESULT WINAPI video_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=81278
Your paranoid android.
=== debiant (32 bit report) ===
mfplat: mfplat.c:2799: Test failed: Unexpected counter value 0. Unhandled exception: page fault on execute access to 0x0a2e7823 in 32-bit code (0x0a2e7823).
Report validation errors: mfplat:mfplat crashed (c0000005)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/evr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index 618bbf8924f..f5bbfffc4a5 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -352,7 +352,8 @@ static HRESULT WINAPI video_stream_sink_ProcessSample(IMFStreamSink *iface, IMFS } else if (stream->parent->state == EVR_STATE_RUNNING) { - IMFTransform_ProcessInput(stream->parent->mixer, stream->id, sample, 0); + if (SUCCEEDED(IMFTransform_ProcessInput(stream->parent->mixer, stream->id, sample, 0))) + IMFVideoPresenter_ProcessMessage(stream->parent->presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0);
if (stream->flags & EVR_STREAM_PREROLLING) {