Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 2fcceeb9c6b0ef543e182c5dc28e64dae6281314
      
https://github.com/WebKit/WebKit/commit/2fcceeb9c6b0ef543e182c5dc28e64dae6281314
  Author: Jean-Yves Avenard <[email protected]>
  Date:   2026-04-01 (Wed, 01 Apr 2026)

  Changed paths:
    M LayoutTests/ipc/serialized-type-info.html
    A 
LayoutTests/media/media-source/media-source-seek-during-pending-seek-expected.txt
    A LayoutTests/media/media-source/media-source-seek-during-pending-seek.html
    M Source/WTF/wtf/NativePromise.h
    M Source/WebCore/platform/PlatformMediaError.cpp
    M Source/WebCore/platform/PlatformMediaError.h
    M Source/WebCore/platform/graphics/AudioVideoRenderer.h
    M Source/WebCore/platform/graphics/MediaSourcePrivate.cpp
    M Source/WebCore/platform/graphics/MediaSourcePrivate.h
    M Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
    M Source/WebCore/platform/graphics/SourceBufferPrivate.h
    M Source/WebCore/platform/graphics/avfoundation/AudioVideoRendererAVFObjC.h
    M Source/WebCore/platform/graphics/avfoundation/AudioVideoRendererAVFObjC.mm
    M 
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h
    M 
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm
    M Source/WebCore/platform/graphics/cocoa/MediaPlayerPrivateWebM.h
    M Source/WebCore/platform/graphics/cocoa/MediaPlayerPrivateWebM.mm
    M 
Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp
    M 
Source/WebCore/platform/graphics/gstreamer/mse/MediaSourcePrivateGStreamer.cpp
    M 
Source/WebCore/platform/graphics/gstreamer/mse/MediaSourcePrivateGStreamer.h
    M 
Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.cpp
    M 
Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.h
    M Source/WebCore/platform/mock/mediasource/MockMediaPlayerMediaSource.cpp
    M Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.cpp
    M Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.h
    M 
Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.messages.in
    M Source/WebKit/Platform/IPC/Connection.h
    M Source/WebKit/Scripts/webkit/messages.py
    M Source/WebKit/Shared/WTFArgumentCoders.serialization.in
    M Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
    M Source/WebKit/WebProcess/GPU/media/AudioVideoRendererRemote.cpp
    M Source/WebKit/WebProcess/GPU/media/AudioVideoRendererRemote.h
    M Source/WebKit/WebProcess/GPU/media/RemoteAudioVideoRendererState.h
    M 
Source/WebKit/WebProcess/GPU/media/RemoteAudioVideoRendererState.serialization.in
    M Source/WebKit/WebProcess/GPU/media/SourceBufferPrivateRemote.cpp
    M Source/WebKit/WebProcess/GPU/media/SourceBufferPrivateRemote.h

  Log Message:
  -----------
  Scrubbing a YouTube video in full-screen causes it to exit full-screen mode.
https://bugs.webkit.org/show_bug.cgi?id=311100
rdar://172682230

Reviewed by Jer Noble.

There were two issues at play:
1- The seeking code relied on a key assumption ; the AudioVideoRenderer will
be flushed and then new samples will be enqueued serially during a seeking 
operation:
 - No new flush will be issued while samples are being enqueued.
This guarantees that after a flush, the first sample enqueued to the renderer
will always be a keyframe.

When a new seek is started before the prior one completed, it was assumed that 
the second time
MediaSourcePrivate::waitForTarget was called, any pending promise would be 
rejected by the MediaSource
which would stop the processing flow of the first seek.
However, the MediaSourcePrivate::waitForTarget isn't synchronous and isn't 
atomic; it will always
take at least two event loop to complete.
It was possible when the new seek came, that the previous waitForTarget promise 
had been resolved
and was already in-flight. Once received by the 
MediaPlayerPrivateMediaSourceAVFObjC
it would then seek the AudioVideoRenderer and then enqueue new frames on the 
SourceBuffer's workqueue.
The 2nd call to MediaSourcePrivate::waitForTarget would then resolve, and also 
start
seeking the renderer and once again flush the renderer; all while the 
SourceBuffer is in the
process on enqueueing new samples.

We properly cancel the MediaSourcePrivate::waitForTarget current operation by 
using
a NativePromiseRequest to track the completion, and disconnect is as needed.

