Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 9a1b47f8701b3a06fa4fbe3bf7a43881fa5cfabe
      
https://github.com/WebKit/WebKit/commit/9a1b47f8701b3a06fa4fbe3bf7a43881fa5cfabe
  Author: Jean-Yves Avenard <[email protected]>
  Date:   2026-06-15 (Mon, 15 Jun 2026)

  Changed paths:
    M Source/WebCore/Modules/mediasource/MediaSource.cpp
    M Source/WebCore/Modules/mediasource/SourceBuffer.cpp
    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/objc/MediaSourcePrivateAVFObjC.h
    M 
Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm
    M Source/WebKit/WebProcess/GPU/media/MediaSourcePrivateRemote.cpp
    M Source/WebKit/WebProcess/GPU/media/MediaSourcePrivateRemote.h

  Log Message:
  -----------
  [MSE] 
imported/w3c/web-platform-tests/media-source/mediasource-getvideoplaybackquality.html
 is an intermittent timeout
https://bugs.webkit.org/show_bug.cgi?id=316898
rdar://179339247

Reviewed by Jer Noble.

MediaSourcePrivate::m_buffered was written by two independent paths running on
different threads, each implementing a different algorithm. JS-visible
mediaSource.buffered could end up with whichever value the loser of the race
published.

Path A — MediaSource::updateBufferedIfNeeded() — runs on the script execution
context (main thread). It is triggered when a SourceBuffer raises its
m_bufferedDirty flag (after track-buffer data changes propagated via
SourceBuffer::sourceBufferPrivateBufferedChanged), when MediaSource's readyState
transitions Open <-> Ended, and when the duration changes. It iterates the
active SourceBuffer set and runs the W3C MSE 10.2 HTMLMediaElement.buffered
algorithm: highest-end-time seed, ended-alignment per active SourceBuffer, then
cross-buffer intersection.

Path B — MediaSourcePrivate::updateBufferedRanges() — runs on
MediaSourcePrivate::m_dispatcher. It is triggered from
SourceBufferPrivate::updateBuffered() each time per-track ranges change. The
existing implementation simply intersected every entry in m_bufferedRanges
without distinguishing active from inactive SourceBuffers and without applying
the readyState-driven ended-alignment.

Both paths wrote m_buffered through MediaSourcePrivate::bufferedChanged() under
m_lock. There is no ordering between the two threads, so when track-buffer
changes arrived close to a readyState transition or to a setBufferedDirty
trigger, Path B could fire after Path A and overwrite the correct value with
the un-aligned, inactive sourceBuffer included intersection.

Fix: extract the two spec algorithms into static helpers shared by both paths.
SourceBufferPrivate::computeBufferedRanges implements MSE 5.1 
SourceBuffer.buffered
and is used by SourceBuffer::updateBuffered and (indirectly) by the
MediaSourcePrivate dispatcher path when building per-SourceBuffer aggregates.
MediaSourcePrivate::computeBufferedRanges implements MSE 10.2 cross-buffer
intersection and is used by both MediaSource::updateBufferedIfNeeded (main) and
MediaSourcePrivate::updateBufferedRanges (dispatcher). Same algorithm + same
inputs => same value, so the remaining write race is benign.

Covered by existing tests.

* Source/WebCore/Modules/mediasource/MediaSource.cpp:
(WebCore::MediaSource::updateBufferedIfNeeded): Replace the inlined algorithm
with calls to the new MediaSourcePrivate::computeBufferedRanges helper, and use
MediaSourcePrivate::isBufferedEqual to skip notification when unchanged without
copying m_buffered out.

* Source/WebCore/Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::updateBuffered): Replace the inlined algorithm with a
call to SourceBufferPrivate::computeBufferedRanges.

* Source/WebCore/platform/graphics/SourceBufferPrivate.h:
* Source/WebCore/platform/graphics/SourceBufferPrivate.cpp:
(WebCore::SourceBufferPrivate::computeBufferedRanges): New static helper
implementing MSE 5.1 SourceBuffer.buffered.

* Source/WebCore/platform/graphics/MediaSourcePrivate.h:
* Source/WebCore/platform/graphics/MediaSourcePrivate.cpp:
(WebCore::MediaSourcePrivate::computeBufferedRanges): New static helper
implementing MSE 10.2 HTMLMediaElement.buffered cross-buffer step.
(WebCore::MediaSourcePrivate::isBufferedEqual): New short-circuit comparison
helper that compares against m_buffered under m_lock without returning a copy.
(WebCore::MediaSourcePrivate::updateBufferedRanges): Build per-SourceBuffer
aggregates via SourceBufferPrivate::computeBufferedRanges, then call
MediaSourcePrivate::computeBufferedRanges for the cross-buffer step. Skip
notification when isBufferedEqual.
(WebCore::MediaSourcePrivate::bufferedChanged): Take Vector by rvalue so
m_buffered is move-assigned.

* 
Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
(WebCore::MediaSourcePrivateAVFObjC::bufferedChanged): Forward the rvalue to
the base via WTF::move.

* Source/WebKit/WebProcess/GPU/media/MediaSourcePrivateRemote.cpp:
(WebKit::MediaSourcePrivateRemote::bufferedChanged): Take Vector by rvalue,
copy once for the IPC capture, move into the base.

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



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

Reply via email to