Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/presenter.c | 36 ++++++++++-- dlls/evr/tests/evr.c | 132 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 5 deletions(-)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index f0733f6f060..5701eb17bd3 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -306,17 +306,43 @@ static HRESULT video_presenter_set_media_type(struct video_presenter *presenter,
static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter) { - IMFMediaType *media_type; + IMFMediaType *media_type, *candidate_type; unsigned int idx = 0; + UINT64 frame_size; + MFVideoArea aperture; + RECT rect; HRESULT hr;
+ if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + video_presenter_get_native_video_size(presenter);
- while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &media_type))) + rect = presenter->dst_rect; + if (rect.left == 0 && rect.right == 0 && rect.bottom == 0 && rect.top == 0) + { + rect.right = presenter->native_size.cx; + rect.bottom = presenter->native_size.cy; + } + + aperture.Area.cx = rect.right - rect.left; + aperture.Area.cy = rect.bottom - rect.top; + aperture.OffsetX.value = 0; + aperture.OffsetX.fract = 0; + aperture.OffsetY.value = 0; + aperture.OffsetY.fract = 0; + frame_size = (UINT64)aperture.Area.cx << 32 | aperture.Area.cy; + + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(presenter->mixer, 0, idx++, &candidate_type))) { /* FIXME: check that d3d device supports this format */
- /* FIXME: potentially adjust frame size */ + if (FAILED(hr = IMFMediaType_CopyAllItems(candidate_type, (IMFAttributes *)media_type))) + WARN("Failed to clone a media type, hr %#x.\n", hr); + IMFMediaType_Release(candidate_type); + + IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, frame_size); + IMFMediaType_SetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&aperture, sizeof(aperture));
hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
@@ -326,12 +352,12 @@ static HRESULT video_presenter_invalidate_media_type(struct video_presenter *pre if (SUCCEEDED(hr)) hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0);
- IMFMediaType_Release(media_type); - if (SUCCEEDED(hr)) break; }
+ IMFMediaType_Release(media_type); + return hr; }
diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 2740f2263f0..31434bde43a 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -2072,6 +2072,137 @@ todo_wine { IMFVideoPresenter_Release(presenter); }
+static void get_output_aperture(IMFTransform *mixer, SIZE *frame_size, MFVideoArea *aperture) +{ + IMFMediaType *media_type; + UINT64 size; + HRESULT hr; + + memset(frame_size, 0xcc, sizeof(*frame_size)); + memset(aperture, 0xcc, sizeof(*aperture)); + + hr = IMFTransform_GetOutputCurrentType(mixer, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + frame_size->cx = size >> 32; + frame_size->cy = size; + + hr = IMFMediaType_GetBlob(media_type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)aperture, sizeof(*aperture), NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFMediaType_Release(media_type); +} + +static void test_presenter_media_type(void) +{ + IMFTopologyServiceLookupClient *lookup_client; + IMFVideoPresenter *presenter; + struct test_host host; + IMFMediaType *input_type; + IDirect3DDeviceManager9 *manager; + HRESULT hr; + IMFTransform *mixer; + IDirect3D9 *d3d; + IDirect3DDevice9 *device; + unsigned int token; + SIZE frame_size; + HWND window; + MFVideoArea aperture; + IMFVideoDisplayControl *display_control; + RECT dst; + + window = create_window(); + d3d = Direct3DCreate9(D3D_SDK_VERSION); + ok(!!d3d, "Failed to create a D3D object.\n"); + if (!(device = create_device(d3d, window))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + goto done; + } + + hr = DXVA2CreateDirect3DDeviceManager9(&token, &manager); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = MFCreateVideoPresenter(NULL, &IID_IDirect3DDevice9, &IID_IMFVideoPresenter, (void **)&presenter); + ok(hr == S_OK, "Failed to create default presenter, hr %#x.\n", hr); + + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFVideoDisplayControl, (void **)&display_control); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = MFCreateVideoMixer(NULL, &IID_IDirect3DDevice9, &IID_IMFTransform, (void **)&mixer); + ok(hr == S_OK, "Failed to create a mixer, hr %#x.\n", hr); + + input_type = create_video_type(&MFVideoFormat_RGB32); + + hr = IMFMediaType_SetUINT64(input_type, &MF_MT_FRAME_SIZE, (UINT64)100 << 32 | 50); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(input_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_ProcessMessage(mixer, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_SetInputType(mixer, 0, input_type, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + init_test_host(&host, mixer, presenter); + + hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, &host.IMFTopologyServiceLookup_iface); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoDisplayControl_SetVideoWindow(display_control, window); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_INVALIDATEMEDIATYPE, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + get_output_aperture(mixer, &frame_size, &aperture); + ok(frame_size.cx == 100 && frame_size.cy == 50, "Unexpected frame size %u x %u.\n", frame_size.cx, frame_size.cy); + ok(aperture.Area.cx == 100 && aperture.Area.cy == 50, "Unexpected size %u x %u.\n", aperture.Area.cx, aperture.Area.cy); + ok(!aperture.OffsetX.value && !aperture.OffsetX.fract && !aperture.OffsetY.value && !aperture.OffsetY.fract, + "Unexpected offset %u x %u.\n", aperture.OffsetX.value, aperture.OffsetY.value); + + SetRect(&dst, 1, 2, 200, 300); + hr = IMFVideoDisplayControl_SetVideoPosition(display_control, NULL, &dst); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + get_output_aperture(mixer, &frame_size, &aperture); +todo_wine { + ok(frame_size.cx == 199 && frame_size.cy == 298, "Unexpected frame size %u x %u.\n", frame_size.cx, frame_size.cy); + ok(aperture.Area.cx == 199 && aperture.Area.cy == 298, "Unexpected size %u x %u.\n", aperture.Area.cx, aperture.Area.cy); +} + ok(!aperture.OffsetX.value && !aperture.OffsetX.fract && !aperture.OffsetY.value && !aperture.OffsetY.fract, + "Unexpected offset %u x %u.\n", aperture.OffsetX.value, aperture.OffsetY.value); + + hr = IMFVideoDisplayControl_SetAspectRatioMode(display_control, MFVideoARMode_None); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + get_output_aperture(mixer, &frame_size, &aperture); +todo_wine { + ok(frame_size.cx == 199 && frame_size.cy == 298, "Unexpected frame size %u x %u.\n", frame_size.cx, frame_size.cy); + ok(aperture.Area.cx == 199 && aperture.Area.cy == 298, "Unexpected size %u x %u.\n", aperture.Area.cx, aperture.Area.cy); +} + ok(!aperture.OffsetX.value && !aperture.OffsetX.fract && !aperture.OffsetY.value && !aperture.OffsetY.fract, + "Unexpected offset %u x %u.\n", aperture.OffsetX.value, aperture.OffsetY.value); + + IMFVideoDisplayControl_Release(display_control); + IMFVideoPresenter_Release(presenter); + IMFTransform_Release(mixer); + +done: + IDirect3D9_Release(d3d); + DestroyWindow(window); +} + static void test_mixer_output_rectangle(void) { IMFVideoMixerControl *mixer_control; @@ -2574,6 +2705,7 @@ START_TEST(evr) test_presenter_ar_mode(); test_presenter_video_window(); test_presenter_quality_control(); + test_presenter_media_type(); test_mixer_output_rectangle(); test_mixer_zorder(); test_mixer_samples();
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
Scaling logic was taken entirely from VMR9.
dlls/evr/presenter.c | 51 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 5701eb17bd3..9b7fb5f6f67 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -426,10 +426,27 @@ static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSu return hr; }
+static void scale_rect(RECT *rect, unsigned int width, unsigned int height, const MFVideoNormalizedRect *scale) +{ + if (rect->left == 0.0f && rect->top == 0.0f && rect->right == 1.0f && rect->bottom == 1.0f) + { + SetRect(rect, 0, 0, width, height); + } + else + { + rect->left = width * scale->left; + rect->right = width * scale->right; + rect->top = height * scale->top; + rect->bottom = height * scale->bottom; + } +} + static void video_presenter_sample_present(struct video_presenter *presenter, IMFSample *sample) { IDirect3DSurface9 *surface, *backbuffer; IDirect3DDevice9 *device; + D3DSURFACE_DESC desc; + RECT dst, src; HRESULT hr;
if (!presenter->swapchain) @@ -450,7 +467,39 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM
IDirect3DSwapChain9_GetDevice(presenter->swapchain, &device); IDirect3DDevice9_StretchRect(device, surface, NULL, backbuffer, NULL, D3DTEXF_POINT); - IDirect3DSwapChain9_Present(presenter->swapchain, NULL, NULL, NULL, NULL, 0); + + IDirect3DSurface9_GetDesc(surface, &desc); + scale_rect(&src, desc.Width, desc.Height, &presenter->src_rect); + + IDirect3DSurface9_GetDesc(backbuffer, &desc); + SetRect(&dst, 0, 0, desc.Width, desc.Height); + + if (presenter->ar_mode & MFVideoARMode_PreservePicture) + { + unsigned int src_width = src.right - src.left, src_height = src.bottom - src.top; + unsigned int dst_width = dst.right - dst.left, dst_height = dst.bottom - dst.top; + + if (src_width * dst_height > dst_width * src_height) + { + /* src is "wider" than dst. */ + unsigned int dst_center = (dst.top + dst.bottom) / 2; + unsigned int scaled_height = src_height * dst_width / src_width; + + dst.top = dst_center - scaled_height / 2; + dst.bottom = dst.top + scaled_height; + } + else if (src_width * dst_height < dst_width * src_height) + { + /* src is "taller" than dst. */ + unsigned int dst_center = (dst.left + dst.right) / 2; + unsigned int scaled_width = src_width * dst_height / src_height; + + dst.left = dst_center - scaled_width / 2; + dst.right = dst.left + scaled_width; + } + } + + IDirect3DSwapChain9_Present(presenter->swapchain, &src, &dst, NULL, NULL, 0);
IDirect3DDevice9_Release(device); IDirect3DSurface9_Release(backbuffer);