From f5db32f02a4d4787e746a7d611f3637c55e6d627 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Thu, 20 Oct 2022 17:03:13 +0200 Subject: [PATCH] Wayland screencast: use damage regions metadata from PW buffers We already communicated SPA_META_VideoDamage before, but we never used these metadata. This change checks whether SPA_META_VideoDamage metadata are available and construct a damage rect combined from all sent damage regions. Bug: webrtc:13429 Change-Id: I326109b4bacf51855904e53345c671640d670323 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/278820 Reviewed-by: Alexander Cooper Commit-Queue: Jan Grulich Cr-Commit-Position: refs/heads/main@{#38449} --- .../desktop_capture/desktop_capture_options.h | 8 +++ .../linux/wayland/base_capturer_pipewire.cc | 2 + .../linux/wayland/shared_screencast_stream.cc | 61 ++++++++++++++++--- .../linux/wayland/shared_screencast_stream.h | 1 + 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h index 4ee5259bb4..0364517405 100644 --- a/modules/desktop_capture/desktop_capture_options.h +++ b/modules/desktop_capture/desktop_capture_options.h @@ -194,6 +194,13 @@ class RTC_EXPORT DesktopCaptureOptions { void set_height(uint32_t height) { height_ = height; } uint32_t get_height() const { return height_; } + + void set_pipewire_use_damage_region(bool use_damage_regions) { + pipewire_use_damage_region_ = use_damage_regions; + } + bool pipewire_use_damage_region() const { + return pipewire_use_damage_region_; + } #endif private: @@ -232,6 +239,7 @@ class RTC_EXPORT DesktopCaptureOptions { bool detect_updated_region_ = false; #if defined(WEBRTC_USE_PIPEWIRE) bool allow_pipewire_ = false; + bool pipewire_use_damage_region_ = true; uint32_t width_ = 0; uint32_t height_ = 0; #endif diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index 2a63fc7a3c..3d006c5f6c 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -42,6 +42,8 @@ BaseCapturerPipeWire::BaseCapturerPipeWire( is_screencast_portal_(false), portal_(std::move(portal)) { source_id_ = RestoreTokenManager::GetInstance().GetUnusedId(); + options_.screencast_stream()->SetUseDamageRegion( + options_.pipewire_use_damage_region()); } BaseCapturerPipeWire::~BaseCapturerPipeWire() { diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc index aacf68ef99..a8704805af 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc @@ -36,6 +36,7 @@ using modules_desktop_capture_linux_wayland::StubPathMap; namespace webrtc { const int kBytesPerPixel = 4; +const int kVideoDamageRegionCount = 16; #if defined(WEBRTC_DLOPEN_PIPEWIRE) const char kPipeWireLib[] = "libpipewire-0.3.so.0"; @@ -88,6 +89,9 @@ class SharedScreenCastStreamPrivate { uint32_t width = 0, uint32_t height = 0); void UpdateScreenCastStreamResolution(uint32_t width, uint32_t height); + void SetUseDamageRegion(bool use_damage_region) { + use_damage_region_ = use_damage_region; + } void SetObserver(SharedScreenCastStream::Observer* observer) { observer_ = observer; } @@ -101,6 +105,11 @@ class SharedScreenCastStreamPrivate { void StopAndCleanupStream(); SharedScreenCastStream::Observer* observer_ = nullptr; + + // Track damage region updates that were reported since the last time + // frame was captured + DesktopRegion damage_region_; + uint32_t pw_stream_node_id_ = 0; DesktopSize stream_size_ = {}; @@ -142,6 +151,8 @@ class SharedScreenCastStreamPrivate { // Resolution changes are processed during buffer processing. bool pending_resolution_change_ RTC_GUARDED_BY(&resolution_lock_) = false; + bool use_damage_region_ = true; + // event handlers pw_core_events pw_core_events_ = {}; pw_stream_events pw_stream_events_ = {}; @@ -294,9 +305,10 @@ void SharedScreenCastStreamPrivate::OnStreamParamChanged( params.push_back(reinterpret_cast(spa_pod_builder_add_object( &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoDamage), SPA_PARAM_META_size, - SPA_POD_CHOICE_RANGE_Int(sizeof(struct spa_meta_region) * 16, - sizeof(struct spa_meta_region) * 1, - sizeof(struct spa_meta_region) * 16)))); + SPA_POD_CHOICE_RANGE_Int( + sizeof(struct spa_meta_region) * kVideoDamageRegionCount, + sizeof(struct spa_meta_region) * 1, + sizeof(struct spa_meta_region) * kVideoDamageRegionCount)))); pw_stream_update_params(that->pw_stream_, params.data(), params.size()); } @@ -585,7 +597,13 @@ SharedScreenCastStreamPrivate::CaptureFrame() { return std::unique_ptr{}; } - return queue_.current_frame()->Share(); + std::unique_ptr frame = queue_.current_frame()->Share(); + if (use_damage_region_) { + frame->mutable_updated_region()->Swap(&damage_region_); + damage_region_.Clear(); + } + + return frame; } std::unique_ptr SharedScreenCastStreamPrivate::CaptureCursor() { @@ -844,13 +862,38 @@ void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) { } } - queue_.current_frame()->mutable_updated_region()->SetRect( - DesktopRect::MakeSize(queue_.current_frame()->size())); - // For testing purpose if (observer_) { observer_->OnDesktopFrameChanged(); } + + if (use_damage_region_) { + const struct spa_meta* video_damage = static_cast( + spa_buffer_find_meta(spa_buffer, SPA_META_VideoDamage)); + if (video_damage) { + spa_meta_region* meta_region; + + queue_.current_frame()->mutable_updated_region()->Clear(); + + spa_meta_for_each(meta_region, video_damage) { + // Skip empty regions + if (meta_region->region.size.width == 0 || + meta_region->region.size.height == 0) { + continue; + } + + damage_region_.AddRect(DesktopRect::MakeXYWH( + meta_region->region.position.x, meta_region->region.position.y, + meta_region->region.size.width, meta_region->region.size.height)); + } + } else { + damage_region_.SetRect( + DesktopRect::MakeSize(queue_.current_frame()->size())); + } + } else { + queue_.current_frame()->mutable_updated_region()->SetRect( + DesktopRect::MakeSize(queue_.current_frame()->size())); + } } void SharedScreenCastStreamPrivate::ConvertRGBxToBGRx(uint8_t* frame, @@ -891,6 +934,10 @@ void SharedScreenCastStream::UpdateScreenCastStreamResolution(uint32_t width, private_->UpdateScreenCastStreamResolution(width, height); } +void SharedScreenCastStream::SetUseDamageRegion(bool use_damage_region) { + private_->SetUseDamageRegion(use_damage_region); +} + void SharedScreenCastStream::SetObserver( SharedScreenCastStream::Observer* observer) { private_->SetObserver(observer); diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h index c58d8402ac..f18c889810 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h @@ -48,6 +48,7 @@ class RTC_EXPORT SharedScreenCastStream uint32_t width = 0, uint32_t height = 0); void UpdateScreenCastStreamResolution(uint32_t width, uint32_t height); + void SetUseDamageRegion(bool use_damage_region); void SetObserver(SharedScreenCastStream::Observer* observer); void StopScreenCastStream();