Backed out 3 changesets (bug 1672987, bug 1672947, bug 1672989) for causing linux bustages. CLOSED TREE

Backed out changeset fc296ca6ed9c (bug 1672989)
Backed out changeset f41784d22570 (bug 1672947)
Backed out changeset 0117c49b1ff6 (bug 1672987)
This commit is contained in:
smolnar 2020-11-05 10:26:11 +02:00
parent c784367df9
commit a60ce46b27
11 changed files with 233 additions and 340 deletions

View File

@ -157,7 +157,12 @@ if (rtc_include_tests) {
if (is_linux) {
if (rtc_use_pipewire) {
defines = [ "WEBRTC_USE_PIPEWIRE" ]
pkg_config("pipewire") {
packages = [ "libpipewire-0.2" ]
defines = [ "WEBRTC_USE_PIPEWIRE" ]
}
pkg_config("gio") {
packages = [
"gio-2.0",
@ -326,7 +331,6 @@ rtc_static_library("desktop_capture_generic") {
}
if (use_x11 || rtc_use_pipewire) {
include_dirs = [ "/third_party/libwebrtc/third_party/pipewire" ]
sources += [
"mouse_cursor_monitor_linux.cc",
"screen_capturer_linux.cc",
@ -368,7 +372,6 @@ rtc_static_library("desktop_capture_generic") {
}
if (rtc_use_pipewire) {
include_dirs = [ "/third_party/libwebrtc/third_party/pipewire" ]
sources += [
"linux/base_capturer_pipewire.cc",
"linux/base_capturer_pipewire.h",

View File

@ -25,8 +25,7 @@ LOCAL_INCLUDES += [
"/ipc/chromium/src",
"/ipc/glue",
"/media/libyuv/libyuv/include/",
"/third_party/libwebrtc/webrtc/",
"/third_party/pipewire"
"/third_party/libwebrtc/webrtc/"
]
UNIFIED_SOURCES += [
@ -162,7 +161,6 @@ if CONFIG["OS_TARGET"] == "Linux":
DEFINES["WEBRTC_LINUX"] = True
DEFINES["WEBRTC_POSIX"] = True
DEFINES["_FILE_OFFSET_BITS"] = "64"
DEFINES["WEBRTC_USE_PIPEWIRE"] = "1"
OS_LIBS += [
"rt",
@ -195,14 +193,6 @@ if CONFIG["OS_TARGET"] == "Linux":
"/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc"
]
CXXFLAGS += CONFIG['TK_CFLAGS']
UNIFIED_SOURCES += [
"/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc",
"/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc",
"/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc"
]
if CONFIG["OS_TARGET"] == "NetBSD":
DEFINES["USE_X11"] = "1"

View File

@ -141,7 +141,7 @@ class DesktopCaptureOptions {
bool disable_effects_ = true;
bool detect_updated_region_ = false;
#if defined(WEBRTC_USE_PIPEWIRE)
bool allow_pipewire_ = true;
bool allow_pipewire_ = false;
#endif
};

View File

@ -13,11 +13,6 @@
#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer_differ_wrapper.h"
#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
#include <gtk/gtk.h>
#include <gtk/gtkx.h>
#endif
namespace webrtc {
DesktopCapturer::~DesktopCapturer() = default;
@ -77,19 +72,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateTabCapturer(
}
#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
// Return true if Firefox is actually running with Wayland backend.
static bool IsWaylandDisplayUsed() {
const auto display = gdk_display_get_default();
if (display == nullptr) {
// We're running in headless mode.
return false;
}
return !GDK_IS_X11_DISPLAY(display);
}
// Return true if Firefox is actually running on Wayland enabled session.
// It means some screensharing capabilities may be limited.
static bool IsWaylandSessionUsed() {
bool DesktopCapturer::IsRunningUnderWayland() {
const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
if (!xdg_session_type || strncmp(xdg_session_type, "wayland", 7) != 0)
return false;
@ -99,10 +82,6 @@ static bool IsWaylandSessionUsed() {
return true;
}
bool DesktopCapturer::IsRunningUnderWayland() {
return IsWaylandSessionUsed() ? IsWaylandDisplayUsed() : false;
}
#endif // defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
} // namespace webrtc

View File

@ -15,10 +15,8 @@
#include <spa/param/format-utils.h>
#include <spa/param/props.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <spa/param/video/raw-utils.h>
#include <spa/support/type-map.h>
#include <memory>
#include <utility>
@ -39,43 +37,30 @@ const char kRequestInterfaceName[] = "org.freedesktop.portal.Request";
const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
// static
struct dma_buf_sync {
uint64_t flags;
};
#define DMA_BUF_SYNC_READ (1 << 0)
#define DMA_BUF_SYNC_START (0 << 2)
#define DMA_BUF_SYNC_END (1 << 2)
#define DMA_BUF_BASE 'b'
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
void BaseCapturerPipeWire::OnStateChanged(void* data,
pw_remote_state old_state,
pw_remote_state state,
const char* error_message) {
BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
RTC_DCHECK(that);
static void SyncDmaBuf(int fd, uint64_t start_or_end) {
struct dma_buf_sync sync = { 0 };
sync.flags = start_or_end | DMA_BUF_SYNC_READ;
while(true) {
int ret;
ret = ioctl (fd, DMA_BUF_IOCTL_SYNC, &sync);
if (ret == -1 && errno == EINTR) {
continue;
} else if (ret == -1) {
RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: " << g_strerror(errno);
switch (state) {
case PW_REMOTE_STATE_ERROR:
RTC_LOG(LS_ERROR) << "PipeWire remote state error: " << error_message;
break;
} else {
case PW_REMOTE_STATE_CONNECTED:
RTC_LOG(LS_INFO) << "PipeWire remote state: connected.";
that->CreateReceivingStream();
break;
case PW_REMOTE_STATE_CONNECTING:
RTC_LOG(LS_INFO) << "PipeWire remote state: connecting.";
break;
case PW_REMOTE_STATE_UNCONNECTED:
RTC_LOG(LS_INFO) << "PipeWire remote state: unconnected.";
break;
}
}
}
// static
void BaseCapturerPipeWire::OnCoreError(void *data,
uint32_t id,
int seq,
int res,
const char *message) {
RTC_LOG(LS_ERROR) << "core error: " << message;
}
// static
void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
pw_stream_state old_state,
@ -88,54 +73,76 @@ void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
case PW_STREAM_STATE_ERROR:
RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
break;
case PW_STREAM_STATE_PAUSED:
case PW_STREAM_STATE_STREAMING:
case PW_STREAM_STATE_CONFIGURE:
pw_stream_set_active(that->pw_stream_, true);
break;
case PW_STREAM_STATE_UNCONNECTED:
case PW_STREAM_STATE_CONNECTING:
case PW_STREAM_STATE_READY:
case PW_STREAM_STATE_PAUSED:
case PW_STREAM_STATE_STREAMING:
break;
}
}
// static
void BaseCapturerPipeWire::OnStreamParamChanged(void *data, uint32_t id,
const struct spa_pod *format) {
void BaseCapturerPipeWire::OnStreamFormatChanged(void* data,
const struct spa_pod* format) {
BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
RTC_DCHECK(that);
RTC_LOG(LS_INFO) << "PipeWire stream param changed.";
RTC_LOG(LS_INFO) << "PipeWire stream format changed.";
if (!format || id != SPA_PARAM_Format) {
if (!format) {
pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr,
/*n_params=*/0);
return;
}
spa_format_video_raw_parse(format, &that->spa_video_format_);
that->spa_video_format_ = new spa_video_info_raw();
spa_format_video_raw_parse(format, that->spa_video_format_,
&that->pw_type_->format_video);
auto width = that->spa_video_format_.size.width;
auto height = that->spa_video_format_.size.height;
auto width = that->spa_video_format_->size.width;
auto height = that->spa_video_format_->size.height;
auto stride = SPA_ROUND_UP_N(width * kBytesPerPixel, 4);
auto size = height * stride;
that->desktop_size_ = DesktopSize(width, height);
uint8_t buffer[1024] = {};
auto builder = spa_pod_builder{buffer, sizeof(buffer)};
// Setup buffers and meta header for new format.
const struct spa_pod* params[3];
params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_size, SPA_POD_Int(size),
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride),
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, 32)));
params[1] = 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_Header),
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))));
params[2] = 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_VideoCrop),
SPA_PARAM_META_size, SPA_POD_Int (sizeof(struct spa_meta_region))));
pw_stream_update_params(that->pw_stream_, params, 3);
const struct spa_pod* params[2];
params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
&builder,
// id to enumerate buffer requirements
that->pw_core_type_->param.idBuffers,
that->pw_core_type_->param_buffers.Buffers,
// Size: specified as integer (i) and set to specified size
":", that->pw_core_type_->param_buffers.size, "i", size,
// Stride: specified as integer (i) and set to specified stride
":", that->pw_core_type_->param_buffers.stride, "i", stride,
// Buffers: specifies how many buffers we want to deal with, set as
// integer (i) where preferred number is 8, then allowed number is defined
// as range (r) from min and max values and it is undecided (u) to allow
// negotiation
":", that->pw_core_type_->param_buffers.buffers, "iru", 8,
SPA_POD_PROP_MIN_MAX(1, 32),
// Align: memory alignment of the buffer, set as integer (i) to specified
// value
":", that->pw_core_type_->param_buffers.align, "i", 16));
params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
&builder,
// id to enumerate supported metadata
that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta,
// Type: specified as id or enum (I)
":", that->pw_core_type_->param_meta.type, "I",
that->pw_core_type_->meta.Header,
// Size: size of the metadata, specified as integer (i)
":", that->pw_core_type_->param_meta.size, "i",
sizeof(struct spa_meta_header)));
pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2);
}
// static
@ -143,26 +150,15 @@ void BaseCapturerPipeWire::OnStreamProcess(void* data) {
BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
RTC_DCHECK(that);
struct pw_buffer *next_buffer;
struct pw_buffer *buffer = nullptr;
pw_buffer* buf = nullptr;
next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
while (next_buffer) {
buffer = next_buffer;
next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
if (next_buffer) {
pw_stream_queue_buffer (that->pw_stream_, buffer);
}
}
if (!buffer) {
if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) {
return;
}
that->HandleBuffer(buffer);
that->HandleBuffer(buf);
pw_stream_queue_buffer(that->pw_stream_, buffer);
pw_stream_queue_buffer(that->pw_stream_, buf);
}
BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type)
@ -173,22 +169,38 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() {
pw_thread_loop_stop(pw_main_loop_);
}
if (pw_type_) {
delete pw_type_;
}
if (spa_video_format_) {
delete spa_video_format_;
}
if (pw_stream_) {
pw_stream_destroy(pw_stream_);
}
if (pw_core_) {
pw_core_disconnect(pw_core_);
if (pw_remote_) {
pw_remote_destroy(pw_remote_);
}
if (pw_context_) {
pw_context_destroy(pw_context_);
if (pw_core_) {
pw_core_destroy(pw_core_);
}
if (pw_main_loop_) {
pw_thread_loop_destroy(pw_main_loop_);
}
if (pw_loop_) {
pw_loop_destroy(pw_loop_);
}
if (current_frame_) {
free(current_frame_);
}
if (start_request_signal_id_) {
g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
}
@ -238,35 +250,27 @@ void BaseCapturerPipeWire::InitPortal() {
void BaseCapturerPipeWire::InitPipeWire() {
pw_init(/*argc=*/nullptr, /*argc=*/nullptr);
pw_main_loop_ = pw_thread_loop_new("pipewire-main-loop", nullptr);
pw_context_ = pw_context_new(pw_thread_loop_get_loop(pw_main_loop_), nullptr, 0);
if (!pw_context_) {
RTC_LOG(LS_ERROR) << "Failed to create PipeWire context";
return;
}
pw_loop_ = pw_loop_new(/*properties=*/nullptr);
pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop");
pw_core_ = pw_context_connect(pw_context_, nullptr, 0);
if (!pw_core_) {
RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context";
return;
}
pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr);
pw_core_type_ = pw_core_get_type(pw_core_);
pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0);
InitPipeWireTypes();
// Initialize event handlers, remote end and stream-related.
pw_core_events_.version = PW_VERSION_CORE_EVENTS;
pw_core_events_.error = &OnCoreError;
pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS;
pw_remote_events_.state_changed = &OnStateChanged;
pw_stream_events_.version = PW_VERSION_STREAM_EVENTS;
pw_stream_events_.state_changed = &OnStreamStateChanged;
pw_stream_events_.param_changed = &OnStreamParamChanged;
pw_stream_events_.format_changed = &OnStreamFormatChanged;
pw_stream_events_.process = &OnStreamProcess;
pw_core_add_listener(pw_core_, &spa_core_listener_, &pw_core_events_, this);
pw_stream_ = CreateReceivingStream();
if (!pw_stream_) {
RTC_LOG(LS_ERROR) << "Failed to create PipeWire stream";
return;
}
pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_,
this);
pw_remote_connect_fd(pw_remote_, pw_fd_);
if (pw_thread_loop_start(pw_main_loop_) < 0) {
RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop";
@ -274,164 +278,105 @@ void BaseCapturerPipeWire::InitPipeWire() {
}
}
pw_stream* BaseCapturerPipeWire::CreateReceivingStream() {
spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
spa_rectangle pwMaxScreenBounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
void BaseCapturerPipeWire::InitPipeWireTypes() {
spa_type_map* map = pw_core_type_->map;
pw_type_ = new PipeWireType();
auto stream = pw_stream_new(pw_core_, "webrtc-pipewire-stream", nullptr);
if (!stream) {
RTC_LOG(LS_ERROR) << "Could not create receiving stream.";
return nullptr;
}
uint8_t buffer[1024] = {};
const spa_pod* params[2];
spa_pod_builder builder = SPA_POD_BUILDER_INIT(buffer, sizeof (buffer));
params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, SPA_VIDEO_FORMAT_RGBA,
SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_BGRA),
SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds,
&pwMinScreenBounds,
&pwMaxScreenBounds),
0));
pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_, this);
if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_,
PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) {
RTC_LOG(LS_ERROR) << "Could not connect receiving stream.";
portal_init_failed_ = true;
}
return stream;
spa_type_media_type_map(map, &pw_type_->media_type);
spa_type_media_subtype_map(map, &pw_type_->media_subtype);
spa_type_format_video_map(map, &pw_type_->format_video);
spa_type_video_format_map(map, &pw_type_->video_format);
}
static void SpaBufferUnmap(unsigned char *map, int map_size, bool IsDMABuf, int fd) {
if (map) {
if (IsDMABuf) {
SyncDmaBuf(fd, DMA_BUF_SYNC_END);
}
munmap(map, map_size);
void BaseCapturerPipeWire::CreateReceivingStream() {
spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
spa_rectangle pwScreenBounds =
spa_rectangle{static_cast<uint32_t>(desktop_size_.width()),
static_cast<uint32_t>(desktop_size_.height())};
spa_fraction pwFrameRateMin = spa_fraction{0, 1};
spa_fraction pwFrameRateMax = spa_fraction{60, 1};
pw_properties* reuseProps = pw_properties_new("pipewire.client.reuse", "1",
/*end of varargs*/ nullptr);
pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
uint8_t buffer[1024] = {};
const spa_pod* params[1];
spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
&builder,
// id to enumerate formats
pw_core_type_->param.idEnumFormat, pw_core_type_->spa_format, "I",
pw_type_->media_type.video, "I", pw_type_->media_subtype.raw,
// Video format: specified as id or enum (I), preferred format is BGRx,
// then allowed formats are enumerated (e) and the format is undecided (u)
// to allow negotiation
":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx,
SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx,
pw_type_->video_format.BGRx),
// Video size: specified as rectangle (R), preferred size is specified as
// first parameter, then allowed size is defined as range (r) from min and
// max values and the format is undecided (u) to allow negotiation
":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2,
&pwMinScreenBounds, &pwScreenBounds,
// Frame rate: specified as fraction (F) and set to minimum frame rate
// value
":", pw_type_->format_video.framerate, "F", &pwFrameRateMin,
// Max frame rate: specified as fraction (F), preferred frame rate is set
// to maximum value, then allowed frame rate is defined as range (r) from
// min and max values and it is undecided (u) to allow negotiation
":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2,
&pwFrameRateMin, &pwFrameRateMax));
pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_,
this);
pw_stream_flags flags = static_cast<pw_stream_flags>(
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE |
PW_STREAM_FLAG_MAP_BUFFERS);
if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
flags, params,
/*n_params=*/1) != 0) {
RTC_LOG(LS_ERROR) << "Could not connect receiving stream.";
portal_init_failed_ = true;
return;
}
}
void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
spa_buffer* spaBuffer = buffer->buffer;
uint8_t *map = nullptr;
uint8_t* src = nullptr;
void* src = nullptr;
if (spaBuffer->datas[0].chunk->size == 0) {
RTC_LOG(LS_ERROR) << "Failed to get video stream: Zero size.";
if (!(src = spaBuffer->datas[0].data)) {
return;
}
switch (spaBuffer->datas[0].type) {
case SPA_DATA_MemFd:
case SPA_DATA_DmaBuf:
map = static_cast<uint8_t*>(mmap(
nullptr, spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0));
if (map == MAP_FAILED) {
RTC_LOG(LS_ERROR) << "Failed to mmap memory: " << std::strerror(errno);
return;
}
if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_START);
}
src = SPA_MEMBER(map, spaBuffer->datas[0].mapoffset, uint8_t);
break;
case SPA_DATA_MemPtr:
map = nullptr;
src = static_cast<uint8_t*>(spaBuffer->datas[0].data);
break;
default:
return;
}
if (!src) {
RTC_LOG(LS_ERROR) << "Failed to get video stream: Wrong data after mmap()";
SpaBufferUnmap(map,
spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
spaBuffer->datas[0].type == SPA_DATA_DmaBuf, spaBuffer->datas[0].fd);
uint32_t maxSize = spaBuffer->datas[0].maxsize;
int32_t srcStride = spaBuffer->datas[0].chunk->stride;
if (srcStride != (desktop_size_.width() * kBytesPerPixel)) {
RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
<< srcStride
<< " != " << (desktop_size_.width() * kBytesPerPixel);
portal_init_failed_ = true;
return;
}
struct spa_meta_region* video_metadata =
static_cast<struct spa_meta_region*>(
spa_buffer_find_meta_data(spaBuffer, SPA_META_VideoCrop, sizeof(*video_metadata)));
// Video size from metada is bigger than an actual video stream size.
// The metadata are wrong or we should up-scale te video...in both cases
// just quit now.
if (video_metadata &&
(video_metadata->region.size.width > (uint32_t)desktop_size_.width() ||
video_metadata->region.size.height > (uint32_t)desktop_size_.height())) {
RTC_LOG(LS_ERROR) << "Stream metadata sizes are wrong!";
SpaBufferUnmap(map,
spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
spaBuffer->datas[0].type == SPA_DATA_DmaBuf, spaBuffer->datas[0].fd);
return;
if (!current_frame_) {
current_frame_ = static_cast<uint8_t*>(malloc(maxSize));
}
RTC_DCHECK(current_frame_ != nullptr);
// Use video metada when video size from metadata is set and smaller than
// video stream size, so we need to adjust it.
video_metadata_use_ = (video_metadata &&
video_metadata->region.size.width != 0 &&
video_metadata->region.size.height != 0 &&
(video_metadata->region.size.width < (uint32_t)desktop_size_.width() ||
video_metadata->region.size.height < (uint32_t)desktop_size_.height()));
DesktopSize video_size_prev = video_size_;
if (video_metadata_use_) {
video_size_ = DesktopSize(video_metadata->region.size.width,
video_metadata->region.size.height);
// 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 == pw_type_->video_format.RGBx) {
uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize));
std::memcpy(tempFrame, src, maxSize);
ConvertRGBxToBGRx(tempFrame, maxSize);
std::memcpy(current_frame_, tempFrame, maxSize);
free(tempFrame);
} else {
video_size_ = desktop_size_;
std::memcpy(current_frame_, src, maxSize);
}
if (!current_frame_ ||
(video_metadata_use_ && !video_size_.equals(video_size_prev))) {
current_frame_ =
std::make_unique<uint8_t[]>
(video_size_.width() * video_size_.height() * kBytesPerPixel);
}
const int32_t dstStride = video_size_.width() * kBytesPerPixel;
const int32_t srcStride = spaBuffer->datas[0].chunk->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 += srcStride * video_metadata->region.position.y;
}
const int xOffset =
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 += xOffset;
std::memcpy(dst, src, dstStride);
// 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, dstStride);
}
src += srcStride - xOffset;
dst += dstStride;
}
SpaBufferUnmap(map,
spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
spaBuffer->datas[0].type == SPA_DATA_DmaBuf, spaBuffer->datas[0].fd);
}
void BaseCapturerPipeWire::ConvertRGBxToBGRx(uint8_t* frame, uint32_t size) {
@ -773,12 +718,17 @@ void BaseCapturerPipeWire::OnStartRequestResponseSignal(
while (g_variant_iter_next(iter, "@(ua{sv})", &variant)) {
guint32 stream_id;
gint32 width;
gint32 height;
GVariant* options;
g_variant_get(variant, "(u@a{sv})", &stream_id, &options);
RTC_DCHECK(options != nullptr);
that->pw_stream_node_id_ = stream_id;
g_variant_lookup(options, "size", "(ii)", &width, &height);
that->desktop_size_.set(width, height);
g_variant_unref(options);
g_variant_unref(variant);
}
@ -863,15 +813,10 @@ void BaseCapturerPipeWire::CaptureFrame() {
return;
}
DesktopSize frame_size = desktop_size_;
if (video_metadata_use_) {
frame_size = video_size_;
}
std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size));
std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_));
result->CopyPixelsFrom(
current_frame_.get(), (frame_size.width() * kBytesPerPixel),
DesktopRect::MakeWH(frame_size.width(), frame_size.height()));
current_frame_, (desktop_size_.width() * kBytesPerPixel),
DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height()));
if (!result) {
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
return;
@ -892,22 +837,4 @@ bool BaseCapturerPipeWire::SelectSource(SourceId id) {
return true;
}
// static
std::unique_ptr<DesktopCapturer>
BaseCapturerPipeWire::CreateRawScreenCapturer(
const DesktopCaptureOptions& options) {
std::unique_ptr<BaseCapturerPipeWire> capturer =
std::make_unique<BaseCapturerPipeWire>(BaseCapturerPipeWire::CaptureSourceType::kAny);
return std::move(capturer);}
// static
std::unique_ptr<DesktopCapturer>
BaseCapturerPipeWire::CreateRawWindowCapturer(
const DesktopCaptureOptions& options) {
std::unique_ptr<BaseCapturerPipeWire> capturer =
std::make_unique<BaseCapturerPipeWire>(BaseCapturerPipeWire::CaptureSourceType::kAny);
return std::move(capturer);
}
} // namespace webrtc

