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();