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 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)