View File

@ -22,13 +22,17 @@
namespace webrtc {
class PipeWireType {
public:
spa_type_media_type media_type;
spa_type_media_subtype media_subtype;
spa_type_format_video format_video;
spa_type_video_format video_format;
};
class BaseCapturerPipeWire : public DesktopCapturer {
public:
enum CaptureSourceType : uint32_t {
kScreen = 0b01,
kWindow = 0b10,
kAny = 0b11
};
enum CaptureSourceType { Screen = 1, Window };
explicit BaseCapturerPipeWire(CaptureSourceType source_type);
~BaseCapturerPipeWire() override;
@ -39,32 +43,28 @@ class BaseCapturerPipeWire : public DesktopCapturer {
bool GetSourceList(SourceList* sources) override;
bool SelectSource(SourceId id) override;
static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(
const DesktopCaptureOptions& options);
static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
const DesktopCaptureOptions& options);
private:
// PipeWire types -->
pw_context* pw_context_ = nullptr;
pw_core* pw_core_ = nullptr;
pw_type* pw_core_type_ = nullptr;
pw_stream* pw_stream_ = nullptr;
pw_remote* pw_remote_ = nullptr;
pw_loop* pw_loop_ = nullptr;
pw_thread_loop* pw_main_loop_ = nullptr;
PipeWireType* pw_type_ = nullptr;
spa_hook spa_core_listener_ = {};
spa_hook spa_stream_listener_ = {};
spa_hook spa_remote_listener_ = {};
pw_core_events pw_core_events_ = {};
pw_stream_events pw_stream_events_ = {};
pw_remote_events pw_remote_events_ = {};
struct spa_video_info_raw spa_video_format_;
spa_video_info_raw* spa_video_format_ = nullptr;
guint32 pw_stream_node_id_ = 0;
gint32 pw_fd_ = -1;
CaptureSourceType capture_source_type_ =
BaseCapturerPipeWire::CaptureSourceType::kAny;
BaseCapturerPipeWire::CaptureSourceType::Screen;
// <-- end of PipeWire types
@ -78,36 +78,33 @@ class BaseCapturerPipeWire : public DesktopCapturer {
guint sources_request_signal_id_ = 0;
guint start_request_signal_id_ = 0;
bool video_metadata_use_ = false;
DesktopSize video_size_;
DesktopSize desktop_size_ = {};
DesktopCaptureOptions options_ = {};
std::unique_ptr<uint8_t[]> current_frame_;
uint8_t* current_frame_ = nullptr;
Callback* callback_ = nullptr;
bool portal_init_failed_ = false;
void InitPortal();
void InitPipeWire();
void InitPipeWireTypes();
pw_stream* CreateReceivingStream();
void CreateReceivingStream();
void HandleBuffer(pw_buffer* buffer);
void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
static void OnCoreError(void *data,
uint32_t id,
int seq,
int res,
const char *message);
static void OnStreamParamChanged(void *data,
uint32_t id,
const struct spa_pod *format);
static void OnStateChanged(void* data,
pw_remote_state old_state,
pw_remote_state state,
const char* error);
static void OnStreamStateChanged(void* data,
pw_stream_state old_state,
pw_stream_state state,
const char* error_message);
static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
static void OnStreamProcess(void* data);
static void OnNewBuffer(void* data, uint32_t id);

View File

@ -15,7 +15,7 @@
namespace webrtc {
ScreenCapturerPipeWire::ScreenCapturerPipeWire()
: BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::kScreen) {}
: BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {}
ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {}
// static

View File

@ -15,7 +15,7 @@
namespace webrtc {
WindowCapturerPipeWire::WindowCapturerPipeWire()
: BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::kWindow) {}
: BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {}
WindowCapturerPipeWire::~WindowCapturerPipeWire() {}
// static

View File

@ -26,7 +26,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
const DesktopCaptureOptions& options) {
#if defined(WEBRTC_USE_PIPEWIRE)
if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
return BaseCapturerPipeWire::CreateRawScreenCapturer(options);
return ScreenCapturerPipeWire::CreateRawScreenCapturer(options);
}
#endif // defined(WEBRTC_USE_PIPEWIRE)

View File

@ -26,7 +26,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
const DesktopCaptureOptions& options) {
#if defined(WEBRTC_USE_PIPEWIRE)
if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
return BaseCapturerPipeWire::CreateRawWindowCapturer(options);
return WindowCapturerPipeWire::CreateRawWindowCapturer(options);
}
#endif // defined(WEBRTC_USE_PIPEWIRE)

View File

@ -186,9 +186,6 @@ if CONFIG["OS_TARGET"] == "Linux":
"/third_party/libwebrtc/webrtc/modules/video_capture/video_capture_internal_impl_gn",
"/third_party/libwebrtc/webrtc/system_wrappers/cpu_features_linux_gn"
]
DIRS += [
"/third_party/pipewire/libpipewire"
]
if CONFIG["OS_TARGET"] == "NetBSD":