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 <alcooper@chromium.org>
Commit-Queue: Jan Grulich <grulja@gmail.com>
Cr-Commit-Position: refs/heads/main@{#38449}
This commit is contained in:
Jan Grulich
2022-10-20 17:03:13 +02:00
committed by WebRTC LUCI CQ
parent 640e92684a
commit f5db32f02a
4 changed files with 65 additions and 7 deletions

View File

@ -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

View File

@ -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() {

View File

@ -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*>(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<SharedDesktopFrame>{};
}
return queue_.current_frame()->Share();
std::unique_ptr<SharedDesktopFrame> frame = queue_.current_frame()->Share();
if (use_damage_region_) {
frame->mutable_updated_region()->Swap(&damage_region_);
damage_region_.Clear();
}
return frame;
}
std::unique_ptr<MouseCursor> 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<struct spa_meta*>(
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);

View File

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