From 3bb0be9bad50812a05e98b42d31ec9d1e581490a Mon Sep 17 00:00:00 2001 From: Marcin Mielczarczyk Date: Thu, 18 Jul 2024 07:25:28 +0200 Subject: [PATCH 1/2] ARRISEOS-45973: Initial support for instant rate "custom-instant-rate-change" will do instant rate change without flush. This change is based on Comcast patch: https://code.rdkcentral.com/r/plugins/gitiles/rdk/components/generic/rdk-oe/meta-rdk-ext/+/refs/heads/rdk-next/recipes-extended/wpe-webkit/files/2.38.2/comcast-AMLOGIC-3262-Initial-support-for-instant-rat.patch --- .../gstreamer/MediaPlayerPrivateGStreamer.cpp | 14 ++++++++++++++ .../gstreamer/mse/WebKitMediaSourceGStreamer.cpp | 16 +++++++++++++++- Source/cmake/OptionsWPE.cmake | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 1bb518f0a228d..b478f93e6429e 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -565,6 +565,20 @@ void MediaPlayerPrivateGStreamer::updatePlaybackRate() GST_INFO_OBJECT(pipeline(), mute ? "Need to mute audio" : "Do not need to mute audio"); if (m_lastPlaybackRate != m_playbackRate) { +#if ENABLE(INSTANT_RATE_CHANGE) + bool didInstantRateChange = false; + if (!paused()) { + GstStructure* s = gst_structure_new("custom-instant-rate-change", + "rate", G_TYPE_DOUBLE, m_playbackRate, nullptr); + didInstantRateChange = gst_element_send_event( + pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s)); + } + if (didInstantRateChange) { + g_object_set(m_pipeline.get(), "mute", mute, nullptr); + m_lastPlaybackRate = m_playbackRate; + } + else +#endif if (doSeek(playbackPosition(), m_playbackRate, static_cast(GST_SEEK_FLAG_FLUSH))) { g_object_set(m_pipeline.get(), "mute", mute, nullptr); m_lastPlaybackRate = m_playbackRate; diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp index 4170799b415c7..23c37e1503d38 100644 --- a/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp @@ -820,7 +820,8 @@ static void webKitMediaSrcStreamFlush(Stream* stream, bool isSeekingFlush, GstCl GST_DEBUG_OBJECT(stream->source, "Resetting segment to current pipeline running time (%" GST_TIME_FORMAT " and stream time (%" GST_TIME_FORMAT " = %s)", GST_TIME_ARGS(pipelineRunningTime), GST_TIME_ARGS(pipelineStreamTime), streamTime.toString().ascii().data()); streamingMembers->segment.base = pipelineRunningTime; - streamingMembers->segment.start = streamingMembers->segment.time = static_cast(pipelineStreamTime); + streamingMembers->segment.rate = stream->source->priv->rate; + streamingMembers->segment.position = streamingMembers->segment.start = streamingMembers->segment.time = static_cast(pipelineStreamTime); } } } @@ -952,6 +953,19 @@ static gboolean webKitMediaSrcSendEvent(GstElement* element, GstEvent* event) webKitMediaSrcSeek(WEBKIT_MEDIA_SRC(element), start, rate); return true; } + case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: { + WebKitMediaSrc* source = WEBKIT_MEDIA_SRC(element); + gboolean result = !source->priv->streams.isEmpty(); + for (const RefPtr& stream : source->priv->streams.values()) + result &= gst_pad_push_event(stream->pad.get(), gst_event_ref(event)); + if (gst_event_has_name(event, "custom-instant-rate-change")) { + gdouble rate = 1.0; + if (gst_structure_get_double(gst_event_get_structure(event), "rate", &rate)) + source->priv->rate = rate; + } + gst_event_unref(event); + return result; + } default: return GST_ELEMENT_CLASS(webkit_media_src_parent_class)->send_event(element, event); } diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index a81bfdadd05bd..aa00de257a2a8 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -107,6 +107,7 @@ WEBKIT_OPTION_DEFINE(USE_GSTREAMER_HOLEPUNCH "Whether to enable GStreamer holepu WEBKIT_OPTION_DEFINE(USE_EXTERNAL_HOLEPUNCH "Whether to enable external holepunch" PRIVATE OFF) WEBKIT_OPTION_DEFINE(ENABLE_ACCELERATED_2D_CANVAS "Whether to enable accelerated 2D canvas" PRIVATE OFF) WEBKIT_OPTION_DEFINE(ENABLE_OIPF_VK "Whether to enable OIPF keys for DAE applications" PRIVATE OFF) +WEBKIT_OPTION_DEFINE(ENABLE_INSTANT_RATE_CHANGE "Whether to enable instant rate change" PRIVATE OFF) # Supported platforms. WEBKIT_OPTION_DEFINE(USE_WPEWEBKIT_PLATFORM_WESTEROS "Whether to enable support for the Westeros platform" PUBLIC OFF) From e6e110e34cad45d4ac6a45f0405b57b96cb041ff Mon Sep 17 00:00:00 2001 From: Marcin Mielczarczyk Date: Wed, 8 May 2024 10:52:25 +0200 Subject: [PATCH 2/2] [YTB tests] Increase the time granularity This fixes YTB MSE Progressive Tests 29, 30, 32, 33 (granularity) by increasing the time granularity to better values (200ms on average, the spec allows a range from 15 to 250ms). --- Source/WebCore/html/HTMLMediaElement.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 7a0e66aa6e9b4..b45fa6d134784 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -4164,7 +4164,7 @@ void HTMLMediaElement::scanTimerFired() // The spec says to fire periodic timeupdate events (those sent while playing) every // "15 to 250ms", we choose the slowest frequency -static const Seconds maxTimeupdateEventFrequency { 250_ms }; +static const Seconds maxTimeupdateEventFrequency { 200_ms }; void HTMLMediaElement::startPlaybackProgressTimer() { @@ -4211,8 +4211,8 @@ void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent) MonotonicTime now = MonotonicTime::now(); Seconds timedelta = now - m_clockTimeAtLastUpdateEvent; - // throttle the periodic events - if (periodicEvent && timedelta < maxTimeupdateEventFrequency) + // Throttle the periodic events, but leave some room for timers that run slightly faster than expected. + if (periodicEvent && timedelta < (maxTimeupdateEventFrequency - 50_ms)) return; // Some media engines make multiple "time changed" callbacks at the same time, but we only want one