From 49e0e77e40beeb318893efb434c853d813062a4b Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 7 Feb 2022 13:10:15 +0100 Subject: [PATCH] PipeWire capturer: make use of ScreenCaptureFrameQueue This allows us to keep always some frame around so we can return it everytime consumer asks us to capture a frame as before we either returned current frame or nothing as there was no new frame available. This will be needed in order to support mouse cursor separately as DesktopAndCursorComposer requires frame everytime, even if it's the same one as before so we can combine it with the mouse cursor. Bug: webrtc:13429 Change-Id: Ice87968846870c0a880ab469d9e052b4978e658c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/239362 Reviewed-by: Mark Foltz Commit-Queue: Mark Foltz Cr-Commit-Position: refs/heads/main@{#35956} --- .../linux/wayland/base_capturer_pipewire.cc | 2 +- .../linux/wayland/shared_screencast_stream.cc | 55 +++++++++++++------ .../linux/wayland/shared_screencast_stream.h | 2 +- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index 04cc1aad33..c4ec92f919 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -59,7 +59,7 @@ void BaseCapturerPipeWire::CaptureFrame() { return; } - std::unique_ptr frame = + std::unique_ptr frame = options_.screencast_stream()->CaptureFrame(); if (!frame || !frame->data()) { diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc index 5d96ab58c0..025573d122 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc @@ -23,7 +23,9 @@ #include #include +#include "absl/memory/memory.h" #include "modules/desktop_capture/linux/wayland/egl_dmabuf.h" +#include "modules/desktop_capture/screen_capture_frame_queue.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/sanitizer.h" @@ -172,7 +174,7 @@ class SharedScreenCastStreamPrivate { bool StartScreenCastStream(uint32_t stream_node_id, int fd); void StopScreenCastStream(); - std::unique_ptr CaptureFrame(); + std::unique_ptr CaptureFrame(); private: uint32_t pw_stream_node_id_ = 0; @@ -181,8 +183,9 @@ class SharedScreenCastStreamPrivate { DesktopSize desktop_size_ = {}; DesktopSize video_size_; - webrtc::Mutex current_frame_lock_; - std::unique_ptr current_frame_; + webrtc::Mutex queue_lock_; + ScreenCaptureFrameQueue queue_ + RTC_GUARDED_BY(&queue_lock_); int64_t modifier_; std::unique_ptr egl_dmabuf_; @@ -541,15 +544,15 @@ void SharedScreenCastStreamPrivate::StopScreenCastStream() { } } -std::unique_ptr -SharedScreenCastStreamPrivate::CaptureFrame() { - webrtc::MutexLock lock(¤t_frame_lock_); +std::unique_ptr SharedScreenCastStreamPrivate::CaptureFrame() { + webrtc::MutexLock lock(&queue_lock_); - if (!current_frame_ || !current_frame_->data()) { - return nullptr; + if (!queue_.current_frame()) { + return std::unique_ptr{}; } - return std::move(current_frame_); + std::unique_ptr frame = queue_.current_frame()->Share(); + return std::move(frame); } void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) { @@ -653,25 +656,41 @@ void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) { ? video_metadata->region.position.x : 0; - webrtc::MutexLock lock(¤t_frame_lock_); - uint8_t* updated_src = src + (spa_buffer->datas[0].chunk->stride * y_offset) + (kBytesPerPixel * x_offset); - current_frame_ = std::make_unique( - DesktopSize(video_size_.width(), video_size_.height())); - current_frame_->CopyPixelsFrom( + + webrtc::MutexLock lock(&queue_lock_); + + // Move to the next frame if the current one is being used and shared + if (queue_.current_frame() && queue_.current_frame()->IsShared()) { + queue_.MoveToNextFrame(); + if (queue_.current_frame() && queue_.current_frame()->IsShared()) { + RTC_LOG(LS_WARNING) + << "Failed to process PipeWire buffer: no available frame"; + return; + } + } + + if (!queue_.current_frame() || + !queue_.current_frame()->size().equals(video_size_)) { + std::unique_ptr frame(new BasicDesktopFrame( + DesktopSize(video_size_.width(), video_size_.height()))); + queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(std::move(frame))); + } + + queue_.current_frame()->CopyPixelsFrom( updated_src, (spa_buffer->datas[0].chunk->stride - (kBytesPerPixel * x_offset)), DesktopRect::MakeWH(video_size_.width(), video_size_.height())); if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx || spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) { - uint8_t* tmp_src = current_frame_->data(); + uint8_t* tmp_src = queue_.current_frame()->data(); for (int i = 0; i < video_size_.height(); ++i) { // If both sides decided to go with the RGBx format we need to convert it // to BGRx to match color format expected by WebRTC. - ConvertRGBxToBGRx(tmp_src, current_frame_->stride()); - tmp_src += current_frame_->stride(); + ConvertRGBxToBGRx(tmp_src, queue_.current_frame()->stride()); + tmp_src += queue_.current_frame()->stride(); } } } @@ -706,7 +725,7 @@ void SharedScreenCastStream::StopScreenCastStream() { private_->StopScreenCastStream(); } -std::unique_ptr SharedScreenCastStream::CaptureFrame() { +std::unique_ptr SharedScreenCastStream::CaptureFrame() { return private_->CaptureFrame(); } diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h index cd87db4a3a..d7105ba7f4 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h @@ -29,7 +29,7 @@ class RTC_EXPORT SharedScreenCastStream bool StartScreenCastStream(uint32_t stream_node_id, int fd); void StopScreenCastStream(); - std::unique_ptr CaptureFrame(); + std::unique_ptr CaptureFrame(); ~SharedScreenCastStream();