mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-19 08:37:54 +01:00
PipeWire capturer: copy content from PW buffer directly to DesktopFrame
This avoids an additional step where we originally copied content from PipeWire buffer to a temporary location and from there to DesktopFrame. This results into less copy operations and hopefully to faster screensharing. I didn't do some exact measures, but simply running htop while sharing a 4k screen I can see following results (usage per top 5 processes): 1) Without this change - 66%, 64%, 26% 23%, 10% 2) With this change - 41%, 39%, 19%, 17%, 12%, Bug: webrtc:13239 Change-Id: I6a661ecc96bfeef370c1a5a3b9dc5e3c0fc665c8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231684 Reviewed-by: Tommi <tommi@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Tommi <tommi@webrtc.org> Cr-Commit-Position: refs/heads/main@{#35156}
This commit is contained in:
parent
6d19d14c26
commit
3695640504
3 changed files with 31 additions and 57 deletions
|
@ -537,8 +537,6 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<void()> cleanup;
|
|
||||||
const int32_t src_stride = spa_buffer->datas[0].chunk->stride;
|
|
||||||
if (spa_buffer->datas[0].type == SPA_DATA_MemFd) {
|
if (spa_buffer->datas[0].type == SPA_DATA_MemFd) {
|
||||||
map.initialize(
|
map.initialize(
|
||||||
static_cast<uint8_t*>(
|
static_cast<uint8_t*>(
|
||||||
|
@ -608,7 +606,6 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
|
||||||
video_metadata_use = true;
|
video_metadata_use = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopSize video_size_prev = video_size_;
|
|
||||||
if (video_metadata_use) {
|
if (video_metadata_use) {
|
||||||
video_size_ =
|
video_size_ =
|
||||||
DesktopSize(video_metadata_size->width, video_metadata_size->height);
|
DesktopSize(video_metadata_size->width, video_metadata_size->height);
|
||||||
|
@ -616,54 +613,41 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
|
||||||
video_size_ = desktop_size_;
|
video_size_ = desktop_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t y_offset = video_metadata_use && (video_metadata->region.position.y +
|
||||||
|
video_size_.height() <=
|
||||||
|
desktop_size_.height())
|
||||||
|
? video_metadata->region.position.y
|
||||||
|
: 0;
|
||||||
|
uint32_t x_offset = video_metadata_use && (video_metadata->region.position.x +
|
||||||
|
video_size_.width() <=
|
||||||
|
desktop_size_.width())
|
||||||
|
? video_metadata->region.position.x
|
||||||
|
: 0;
|
||||||
|
|
||||||
webrtc::MutexLock lock(¤t_frame_lock_);
|
webrtc::MutexLock lock(¤t_frame_lock_);
|
||||||
if (!current_frame_ || !video_size_.equals(video_size_prev)) {
|
|
||||||
current_frame_ = std::make_unique<uint8_t[]>(
|
|
||||||
video_size_.width() * video_size_.height() * kBytesPerPixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t dst_stride = video_size_.width() * kBytesPerPixel;
|
uint8_t* updated_src = src + (spa_buffer->datas[0].chunk->stride * y_offset) +
|
||||||
|
(kBytesPerPixel * x_offset);
|
||||||
|
current_frame_ = std::make_unique<BasicDesktopFrame>(
|
||||||
|
DesktopSize(video_size_.width(), video_size_.height()));
|
||||||
|
current_frame_->CopyPixelsFrom(
|
||||||
|
updated_src,
|
||||||
|
(spa_buffer->datas[0].chunk->stride - (kBytesPerPixel * x_offset)),
|
||||||
|
DesktopRect::MakeWH(video_size_.width(), video_size_.height()));
|
||||||
|
|
||||||
if (src_stride != (desktop_size_.width() * kBytesPerPixel)) {
|
if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx ||
|
||||||
RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
|
spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) {
|
||||||
<< src_stride
|
uint8_t* tmp_src = current_frame_->data();
|
||||||
<< " != " << (desktop_size_.width() * kBytesPerPixel);
|
for (int i = 0; i < video_size_.height(); ++i) {
|
||||||
portal_init_failed_ = true;
|
// If both sides decided to go with the RGBx format we need to convert it
|
||||||
|
// to BGRx to match color format expected by WebRTC.
|
||||||
return;
|
ConvertRGBxToBGRx(tmp_src, current_frame_->stride());
|
||||||
}
|
tmp_src += current_frame_->stride();
|
||||||
|
|
||||||
// Adjust source content based on metadata video position
|
|
||||||
if (video_metadata_use &&
|
|
||||||
(video_metadata->region.position.y + video_size_.height() <=
|
|
||||||
desktop_size_.height())) {
|
|
||||||
src += src_stride * video_metadata->region.position.y;
|
|
||||||
}
|
|
||||||
const int x_offset =
|
|
||||||
video_metadata_use &&
|
|
||||||
(video_metadata->region.position.x + video_size_.width() <=
|
|
||||||
desktop_size_.width())
|
|
||||||
? video_metadata->region.position.x * kBytesPerPixel
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
uint8_t* dst = current_frame_.get();
|
|
||||||
for (int i = 0; i < video_size_.height(); ++i) {
|
|
||||||
// Adjust source content based on crop video position if needed
|
|
||||||
src += x_offset;
|
|
||||||
std::memcpy(dst, src, dst_stride);
|
|
||||||
// If both sides decided to go with the RGBx format we need to convert it to
|
|
||||||
// BGRx to match color format expected by WebRTC.
|
|
||||||
if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx ||
|
|
||||||
spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) {
|
|
||||||
ConvertRGBxToBGRx(dst, dst_stride);
|
|
||||||
}
|
}
|
||||||
src += src_stride - x_offset;
|
|
||||||
dst += dst_stride;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseCapturerPipeWire::ConvertRGBxToBGRx(uint8_t* frame, uint32_t size) {
|
void BaseCapturerPipeWire::ConvertRGBxToBGRx(uint8_t* frame, uint32_t size) {
|
||||||
// Change color format for KDE KWin which uses RGBx and not BGRx
|
|
||||||
for (uint32_t i = 0; i < size; i += 4) {
|
for (uint32_t i = 0; i < size; i += 4) {
|
||||||
uint8_t tempR = frame[i];
|
uint8_t tempR = frame[i];
|
||||||
uint8_t tempB = frame[i + 2];
|
uint8_t tempB = frame[i + 2];
|
||||||
|
@ -1103,18 +1087,7 @@ void BaseCapturerPipeWire::CaptureFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
webrtc::MutexLock lock(¤t_frame_lock_);
|
webrtc::MutexLock lock(¤t_frame_lock_);
|
||||||
if (!current_frame_) {
|
if (!current_frame_ || !current_frame_->data()) {
|
||||||
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DesktopSize frame_size = video_size_;
|
|
||||||
|
|
||||||
std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size));
|
|
||||||
result->CopyPixelsFrom(
|
|
||||||
current_frame_.get(), (frame_size.width() * kBytesPerPixel),
|
|
||||||
DesktopRect::MakeWH(frame_size.width(), frame_size.height()));
|
|
||||||
if (!result) {
|
|
||||||
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1122,7 +1095,7 @@ void BaseCapturerPipeWire::CaptureFrame() {
|
||||||
// TODO(julien.isorce): http://crbug.com/945468. Set the icc profile on the
|
// TODO(julien.isorce): http://crbug.com/945468. Set the icc profile on the
|
||||||
// frame, see ScreenCapturerX11::CaptureFrame.
|
// frame, see ScreenCapturerX11::CaptureFrame.
|
||||||
|
|
||||||
callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(current_frame_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) {
|
bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) {
|
||||||
|
|
|
@ -95,7 +95,7 @@ class BaseCapturerPipeWire : public DesktopCapturer {
|
||||||
DesktopCaptureOptions options_ = {};
|
DesktopCaptureOptions options_ = {};
|
||||||
|
|
||||||
webrtc::Mutex current_frame_lock_;
|
webrtc::Mutex current_frame_lock_;
|
||||||
std::unique_ptr<uint8_t[]> current_frame_;
|
std::unique_ptr<BasicDesktopFrame> current_frame_;
|
||||||
Callback* callback_ = nullptr;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
bool portal_init_failed_ = false;
|
bool portal_init_failed_ = false;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
#include "rtc_base/sanitizer.h"
|
#include "rtc_base/sanitizer.h"
|
||||||
|
|
Loading…
Reference in a new issue