-- v3: mfmediaengine: Pass volume changes to the audio renderer. mfmediaengine/tests: Add a simple video playback test.
From: Bernhard Kölbl besentv@gmail.com
Testing playback of a short mp4 file with h264 video and aac audio.
This test would hang before the changes made to media format handling for output nodes in the media session. Adding it now to reduce the risk of regressions. --- dlls/mfmediaengine/tests/mfmediaengine.c | 192 +++++++++++++++++++++++ dlls/mfmediaengine/tests/resource.rc | 7 + dlls/mfmediaengine/tests/test.mp4 | Bin 0 -> 4355 bytes 3 files changed, 199 insertions(+) create mode 100644 dlls/mfmediaengine/tests/test.mp4
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 3a5b2bf8253..6efe489c6d3 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1313,6 +1313,197 @@ done: CloseHandle(notify.ready_event); }
+static WCHAR *unpack_resource(const WCHAR *name) +{ + static WCHAR path[MAX_PATH]; + void *res_data; + DWORD written; + HANDLE file; + HRSRC res; + + GetTempPathW(ARRAY_SIZE(path), path); + lstrcatW(path, name); + + file = CreateFileW(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", wine_dbgstr_w(path), GetLastError()); + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok(res != 0, "couldn't find resource\n"); + + res_data = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, res_data, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), "couldn't write resource\n" ); + + CloseHandle(file); + + return path; +} + +struct playback_notify +{ + IMFMediaEngineNotify IMFMediaEngineNotify_iface; + + IMFMediaEngineEx *media_engine; + HANDLE ended_event; + HANDLE ready_event; + HRESULT error; +}; + +static HRESULT WINAPI playback_notify_QueryInterface(IMFMediaEngineNotify *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IMFMediaEngineNotify)) + { + *obj = iface; + IMFMediaEngineNotify_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI playback_notify_AddRef(IMFMediaEngineNotify *iface) +{ + return 2; +} + +static ULONG WINAPI playback_notify_Release(IMFMediaEngineNotify *iface) +{ + return 1; +} + +static HRESULT WINAPI playback_notify_EventNotify(IMFMediaEngineNotify *iface, DWORD event, DWORD_PTR param1, DWORD param2) +{ + struct playback_notify *notify = CONTAINING_RECORD(iface, struct playback_notify, IMFMediaEngineNotify_iface); + IMFMediaEngineEx *media_engine = notify->media_engine; + DWORD width, height; + HRESULT hr; + BOOL ret; + + switch (event) + { + case MF_MEDIA_ENGINE_EVENT_CANPLAY: + hr = IMFMediaEngineEx_Play(media_engine); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case MF_MEDIA_ENGINE_EVENT_FORMATCHANGE: + ret = IMFMediaEngineEx_HasVideo(media_engine); + ok(ret, "Unexpected HasVideo %u.\n", ret); + hr = IMFMediaEngineEx_GetNativeVideoSize(media_engine, &width, &height); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(width == 32, "Unexpected width %lu.\n", width); + ok(height == 24, "Unexpected height %lu.\n", height); + break; + + case MF_MEDIA_ENGINE_EVENT_ERROR: + ok(broken(param2 == MF_E_UNSUPPORTED_BYTESTREAM_TYPE), "Unexpected error %#lx\n", param2); + notify->error = param2; + /* fallthrough */ + case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY: + hr = IMFMediaEngineEx_Play(media_engine); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + case MF_MEDIA_ENGINE_EVENT_TIMEUPDATE: + SetEvent(notify->ready_event); + break; + case MF_MEDIA_ENGINE_EVENT_ENDED: + SetEvent(notify->ended_event); + break; + } + + return S_OK; +} + +static IMFMediaEngineNotifyVtbl playback_notify_vtbl = +{ + playback_notify_QueryInterface, + playback_notify_AddRef, + playback_notify_Release, + playback_notify_EventNotify, +}; + +static void test_video_playback(void) +{ + struct playback_notify notify = {{&playback_notify_vtbl}}; + IMFMediaEngineEx *media_engine; + IMFDXGIDeviceManager *manager; + double current_time, duration; + LONGLONG presentation_time; + WCHAR *filename = NULL; + ID3D11Device *device; + UINT token; + HRESULT hr; + DWORD res; + + notify.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!notify.ready_event, "CreateEventW failed, error %lu\n", GetLastError()); + + notify.ended_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!notify.ended_event, "CreateEventW failed, error %lu\n", GetLastError()); + + if (!(device = create_d3d11_device())) + { + skip("Failed to create a D3D11 device, skipping tests.\n"); + return; + } + + hr = pMFCreateDXGIDeviceManager(&token, &manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)device, token); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + media_engine = create_media_engine_ex(¬ify.IMFMediaEngineNotify_iface, + manager, DXGI_FORMAT_B8G8R8X8_UNORM); + + IMFDXGIDeviceManager_Release(manager); + + media_engine = create_media_engine_ex(¬ify.IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM); + + if (!(notify.media_engine = media_engine)) + return; + + filename = unpack_resource(L"test.mp4"); + ok(!!filename, "Failed to unpack resource.\n"); + + hr = IMFMediaEngineEx_SetSource(media_engine, filename); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + res = WaitForSingleObject(notify.ready_event, 5000); + ok(!res, "Unexpected res %#lx.\n", res); + + if (FAILED(notify.error)) + { + win_skip("Media engine reported error %#lx, skipping tests.\n", notify.error); + goto done; + } + + duration = IMFMediaEngineEx_GetDuration(media_engine); + todo_wine ok(duration == 0.167, "IMFMediaEngineEx_GetDuration returned %lf.\n", duration); + + while (WaitForSingleObject(notify.ended_event, 25) > WAIT_OBJECT_0) + { + current_time = IMFMediaEngineEx_GetCurrentTime(media_engine); + ok(current_time <= 0.270, "IMFMediaEngineEx_GetCurrentTime returned %lf.\n", current_time); + + hr = IMFMediaEngineEx_OnVideoStreamTick(media_engine, &presentation_time); + ok(hr == S_OK || hr == S_FALSE, "Unexpected hr %#lx.\n", hr); + ok(presentation_time <= 1670000, "presentation_time was %I64d.\n", presentation_time); + } + + current_time = IMFMediaEngineEx_GetCurrentTime(media_engine); + todo_wine ok(current_time > 0.0, "IMFMediaEngineEx_GetCurrentTime returned %lf.\n", current_time); + +done: + IMFMediaEngineEx_Shutdown(media_engine); + IMFMediaEngineEx_Release(media_engine); + + ID3D11Device_Release(device); + + CloseHandle(notify.ended_event); + CloseHandle(notify.ready_event); +} + START_TEST(mfmediaengine) { HRESULT hr; @@ -1344,6 +1535,7 @@ START_TEST(mfmediaengine) test_SetSourceFromByteStream(); test_audio_configuration(); test_TransferVideoFrames(); + test_video_playback();
IMFMediaEngineClassFactory_Release(factory);
diff --git a/dlls/mfmediaengine/tests/resource.rc b/dlls/mfmediaengine/tests/resource.rc index 50152586758..60ef1da78e6 100644 --- a/dlls/mfmediaengine/tests/resource.rc +++ b/dlls/mfmediaengine/tests/resource.rc @@ -30,3 +30,10 @@ i420-64x64.avi RCDATA i420-64x64.avi /* Generated from running the tests on Windows */ /* @makedep: rgb32frame.bmp */ rgb32frame.bmp RCDATA rgb32frame.bmp + +/* ffmpeg -filter_complex "testsrc=duration=0.16:size=32x24:rate=30,colorspace=iall=bt709:all=bt709:format=yuv420p[0]; \ + * sine=frequency=1000:duration=0.16[1]" -c:v h264 -profile:v main \ + * -map "[0]:v" -map "[1]:a" -to 0.16s -f mp4 -y test.mp4 + */ +/* @makedep: test.mp4 */ +test.mp4 RCDATA test.mp4 diff --git a/dlls/mfmediaengine/tests/test.mp4 b/dlls/mfmediaengine/tests/test.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..bb367c996be78ac1dec5c6c9e40d4c1d2e26d1a4 GIT binary patch literal 4355 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
literal 0 HcmV?d00001
From: Bernhard Kölbl besentv@gmail.com
--- dlls/mfmediaengine/main.c | 58 ++++++++++++++++++++---- dlls/mfmediaengine/tests/mfmediaengine.c | 3 ++ 2 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index b2ddc376db8..c15fdbd164c 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -174,6 +174,10 @@ struct media_engine } cb; } d3d11; } video_frame; + struct + { + IMFMediaSink *sar; + } audio_renderer; CRITICAL_SECTION cs; };
@@ -1002,27 +1006,36 @@ static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresen static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; - IMFActivate *sar_activate; + IMFAttributes *attrs; + IMFStreamSink *sink; + IMFMediaSink *sar; HRESULT hr;
*node = NULL;
- if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate))) + if (FAILED(hr = MFCreateAttributes(&attrs, 2))) return hr;
/* Configuration attributes keys differ between Engine and SAR. */ if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category))) - IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category); + IMFAttributes_SetUINT32(attrs, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category); if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role))) - IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role); + IMFAttributes_SetUINT32(attrs, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role); + + if (FAILED(hr = MFCreateAudioRenderer(attrs, &sar))) + return hr; + + if (FAILED(hr = IMFMediaSink_GetStreamSinkByIndex(sar, 0, &sink))) + return hr;
if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node))) { - IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate); + IMFTopologyNode_SetObject(*node, (IUnknown *)sink); IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); }
- IMFActivate_Release(sar_activate); + IMFStreamSink_Release(sink); + engine->audio_renderer.sar = sar;
return hr; } @@ -1084,6 +1097,12 @@ static void media_engine_clear_presentation(struct media_engine *engine) if (engine->presentation.pd) IMFPresentationDescriptor_Release(engine->presentation.pd); memset(&engine->presentation, 0, sizeof(engine->presentation)); + if (engine->audio_renderer.sar) + { + IMFMediaSink_Shutdown(engine->audio_renderer.sar); + IMFMediaSink_Release(engine->audio_renderer.sar); + engine->audio_renderer.sar = NULL; + } }
static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) @@ -1999,6 +2018,7 @@ static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface) static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume) { struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); + IMFGetService *service = NULL; HRESULT hr = S_OK;
TRACE("%p, %f.\n", iface, volume); @@ -2008,9 +2028,31 @@ static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double vol hr = MF_E_SHUTDOWN; else if (volume != engine->volume) { - engine->volume = volume; - IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0); + IMFSimpleAudioVolume *sa_volume; + + if (!engine->audio_renderer.sar) + { + hr = E_FAIL; + goto done; + } + + if (FAILED(hr = IMFMediaSink_QueryInterface(engine->audio_renderer.sar, &IID_IMFGetService, (void **)&service))) + goto done; + + if (FAILED(hr = IMFGetService_GetService(service, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume))) + goto done; + + if (SUCCEEDED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, (float)volume))) + { + engine->volume = volume; + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0); + } + + IMFSimpleAudioVolume_Release(sa_volume); } +done: + if (service) + IMFGetService_Release(service); LeaveCriticalSection(&engine->cs);
return hr; diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 6efe489c6d3..61152d395f5 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1472,6 +1472,9 @@ static void test_video_playback(void) res = WaitForSingleObject(notify.ready_event, 5000); ok(!res, "Unexpected res %#lx.\n", res);
+ hr = IMFMediaEngineEx_SetVolume(media_engine, 0.1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(notify.error)) { win_skip("Media engine reported error %#lx, skipping tests.\n", notify.error);
Nikolay Sivov (@nsivov) commented about dlls/mfmediaengine/main.c:
goto done;
}
if (FAILED(hr = IMFMediaSink_QueryInterface(engine->audio_renderer.sar, &IID_IMFGetService, (void **)&service)))
goto done;
if (FAILED(hr = IMFGetService_GetService(service, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume)))
goto done;
if (SUCCEEDED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, (float)volume)))
{
engine->volume = volume;
IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
}
IMFSimpleAudioVolume_Release(sa_volume);
First of all, it does not have to be that explicit. You can ask session for volume control service directly, without accessing SAR node yourself. Second point, what happens if volume is set to 0.5 before media item is set? Does it sync this stored volume with session once it's created?
I don't think it makes sense to include this test together with volume control implementation.
On Wed Nov 23 16:23:22 2022 +0000, Nikolay Sivov wrote:
First of all, it does not have to be that explicit. You can ask session for volume control service directly, without accessing SAR node yourself. Second point, what happens if volume is set to 0.5 before media item is set? Does it sync this stored volume with session once it's created?
Mhm, I didn't think about the second case. It seems like it doesn't, but I could probably make it so on topo load it sets the volume as well.
On Wed Nov 23 16:55:57 2022 +0000, Bernhard Kölbl wrote:
Mhm, I didn't think about the second case. It seems like it doesn't, but I could probably make it so on topo load it sets the volume as well.
It's easy to test manually.
On Wed Nov 23 16:56:54 2022 +0000, Nikolay Sivov wrote:
It's easy to test manually.
I guess you mean on Windows?
On Wed Nov 23 16:59:53 2022 +0000, Bernhard Kölbl wrote:
I guess you mean on Windows?
There is nothing to test on wine, so yes.
On Wed Nov 23 17:05:51 2022 +0000, Nikolay Sivov wrote:
There is nothing to test on wine, so yes.
Well then I'd suggest keeping the first patch together with volume changes.
Well then I'd suggest keeping the first patch together with volume changes.
I don't understand what you mean.
On Wed Nov 23 18:12:28 2022 +0000, Nikolay Sivov wrote:
Well then I'd suggest keeping the first patch together with volume changes.
I don't understand what you mean.
The first patch plays audio and video data, so it's maybe a good idea to keep the tests and add volume changes as well. One before setting the source, one after. Otherwise we can't really add tests right now.
Otherwise we can't really add tests right now.
Volume change tests to be percise.
On Wed Nov 23 19:00:15 2022 +0000, Bernhard Kölbl wrote:
Otherwise we can't really add tests right now.
Volume change tests to be percise.
I think playing something and making sure volume changes is enough, I don't see how you can do that in a test. Important question is what happens when you play next file, does volume go back to 1.0 or not, and so on.
On Wed Nov 23 19:02:25 2022 +0000, Nikolay Sivov wrote:
I think playing something and making sure volume changes is enough, I don't see how you can do that in a test. Important question is what happens when you play next file, does volume go back to 1.0 or not, and so on.
Well, of course you can't check volume change with a test, but it's probably still a good idea to have such a "non winetest" in the codebase, so we don't have situations like with MfPlayer.exe, where you need to download an external app to fix the implementation.
On Wed Nov 23 20:15:03 2022 +0000, Bernhard Kölbl wrote:
Well, of course you can't check volume change with a test, but it's probably still a good idea to have such a "non winetest" in the codebase, so we don't have situations like with MfPlayer.exe, where you need to download an external app to fix the implementation.
So I tested it real quick and volume always changes when you use the SetVolume function, and it's never reset on loading new files. So yeah, the volume needs to be applied to session during load.