Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/mixer.c | 75 ++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 28 deletions(-)
diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c index 4f5837a49a4..b9a28c4ad75 100644 --- a/dlls/evr/mixer.c +++ b/dlls/evr/mixer.c @@ -95,7 +95,8 @@ struct video_mixer IMFAttributes *attributes; IMFAttributes *internal_attributes; unsigned int mixing_flags; - unsigned int is_streaming; + unsigned int is_streaming : 1; + unsigned int output_rendered : 1; struct { COLORREF rgba; @@ -207,6 +208,20 @@ static void video_mixer_update_zorder_map(struct video_mixer *mixer) qsort(mixer->zorder, mixer->input_count, sizeof(*mixer->zorder), video_mixer_zorder_sort_compare); }
+static void video_mixer_flush_input(struct video_mixer *mixer) +{ + unsigned int i; + + for (i = 0; i < mixer->input_count; ++i) + { + if (mixer->inputs[i].sample) + IMFSample_Release(mixer->inputs[i].sample); + mixer->inputs[i].sample = NULL; + mixer->inputs[i].sample_requested = 0; + } + mixer->output_rendered = 0; +} + static void video_mixer_clear_types(struct video_mixer *mixer) { unsigned int i; @@ -216,10 +231,8 @@ static void video_mixer_clear_types(struct video_mixer *mixer) if (mixer->inputs[i].media_type) IMFMediaType_Release(mixer->inputs[i].media_type); mixer->inputs[i].media_type = NULL; - if (mixer->inputs[i].sample) - IMFSample_Release(mixer->inputs[i].sample); - mixer->inputs[i].sample = NULL; } + video_mixer_flush_input(mixer); for (i = 0; i < mixer->output.rt_formats_count; ++i) { IMFMediaType_Release(mixer->output.rt_formats[i].media_type); @@ -1129,17 +1142,7 @@ static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, case MFT_MESSAGE_COMMAND_FLUSH:
EnterCriticalSection(&mixer->cs); - - for (i = 0; i < mixer->input_count; ++i) - { - if (mixer->inputs[i].sample) - { - IMFSample_Release(mixer->inputs[i].sample); - mixer->inputs[i].sample = NULL; - mixer->inputs[i].sample_requested = 0; - } - } - + video_mixer_flush_input(mixer); LeaveCriticalSection(&mixer->cs);
break; @@ -1189,10 +1192,12 @@ static HRESULT WINAPI video_mixer_transform_ProcessInput(IMFTransform *iface, DW { if (!input->media_type || !mixer->output.media_type) hr = MF_E_TRANSFORM_TYPE_NOT_SET; - else if (input->sample) + else if (input->sample && !mixer->output_rendered) hr = MF_E_NOTACCEPTING; else { + if (input->sample && mixer->output_rendered) + video_mixer_flush_input(mixer); mixer->is_streaming = 1; input->sample_requested = 0; input->sample = sample; @@ -1361,6 +1366,7 @@ static HRESULT video_mixer_get_sample_desired_time(IMFSample *sample, LONGLONG * IMFDesiredSample *desired; HRESULT hr;
+ *timestamp = *duration = 0; if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFDesiredSample, (void **)&desired))) { hr = IMFDesiredSample_GetDesiredSampleTimeAndDuration(desired, timestamp, duration); @@ -1370,6 +1376,18 @@ static HRESULT video_mixer_get_sample_desired_time(IMFSample *sample, LONGLONG * return hr; }
+static BOOL video_mixer_has_input(const struct video_mixer *mixer) +{ + unsigned int i; + + for (i = 0; i < mixer->input_count; ++i) + { + if (!mixer->inputs[i].sample) return FALSE; + } + + return TRUE; +} + static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *buffers, DWORD *status) { @@ -1377,6 +1395,7 @@ static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, D LONGLONG timestamp, duration; IDirect3DSurface9 *surface; IDirect3DDevice9 *device; + BOOL repaint = FALSE; unsigned int i; HRESULT hr;
@@ -1396,15 +1415,20 @@ static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, D { if (mixer->is_streaming) { - for (i = 0; i < mixer->input_count; ++i) + /* Desired timestamp is ignored, duration is required to be non-zero but is not used either. */ + if (SUCCEEDED(video_mixer_get_sample_desired_time(buffers->pSample, ×tamp, &duration))) { - if (!mixer->inputs[i].sample) + if (!(repaint = !!duration)) { - hr = MF_E_TRANSFORM_NEED_MORE_INPUT; - break; + WARN("Unexpected sample duration.\n"); + hr = E_INVALIDARG; } }
+ /* Not enough input, or no new input. */ + if (SUCCEEDED(hr) && (!video_mixer_has_input(mixer) || (!repaint && mixer->output_rendered))) + hr = MF_E_TRANSFORM_NEED_MORE_INPUT; + if (SUCCEEDED(hr)) { video_mixer_render(mixer, surface); @@ -1412,22 +1436,17 @@ static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, D timestamp = duration = 0; if (SUCCEEDED(IMFSample_GetSampleTime(mixer->inputs[0].sample, ×tamp))) { - IMFSample_SetSampleTime(buffers->pSample, timestamp); - IMFSample_GetSampleDuration(mixer->inputs[0].sample, &duration); + IMFSample_SetSampleTime(buffers->pSample, timestamp); IMFSample_SetSampleDuration(buffers->pSample, duration); } + mixer->output_rendered = 1; }
- if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && !repaint) { for (i = 0; i < mixer->input_count; ++i) - { - if (mixer->inputs[i].sample) - IMFSample_Release(mixer->inputs[i].sample); - mixer->inputs[i].sample = NULL; video_mixer_request_sample(mixer, i); - } } } else
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/mixer.c | 21 +++----- dlls/evr/tests/evr.c | 121 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 14 deletions(-)
diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c index b9a28c4ad75..8fe80c2f4a9 100644 --- a/dlls/evr/mixer.c +++ b/dlls/evr/mixer.c @@ -1125,34 +1125,27 @@ static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface,
TRACE("%p, %#x, %#lx.\n", iface, message, param);
+ EnterCriticalSection(&mixer->cs); + switch (message) { case MFT_MESSAGE_SET_D3D_MANAGER: - - EnterCriticalSection(&mixer->cs); - video_mixer_release_device_manager(mixer); if (param) hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&mixer->device_manager);
- LeaveCriticalSection(&mixer->cs); - break;
case MFT_MESSAGE_COMMAND_FLUSH: - - EnterCriticalSection(&mixer->cs); video_mixer_flush_input(mixer); - LeaveCriticalSection(&mixer->cs);
break;
case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: case MFT_MESSAGE_NOTIFY_END_STREAMING: - - EnterCriticalSection(&mixer->cs); - - if (!mixer->is_streaming) + if (mixer->is_streaming) + video_mixer_flush_input(mixer); + else { for (i = 0; i < mixer->input_count; ++i) video_mixer_request_sample(mixer, i); @@ -1160,8 +1153,6 @@ static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface,
mixer->is_streaming = message == MFT_MESSAGE_NOTIFY_BEGIN_STREAMING;
- LeaveCriticalSection(&mixer->cs); - break;
case MFT_MESSAGE_COMMAND_DRAIN: @@ -1172,6 +1163,8 @@ static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, hr = E_NOTIMPL; }
+ LeaveCriticalSection(&mixer->cs); + return hr; }
diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 57b64937b79..046a7e4db59 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -94,6 +94,15 @@ static IFilterGraph2 *create_graph(void) return ret; }
+#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) +static void _expect_ref(IUnknown *obj, ULONG ref, int line) +{ + ULONG rc; + IUnknown_AddRef(obj); + rc = IUnknown_Release(obj); + ok_(__FILE__,line)(rc == ref, "Unexpected refcount %d, expected %d.\n", rc, ref); +} + static ULONG get_refcount(void *iface) { IUnknown *unknown = iface; @@ -3061,6 +3070,117 @@ static void test_MFIsFormatYUV(void) } }
+static void test_mixer_render(void) +{ + IMFMediaType *video_type, *output_type; + IMFVideoMixerControl *mixer_control; + IDirect3DDeviceManager9 *manager; + IMFVideoProcessor *processor; + IDirect3DSurface9 *surface; + IDirect3DDevice9 *device; + IMFTransform *mixer; + IMFSample *sample; + DWORD status; + HWND window; + UINT token; + HRESULT hr; + + window = create_window(); + if (!(device = create_device(window))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + goto done; + } + + hr = MFCreateVideoMixer(NULL, &IID_IDirect3DDevice9, &IID_IMFTransform, (void **)&mixer); + ok(hr == S_OK, "Failed to create a mixer, hr %#x.\n", hr); + + hr = IMFTransform_QueryInterface(mixer, &IID_IMFVideoProcessor, (void **)&processor); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_QueryInterface(mixer, &IID_IMFVideoMixerControl, (void **)&mixer_control); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + /* Configure device and media types. */ + hr = DXVA2CreateDirect3DDeviceManager9(&token, &manager); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token); + ok(hr == S_OK, "Failed to set a device, 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); + + video_type = create_video_type(&MFVideoFormat_RGB32); + + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)64 << 32 | 64); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_SetInputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_GetOutputAvailableType(mixer, 0, 0, &output_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTransform_SetOutputType(mixer, 0, output_type, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFMediaType_Release(output_type); + IMFMediaType_Release(video_type); + + surface = create_surface(manager, 64, 64); + ok(!!surface, "Failed to create input surface.\n"); + + hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + EXPECT_REF(sample, 1); + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + EXPECT_REF(sample, 2); + + hr = IMFTransform_GetOutputStatus(mixer, &status); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(status == MFT_OUTPUT_STATUS_SAMPLE_READY, "Unexpected status %#x.\n", status); + + /* FLUSH/END_STREAMING releases input */ + hr = IMFTransform_ProcessMessage(mixer, MFT_MESSAGE_NOTIFY_END_STREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + EXPECT_REF(sample, 1); + + hr = IMFTransform_GetOutputStatus(mixer, &status); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!status, "Unexpected status %#x.\n", status); + + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + EXPECT_REF(sample, 2); + + hr = IMFTransform_GetOutputStatus(mixer, &status); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(status == MFT_OUTPUT_STATUS_SAMPLE_READY, "Unexpected status %#x.\n", status); + + hr = IMFTransform_ProcessMessage(mixer, MFT_MESSAGE_COMMAND_FLUSH, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + EXPECT_REF(sample, 1); + + hr = IMFTransform_GetOutputStatus(mixer, &status); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!status, "Unexpected status %#x.\n", status); + + IMFSample_Release(sample); + IDirect3DSurface9_Release(surface); + IMFTransform_Release(mixer); + + IDirect3DDevice9_Release(device); + IDirect3DDeviceManager9_Release(manager); + +done: + DestroyWindow(window); +} + START_TEST(evr) { IMFVideoPresenter *presenter; @@ -3099,6 +3219,7 @@ START_TEST(evr) test_mixer_output_rectangle(); test_mixer_zorder(); test_mixer_samples(); + test_mixer_render(); test_MFIsFormatYUV();
CoUninitialize();