2- The flush operation was started on the main thread while the samples 
re-enqueueing was occurring
on the SourceBuffer, the tasks dispatched to flush the renderer and re-enqueue 
the content could run
out of order.

We restructure the seek operations and 
MediaPlayerPrivateMediaSourceAVFObjC::startSeek() was restructured
to not require the inner promise resolver to call back into startSeek() again.
AudioVideoRenderer prepareToSeek(MediaTime) , now takes the seek time and
return a MediaTimePromise.
If no seeking is required by the AudioVideoRenderer's synchronizer, then the 
promise
is resolved with the current time value to indicate the caller can short 
circuit and finish the seek early.
Otherwise the promise is resolved with MediaTime::isIndefinite() which 
indicates that samples need
to be re-enqueued following a flush on their respective tracks.

The AudioVideoRenderer no longer needs to be fully flushed; instead all current 
tracks
much be individually flushed for the seek operation to continue.

The new flow is more asynchronous and parallelise two tasks:
 - m_mediaSourcePrivate)->reenqueueMediaForTime(seekTime),
 - m_renderer->finishSeek(seekTime)
so that the renderer can start waiting for the first sample decoding to 
complete before all frames have been enqueued.

It also allows the seek to be more easily interrupted and another seek started.

We now track the seek state from within AudioVideoRendereRemote as 
AudioVideoRendererRemote::seeking() could
have returned a stale value. It also allows to better assert that the API usage 
of seeking with the AudioVideoRenderer
is correct.

Fly-By: the m_rendererSeekRequest wasn't always disconnected/completed should 
an error occur
(such as the GPU process crashing), which would have caused an assertion on 
debug build.

We add some assertions and logging to more easily detect should the first frame
received after a flush not be a keyframe.

Added test.

* LayoutTests/ipc/serialized-type-info.html:
* 
LayoutTests/media/media-source/media-source-seek-during-pending-seek-expected.txt:
 Added.
