Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 88ab9766f984b092d29cffad9b898161eb9a59f2
https://github.com/WebKit/WebKit/commit/88ab9766f984b092d29cffad9b898161eb9a59f2
Author: Jean-Yves Avenard <[email protected]>
Date: 2026-05-08 (Fri, 08 May 2026)
Changed paths:
M Source/WebCore/platform/graphics/cocoa/VideoMediaSampleRenderer.h
M Source/WebCore/platform/graphics/cocoa/VideoMediaSampleRenderer.mm
M Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.cpp
Log Message:
-----------
[MSE|Cocoa] Power Regression while watching Netflix when a decompression
session is in use.
https://bugs.webkit.org/show_bug.cgi?id=314364
rdar://176517064
Reviewed by Jer Noble.
VideoMediaSampleRenderer logic was to keep a fixed number of decoded frames
ahead of current time (driven by the DecodeHighWaterMark constant: 133ms).
Decoding would then be performed in burst until that number was reached
and stop, a new decode every time a previous sample expired.
An AVSampleBufferDisplayLayer however, uses a low of 100ms and a high of 166ms
watermark logic, driving the decode to be performed in burst instead.
Analysis shows that doing so is more efficient power wise.
We now make the VideoMediaSampleRenderer use a low/high watermark approach
we will decode until we have decoded DecodeHighWaterMark frames and stop
until there's only DecodeLowWaterMark left.
In addition, we copy AVF's use of kVTDecodeFrame_1xRealTimePlayback,
withholding kVTDecodeFrame_1xRealTimePlayback during initial fill and stopping
when below low water window; while unconditionally set for iOS family.
Introduce two flags on VideoMediaSampleRenderer:
- m_decoderIdledAtHighWaterMark: set when we pause the decoder on the
lookahead-confirmed stop branch; cleared inline the next time we see
endTime drop below the low watermark. Drives the hysteresis gate that
keeps the decoder idle through the drain window.
- m_hasReachedHighWatermark: set on any crossing of the high watermark,
cleared only on flush. Used exclusively to mirror AVF's decay-gate on
macOS, where RealTime is suppressed when this flag is set AND the
decoded buffer has since drained below the low watermark. Non-macOS
platforms set the flag whenever rate is close to 1x and the sample
is displaying, matching AVF's iOS policy. Initial fill (before the
first high crossing) is no longer gated out on any platform, again
matching AVF.
Both flags are cleared in flushDecodedSampleQueue so seek/track-change
behavior is identical to before. DecodeHighWaterMark is also raised from
133 ms to 166 ms; with the hysteresis in place this produces clean
~167 ms high-to-high pause cycles with 2-3 decodes per burst on 24 fps
4K MSE content, instead of the previous per-frame cadence pinned at the
high mark.
Also fly-by fix a missing IPC parameter forwarding in
RemoteAudioVideoRendererProxyManager::enqueueSample: the
minimumPresentationTime received from the .messages.in was accepted
by the handler but not passed through to renderer->enqueueSample,
silently defaulting to std::nullopt. As a result, GPU-process MSE
playback never saw the caller's lookahead hint, which meant the
lookahead-stop branch (and therefore the hysteresis itself) never
engaged for MSE video in the GPU process. Forwarding the parameter
restores the intended flow and is a prerequisite for the hysteresis
work above to take effect on the MSE path.
* Source/WebCore/platform/graphics/cocoa/VideoMediaSampleRenderer.h:
Add m_decoderIdledAtHighWaterMark and m_hasReachedHighWatermark,
both dispatcher-guarded.
* Source/WebCore/platform/graphics/cocoa/VideoMediaSampleRenderer.mm:
(WebCore::VideoMediaSampleRenderer::decodeNextSampleIfNeeded):
Add the hysteresis gate; set m_hasReachedHighWatermark on every
high-watermark crossing; set m_decoderIdledAtHighWaterMark on the
lookahead-confirmed stop; move the RealTime-flag gate below the
sample-consumed block so it can check sample->isNonDisplaying()
and apply the macOS-only decay suppression via
m_hasReachedHighWatermark. Bump DecodeHighWaterMark from 133 ms to
166 ms.
(WebCore::VideoMediaSampleRenderer::flushDecodedSampleQueue):
Clear both new flags on flush.
* Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.cpp:
(WebKit::RemoteAudioVideoRendererProxyManager::enqueueSample):
Pass the received minimumPresentationTime through to
renderer->enqueueSample instead of dropping it on the floor and
relying on the std::nullopt default.
Canonical link: https://commits.webkit.org/312870@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications