From 848980198ebdc7fd9257ff64faace33eada44798 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Tue, 14 May 2024 09:25:39 +0200 Subject: [PATCH] Video capture PipeWire: always capture latest processed buffer Both CaptureFrame() and ProcessBuffer() hold a lock over the frame queue and it happens that one waits for the other, causing unnecessary delays since we already work with a queue having two frames, but this way we don't really need a queue. Instead, keep reference to the last processed buffer, which we will always use in CaptureFrame() and update it every time at the end of ProcessBuffer(). This avoid unnecessary waiting for the lock over the queue to be released. Bug: chromium:333945842 Change-Id: I4afeb1daacd342e92578a50ac6e1c89a691bb8f8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/350042 Commit-Queue: Jan Grulich Reviewed-by: Alexander Cooper Reviewed-by: Mark Foltz Cr-Commit-Position: refs/heads/main@{#42394} --- .../linux/wayland/shared_screencast_stream.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc index 4e042ef79e..15f9b1e55f 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc @@ -83,6 +83,9 @@ class SharedScreenCastStreamPrivate { webrtc::Mutex queue_lock_; ScreenCaptureFrameQueue queue_ RTC_GUARDED_BY(&queue_lock_); + webrtc::Mutex latest_frame_lock_; + SharedDesktopFrame* latest_available_frame_ + RTC_GUARDED_BY(&latest_frame_lock_) = nullptr; std::unique_ptr mouse_cursor_; DesktopVector mouse_cursor_position_ = DesktopVector(-1, -1); @@ -603,13 +606,13 @@ void SharedScreenCastStreamPrivate::StopAndCleanupStream() { std::unique_ptr SharedScreenCastStreamPrivate::CaptureFrame() { - webrtc::MutexLock lock(&queue_lock_); + webrtc::MutexLock latest_frame_lock(&latest_frame_lock_); - if (!pw_stream_ || !queue_.current_frame()) { + if (!pw_stream_ || !latest_available_frame_) { return std::unique_ptr{}; } - std::unique_ptr frame = queue_.current_frame()->Share(); + std::unique_ptr frame = latest_available_frame_->Share(); if (use_damage_region_) { frame->mutable_updated_region()->Swap(&damage_region_); damage_region_.Clear(); @@ -842,6 +845,8 @@ void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) { if (observer_) { observer_->OnFailedToProcessBuffer(); } + webrtc::MutexLock latest_frame_lock(&latest_frame_lock_); + latest_available_frame_ = nullptr; return; } @@ -860,9 +865,16 @@ void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) { observer_->OnDesktopFrameChanged(); } + // We have to hold the lock over the latest_frame here already, since + // we are going to update damage region, which corresponds to the latest + // frame and is accessed in CaptureFrame() + webrtc::MutexLock latest_frame_lock(&latest_frame_lock_); + UpdateFrameUpdatedRegions(spa_buffer, *queue_.current_frame()); queue_.current_frame()->set_may_contain_cursor(is_cursor_embedded_); + latest_available_frame_ = queue_.current_frame(); + if (callback_) { std::unique_ptr frame = queue_.current_frame()->Share(); frame->set_capturer_id(DesktopCapturerId::kWaylandCapturerLinux);