From 617daa5e3ad58c3503c07e1f2307a90c9c335711 Mon Sep 17 00:00:00 2001 From: Ganesh prasad Sahu Date: Mon, 15 Jun 2026 05:49:04 +0000 Subject: [PATCH] =?UTF-8?q?=20=20=20=20Queue=20frames=20till=20Video=20Fra?= =?UTF-8?q?me=20Observer=20is=20ready=20=20=20=20=20https://bugs.webkit.or?= =?UTF-8?q?g/show=5Fbug.cgi=3Fid=3D317111=20=20=20=20=20Reviewed=20by:=20E?= =?UTF-8?q?.=20Oca=C3=B1a=20Gonz=C3=A1lez?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem : WebRTC playback doesnot recover from a black screen and the issue is seen Intermittently Cause: The first video frame(s) (containing SPS/PPS/IDR) being dropped because libwebrtc starts delivering decoded frames before the downstream GStreamer pipeline's InternalSource registers as a VideoFrameObserver. Without first having the SPS/PPS and the first sync frame , the decoder can not decode any subsequent delta frames. In Following code snippet from mediastream/gstreamer/GStreamerMediaStreamSource.cpp, frames received while m_isObserving is false might be dropped. void videoFrameAvailable(VideoFrame& videoFrame, VideoFrameTimeMetadata) final { if (!m_parent || !m_isObserving) return; updateFirstVideoSampleSeenFlag(); Change : While this patch doesnot address the root cause of delayed start of VideoFrameObserver, add a small frame buffer to hold frames (currently max size set to 30 frames) that arrive before any observer registers. deliver the frames when observer is registered Note: From tests it is observed that only the first frame or 2 is actually needed to be queued. * Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp: (RealtimeMediaSource::videoFrameAvailable) : Queue frames till observer is ready * Source/WebCore/platform/mediastream/RealtimeMediaSource.h: (struct PendingVideoFrame) : Added a buffer to hold the frames --- .../mediastream/RealtimeMediaSource.cpp | 20 +++++++++++++++++++ .../mediastream/RealtimeMediaSource.h | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp index f894fef450c68..c3b89e455d2cb 100644 --- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp @@ -338,6 +338,26 @@ void RealtimeMediaSource::videoFrameAvailable(VideoFrame& videoFrame, VideoFrame updateHasStartedProducingData(); Locker locker { m_videoFrameObserversLock }; + if (m_videoFrameObservers.isEmpty()) { + if (m_pendingVideoFrames.size() < maxPendingVideoFramesBeforeAddTrack) { + m_pendingVideoFrames.append(PendingVideoFrame { &videoFrame, metadata }); + } + else { + WTFLogAlways("RealtimeMediaSource: Dropping video frame (queue is full) %zu frames", m_pendingVideoFrames.size()); + } + return; + } + if (!m_pendingVideoFrames.isEmpty()) { + WTFLogAlways("RealtimeMediaSource: Delivering %zu queued frame(s) (pipeline ready)", m_pendingVideoFrames.size()); + for (auto& pending : m_pendingVideoFrames) { + if (pending.frame) { + for (auto* obs : m_videoFrameObservers) + obs->videoFrameAvailable(*pending.frame, pending.metadata); + } + } + m_pendingVideoFrames.clear(); + } + for (auto& [key, value] : m_videoFrameObservers) { if (auto* adaptor = value.get()) { if (adaptor->frameDecimation > 1 && ++adaptor->frameDecimationCounter % adaptor->frameDecimation) diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h index d5fbb8b487a07..be1fb0416602d 100644 --- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h @@ -391,6 +391,13 @@ class WEBCORE_EXPORT RealtimeMediaSource mutable Lock m_videoFrameObserversLock; HashMap> m_videoFrameObservers WTF_GUARDED_BY_LOCK(m_videoFrameObserversLock); + struct PendingVideoFrame { + RefPtr frame; + VideoFrameTimeMetadata metadata; + }; + static constexpr size_t maxPendingVideoFramesBeforeAddTrack = 30; + Vector m_pendingVideoFrames WTF_GUARDED_BY_LOCK(m_videoFrameObserversLock); + CaptureDevice m_device; // Set on the main thread from constraints.