[PATCH v8 0/3] MR10306: mfmediaengine: Implement looping behaviour.
When `IMFMediaEngine::SetLoop(TRUE)` is called, media engine will repeatedly loop the video. -- v8: mfmediaengine: Keep the last presentation sample on flush. https://gitlab.winehq.org/wine/wine/-/merge_requests/10306
From: Brendan McGrath <bmcgrath@codeweavers.com> When a sink is stopped, all pending requests are discarded by the client (for example IMFMediaSession). --- dlls/mfmediaengine/video_frame_sink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mfmediaengine/video_frame_sink.c b/dlls/mfmediaengine/video_frame_sink.c index f710466fed4..301a2bcd03a 100644 --- a/dlls/mfmediaengine/video_frame_sink.c +++ b/dlls/mfmediaengine/video_frame_sink.c @@ -1010,6 +1010,7 @@ static HRESULT video_frame_sink_set_state(struct video_frame_sink *sink, enum si { video_frame_sink_sample_queue_flush(sink); video_frame_sink_set_flag(sink, FLAGS_FIRST_FRAME, FALSE); + sink->sample_request_pending = FALSE; } if (state == SINK_STATE_RUNNING && (sink->state == SINK_STATE_STOPPED || sink->state == SINK_STATE_PAUSED || -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10306
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mfmediaengine/main.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 2ababd674d7..9800f27cef9 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -928,6 +928,7 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface); IMFMediaEvent *event = NULL; MediaEventType event_type; + BOOL ended_event = FALSE; HRESULT hr; if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event))) @@ -1008,14 +1009,21 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0); break; case MESessionEnded: - EnterCriticalSection(&engine->cs); - media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE); - media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE); - engine->video_frame.pts = MINLONGLONG; + if (engine->flags & FLAGS_ENGINE_LOOP) + { + media_engine_set_current_time(engine, 0.0); + } + else + { + engine->video_frame.pts = MINLONGLONG; + media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE); + media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE); + ended_event = TRUE; + } LeaveCriticalSection(&engine->cs); - - IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0); + if (ended_event) + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0); break; case MEEndOfPresentationSegment: -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10306
From: Brendan McGrath <bmcgrath@codeweavers.com> On Windows, if IMFMediaEngine::TransferVideoFrame is called after the video has finished, then the last video frame presented is returned. --- dlls/mfmediaengine/video_frame_sink.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dlls/mfmediaengine/video_frame_sink.c b/dlls/mfmediaengine/video_frame_sink.c index 301a2bcd03a..095282532ea 100644 --- a/dlls/mfmediaengine/video_frame_sink.c +++ b/dlls/mfmediaengine/video_frame_sink.c @@ -165,13 +165,6 @@ static void video_frame_sink_sample_queue_flush(struct video_frame_sink *sink) queue->used = 0; queue->front = 0; queue->back = ARRAY_SIZE(queue->samples) - 1; - - if (queue->presentation_sample) - { - IMFSample_Release(queue->presentation_sample); - queue->presentation_sample = NULL; - queue->sample_presented = FALSE; - } } static void video_frame_sink_sample_queue_free(struct video_frame_sink *sink) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10306
v6: - Keep last presented sample after video has finished. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10306#note_132134
Nikolay Sivov (@nsivov) commented about dlls/mfmediaengine/video_frame_sink.c:
queue->used = 0; queue->front = 0; queue->back = ARRAY_SIZE(queue->samples) - 1; - - if (queue->presentation_sample) - { - IMFSample_Release(queue->presentation_sample); - queue->presentation_sample = NULL; - queue->sample_presented = FALSE; - } }
Does this work correctly when we start a new playback? Do we ensure somewhere that old frame is dropped? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10306#note_132151
Does this work correctly when we start a new playback?
I just did a quick test on Windows. It looks to work the same. To test, I called SetSource on a new file at the end of the first presentation and suppressed any new samples from that second source (via the use of a Source extension). When calling `TransferVideoFrame`, I continued to get the last presented frame.
Do we ensure somewhere that old frame is dropped?
The old frame will either be: 1. replaced on delivery of a new sample; or 2. released on release of the media engine -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10306#note_132218
This merge request was approved by Nikolay Sivov. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10306
participants (3)
-
Brendan McGrath -
Brendan McGrath (@redmcg) -
Nikolay Sivov (@nsivov)