[PATCH 0/1] MR8409: mfmediaengine: Only forward the most recent seek time.
MF Media Engine on Windows will only send one seek request at a time. It will queue the `seekTime` value of the most recent `SetCurrentTime` call and forward only that request to the Media Session after it completes its current seek (i.e. when it sends out the `MF_MEDIA_ENGINE_EVENT_SEEKED` notify event). Wine currently forwards every `SetCurrentTime` call to the Media Session, which can result in a large queue of seeks, one performed after the other, resulting in a delay before completing the final seek request. This fixes slow seek times in some worlds in VRChat. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8409
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mfmediaengine/main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 27249f09fa6..51d89bde79b 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -153,6 +153,7 @@ struct media_engine double default_playback_rate; double volume; double duration; + double next_seek; MF_MEDIA_ENGINE_NETWORK network_state; MF_MEDIA_ENGINE_ERR error_code; HRESULT extended_code; @@ -911,6 +912,8 @@ static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *ifac return E_NOTIMPL; } +static HRESULT media_engine_set_current_time(struct media_engine *engine, double seektime); + static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface); @@ -989,6 +992,8 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface media_engine_set_flag(engine, FLAGS_ENGINE_SEEKING | FLAGS_ENGINE_IS_ENDED, FALSE); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_SEEKED, 0, 0); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0); + if (isfinite(engine->next_seek)) + media_engine_set_current_time(engine, engine->next_seek); } LeaveCriticalSection(&engine->cs); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0); @@ -1865,6 +1870,14 @@ static HRESULT media_engine_set_current_time(struct media_engine *engine, double if (FAILED(hr) || !(caps & MFSESSIONCAP_SEEK)) return hr; + if (engine->flags & FLAGS_ENGINE_SEEKING) + { + engine->next_seek = seektime; + return S_OK; + } + + engine->next_seek = NAN; + position.vt = VT_I8; position.hVal.QuadPart = min(max(0, seektime), engine->duration) * 10000000; @@ -3378,6 +3391,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct engine->playback_rate = 1.0; engine->volume = 1.0; engine->duration = NAN; + engine->next_seek = NAN; engine->video_frame.pts = MINLONGLONG; InitializeCriticalSection(&engine->cs); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8409
This makes sense. Have you checked if media session itself does similar kind of throttling on Windows? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8409#note_107745
On Tue Jun 24 20:56:25 2025 +0000, Nikolay Sivov wrote:
This makes sense. Have you checked if media session itself does similar kind of throttling on Windows? I did yes. I made multiple calls to `IMFMediaSession::Start` in a row and found they all reached the `IMFMediaSource`. But if I called `IMFMediaEngine::SetCurrentTime` multiple times in a row, only the first and last made it to the `IMFMediaSource`.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/8409#note_107834
Nikolay Sivov (@nsivov) commented about dlls/mfmediaengine/main.c:
engine->playback_rate = 1.0; engine->volume = 1.0; engine->duration = NAN; + engine->next_seek = NAN; engine->video_frame.pts = MINLONGLONG;
NAN was used for duration as a special marker because it doesn't come from user input. For the "next_seek" we could use another flag probably, instead of relying on this special value. Let me know which way looks better to you. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8409#note_107840
On Tue Jun 24 21:21:02 2025 +0000, Nikolay Sivov wrote:
NAN was used for duration as a special marker because it doesn't come from user input. For the "next_seek" we could use another flag probably, instead of relying on this special value. Let me know which way looks better to you. I actually started with '-1', but then I thought maybe the user _could_ provide that. So I went with NAN for the same reason; it's not a value that you would expect from user input.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/8409#note_107854
This merge request was approved by Nikolay Sivov. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8409
participants (3)
-
Brendan McGrath -
Brendan McGrath (@redmcg) -
Nikolay Sivov (@nsivov)