From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfmediaengine/Makefile.in | 2 +- dlls/mfmediaengine/main.c | 120 +++++++++++++++++++++++ dlls/mfmediaengine/tests/mfmediaengine.c | 2 - 3 files changed, 121 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/Makefile.in b/dlls/mfmediaengine/Makefile.in index 5b593814ef6..c5dc42c9e35 100644 --- a/dlls/mfmediaengine/Makefile.in +++ b/dlls/mfmediaengine/Makefile.in @@ -1,5 +1,5 @@ MODULE = mfmediaengine.dll -IMPORTS = oleaut32 ole32 mfplat mf mfuuid dxguid uuid +IMPORTS = oleaut32 ole32 mfplat mf mfuuid dxguid uuid windowscodecs
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index aab5fd64aa2..f096c2054f2 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -29,6 +29,7 @@ #include "mferror.h" #include "dxgi.h" #include "d3d11.h" +#include "wincodec.h" #include "mmdeviceapi.h" #include "audiosessiontypes.h"
@@ -2707,12 +2708,126 @@ done: return hr; }
+static HRESULT media_engine_transfer_wic(struct media_engine *engine, IWICBitmap *bitmap, + const MFVideoNormalizedRect *src_mf_rect, const RECT *dst_rect, const MFARGB *color) +{ + UINT frame_width, frame_height, dst_width, dst_height, dst_size, src_stride, dst_stride, format_size, y; + RECT src_rect = {0}, dst_rect_default = {0}; + DWORD max_length, current_length; + IMFMediaBuffer *media_buffer; + WICPixelFormatGUID format; + IWICBitmapLock *lock; + BYTE *data, *buffer; + IMFSample *sample; + WICRect wic_rect; + HRESULT hr; + + frame_width = engine->video_frame.size.cx; + frame_height = engine->video_frame.size.cy; + + if (src_mf_rect) + { + src_rect.left = src_mf_rect->left * frame_width + 0.5f; + src_rect.top = src_mf_rect->top * frame_height + 0.5f; + src_rect.right = src_mf_rect->right * frame_width + 0.5f; + src_rect.bottom = src_mf_rect->bottom * frame_height + 0.5f; + } + else + { + src_rect.right = frame_width; + src_rect.bottom = frame_height; + } + + if (FAILED(hr = IWICBitmap_GetPixelFormat(bitmap, &format)) + || FAILED(IWICBitmap_GetSize(bitmap, &dst_width, &dst_height))) + return hr; + + if (!dst_rect) + { + dst_rect = &dst_rect_default; + dst_rect_default.right = dst_width; + dst_rect_default.bottom = dst_height; + } + + if (!video_frame_sink_get_sample(engine->presentation.frame_sink, &sample)) + return MF_E_UNEXPECTED; + hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer); + IMFSample_Release(sample); + if (FAILED(hr)) + return hr; + + if (dst_rect->left + src_rect.right - src_rect.left > dst_width + || dst_rect->top + src_rect.bottom - src_rect.top > dst_height) + { + hr = MF_E_UNEXPECTED; + goto done; + } + if (dst_rect->right - dst_rect->left != src_rect.right - src_rect.left + || dst_rect->bottom - dst_rect->top != src_rect.bottom - src_rect.top) + { + FIXME("Scaling/letterboxing is not implemented.\n"); + goto done; + } + + if (!IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGR) && !IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGRA)) + { + FIXME("Unsupported format %s.\n", wine_dbgstr_guid(&format)); + goto done; + } + if (engine->video_frame.output_format != DXGI_FORMAT_B8G8R8A8_UNORM + && engine->video_frame.output_format != DXGI_FORMAT_B8G8R8X8_UNORM) + { + FIXME("Unsupported format %#x.\n", engine->video_frame.output_format); + goto done; + } + format_size = 4; + + wic_rect.X = dst_rect->left; + wic_rect.Y = dst_rect->top; + wic_rect.Width = dst_rect->right - dst_rect->left; + wic_rect.Height = dst_rect->bottom - dst_rect->top; + if (FAILED(hr = IWICBitmap_Lock(bitmap, &wic_rect, WICBitmapLockWrite, &lock))) + goto done; + + if (FAILED(hr = IWICBitmapLock_GetStride(lock, &dst_stride)) + || FAILED(hr = IWICBitmapLock_GetDataPointer(lock, &dst_size, &data))) + goto done_unlock_dst; + + if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, &max_length, ¤t_length))) + goto done_unlock_dst; + + if (current_length < frame_width * frame_height * format_size) + { + WARN("Unexpected source length %lu.\n", current_length); + hr = MF_E_UNEXPECTED; + goto done_unlock_dst; + } + + src_stride = frame_width * format_size; + buffer += src_rect.top * src_stride + src_rect.left * format_size; + for (y = 0; y < wic_rect.Height; ++y) + { + memcpy(data, buffer, dst_stride); + buffer += src_stride; + data += dst_stride; + } + + IMFMediaBuffer_Unlock(media_buffer); + +done_unlock_dst: + IWICBitmapLock_Release(lock); +done: + IMFMediaBuffer_Release(media_buffer); + return hr; +} + static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface, const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) { struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); ID3D11Texture2D *texture; HRESULT hr = E_NOINTERFACE; + IWICBitmap *bitmap;
TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)", src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)", @@ -2726,6 +2841,11 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, I hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture); } + else if (!engine->device_manager && SUCCEEDED(IUnknown_QueryInterface(surface, &IID_IWICBitmap, (void **)&bitmap))) + { + hr = media_engine_transfer_wic(engine, bitmap, src_rect, dst_rect, color); + IWICBitmap_Release(bitmap); + } else { FIXME("Unsupported destination type.\n"); diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 715d44a8ef7..79b0edf8da3 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1467,7 +1467,6 @@ static void test_TransferVideoFrame_wic(void) SetRect(&dst_rect, 0, 0, wicrc.Width, wicrc.Height); IMFMediaEngineEx_OnVideoStreamTick(notify->media_engine, &pts); hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)bitmap, NULL, &dst_rect, NULL); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IWICBitmap_Lock(bitmap, &wicrc, WICBitmapLockRead, &lock); @@ -1480,7 +1479,6 @@ static void test_TransferVideoFrame_wic(void) ok(lock_buffer_size == 16384, "got lock_buffer_size %u\n", lock_buffer_size); ok(lock_buffer_stride == wicrc.Width * 4, "got lock_buffer_stride %u\n", lock_buffer_stride); res = check_rgb32_data(L"rgb32frame.bmp", lock_buffer, lock_buffer_stride * wicrc.Height, &dst_rect); - todo_wine ok(res == 0, "Unexpected %lu%% diff\n", res);
IWICBitmapLock_Release(lock);