* LayoutTests/media/media-source/media-source-seek-during-pending-seek.html: 
Added.
* Source/WTF/wtf/NativePromise.h:
(WTF::GenericPromiseConverter::convertError): Add converter to send a 
GenericPromise over IPC.
* Source/WebCore/platform/PlatformMediaError.cpp:
(WebCore::convertEnumerationToString):
* Source/WebCore/platform/PlatformMediaError.h:
* Source/WebCore/platform/graphics/AudioVideoRenderer.h:
(WebCore::SynchronizerInterface::prepareToSeek): Deleted.
* Source/WebCore/platform/graphics/MediaSourcePrivate.cpp:
(WebCore::MediaSourcePrivate::waitForTarget):
(WebCore::MediaSourcePrivate::reenqueueMediaForTime):
(WebCore::MediaSourcePrivate::seekToTime): Deleted.
* Source/WebCore/platform/graphics/MediaSourcePrivate.h:
* Source/WebCore/platform/graphics/SourceBufferPrivate.cpp:
(WebCore::SourceBufferPrivate::reenqueueMediaForTime):
(WebCore::SourceBufferPrivate::isReenqueuePending const):
(WebCore::SourceBufferPrivate::provideMediaData):
(WebCore::SourceBufferPrivate::attach):
(WebCore::SourceBufferPrivate::seekToTime): Deleted.
* Source/WebCore/platform/graphics/SourceBufferPrivate.h:
(WebCore::SourceBufferPrivate::timeFudgeFactor const):
(WebCore::SourceBufferPrivate::isSeeking const): Deleted.
* Source/WebCore/platform/graphics/avfoundation/AudioVideoRendererAVFObjC.h:
* Source/WebCore/platform/graphics/avfoundation/AudioVideoRendererAVFObjC.mm:
(WebCore::AudioVideoRendererAVFObjC::enqueueSample):
(WebCore::AudioVideoRendererAVFObjC::isReadyForMoreSamples):
(WebCore::AudioVideoRendererAVFObjC::requestMediaDataWhenReady):
(WebCore::AudioVideoRendererAVFObjC::flush):
(WebCore::AudioVideoRendererAVFObjC::flushTrack):
(WebCore::AudioVideoRendererAVFObjC::setTimeObserver):
(WebCore::AudioVideoRendererAVFObjC::prepareToSeek):
(WebCore::AudioVideoRendererAVFObjC::finishSeek):
(WebCore::AudioVideoRendererAVFObjC::maybeCompleteSeek):
(WebCore::AudioVideoRendererAVFObjC::flushVideo):
(WebCore::AudioVideoRendererAVFObjC::flushAudio):
(WebCore::AudioVideoRendererAVFObjC::flushAudioTrack):
(WebCore::AudioVideoRendererAVFObjC::cancelSeekingPromiseIfNeeded):
(WebCore::AudioVideoRendererAVFObjC::toString const):
(WebCore::AudioVideoRendererAVFObjC::seekTo): Deleted.
* 
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
* 
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::MediaPlayerPrivateMediaSourceAVFObjC):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::~MediaPlayerPrivateMediaSourceAVFObjC):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekInternal):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::continueSeek):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::reenqueueMediaForTimeAndFinishSeek):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::cancelPendingSeek):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::startSeek):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::flush): Deleted.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::reenqueueMediaForTime): Deleted.
* Source/WebCore/platform/graphics/cocoa/MediaPlayerPrivateWebM.h:
* Source/WebCore/platform/graphics/cocoa/MediaPlayerPrivateWebM.mm:
(WebCore::MediaPlayerPrivateWebM::seekInternal):
(WebCore::MediaPlayerPrivateWebM::reenqueueMediaForTime):
(WebCore::MediaPlayerPrivateWebM::startSeek): Deleted.
* 
Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
(WebCore::MediaPlayerPrivateGStreamerMSE::doSeek):
* 
Source/WebCore/platform/graphics/gstreamer/mse/MediaSourcePrivateGStreamer.cpp:
(WebCore::MediaSourcePrivateGStreamer::willSeek): Deleted.
* Source/WebCore/platform/graphics/gstreamer/mse/MediaSourcePrivateGStreamer.h:
* 
Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.cpp:
(WebCore::SourceBufferPrivateGStreamer::willSeek): Deleted.
(WebCore::SourceBufferPrivateGStreamer::isSeeking const): Deleted.
(WebCore::SourceBufferPrivateGStreamer::seekToTime): Deleted.
* Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.h:
* Source/WebCore/platform/mock/mediasource/MockMediaPlayerMediaSource.cpp:
(WebCore::MockMediaPlayerMediaSource::seekToTarget):
* Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.cpp:
(WebKit::RemoteAudioVideoRendererProxyManager::prepareToSeek):
(WebKit::RemoteAudioVideoRendererProxyManager::finishSeek):
(WebKit::RemoteAudioVideoRendererProxyManager::stateFor const):
(WebKit::RemoteAudioVideoRendererProxyManager::seekTo): Deleted.
* Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.h:
* 
Source/WebKit/GPUProcess/media/RemoteAudioVideoRendererProxyManager.messages.in:
* Source/WebKit/Platform/IPC/Connection.h:
* Source/WebKit/Scripts/webkit/messages.py:
(types_that_cannot_be_forward_declared):
(headers_for_type):
* Source/WebKit/Shared/WTFArgumentCoders.serialization.in:
* Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in:
* Source/WebKit/WebProcess/GPU/media/AudioVideoRendererRemote.cpp:
(WebKit::AudioVideoRendererRemote::AudioVideoRendererRemote):
(WebKit::AudioVideoRendererRemote::cancelPendingSeek):
(WebKit::AudioVideoRendererRemote::prepareToSeek):
(WebKit::AudioVideoRendererRemote::finishSeek):
(WebKit::AudioVideoRendererRemote::seeking const):
(WebKit::AudioVideoRendererRemote::enqueueSample):
(WebKit::AudioVideoRendererRemote::flush):
(WebKit::AudioVideoRendererRemote::~AudioVideoRendererRemote): Deleted.
(WebKit::AudioVideoRendererRemote::seekTo): Deleted.
* Source/WebKit/WebProcess/GPU/media/AudioVideoRendererRemote.h:
* Source/WebKit/WebProcess/GPU/media/RemoteAudioVideoRendererState.h:
* 
Source/WebKit/WebProcess/GPU/media/RemoteAudioVideoRendererState.serialization.in:
* Source/WebKit/WebProcess/GPU/media/SourceBufferPrivateRemote.cpp:
(WebKit::SourceBufferPrivateRemote::reenqueueMediaForTime):
(WebKit::SourceBufferPrivateRemote::seekToTime): Deleted.
* Source/WebKit/WebProcess/GPU/media/SourceBufferPrivateRemote.h:

Canonical link: https://commits.webkit.org/310415@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to