85157a42c7
Also backport upstream fixes for PipeWire camera support. Resolves: RHEL-64749
232 lines
9.6 KiB
Diff
232 lines
9.6 KiB
Diff
From 286575b387cff9b3ec318d3cf90cf20d2f3c2ce4 Mon Sep 17 00:00:00 2001
|
|
From: Jan Grulich <jgrulich@redhat.com>
|
|
Date: Mon, 2 Sep 2024 11:07:20 +0000
|
|
Subject: [PATCH] Bug 1913286 - WebRTC backport: PipeWire camera: filter out
|
|
devices with no capabilities r=pehrsons,webrtc-reviewers
|
|
|
|
Filter out devices that do not support any format supported by WebRTC.
|
|
This will for example be IR cameras that show as duplicated in the list
|
|
of cameras, but support only GRAY8 format and for that reason do not
|
|
work at all.
|
|
|
|
This is a simple backport of an WebRTC upstream change.
|
|
|
|
Upstream commit: b4aba7834e6c94adace1cb4c20e2e1ee70eb9cc5
|
|
|
|
Differential Revision: https://phabricator.services.mozilla.com/D219224
|
|
---
|
|
.../linux/device_info_pipewire.cc | 20 ++++-----
|
|
.../video_capture/linux/pipewire_session.cc | 43 +++++++++++++------
|
|
.../video_capture/linux/pipewire_session.h | 21 ++++++---
|
|
.../b4aba7834e.no-op-cherry-pick-msg | 1 +
|
|
4 files changed, 58 insertions(+), 27 deletions(-)
|
|
create mode 100644 third_party/libwebrtc/moz-patch-stack/b4aba7834e.no-op-cherry-pick-msg
|
|
|
|
diff --git a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
|
|
index 31d922035b3f8..db2a3c7099169 100644
|
|
--- a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
|
|
+++ b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
|
|
@@ -57,31 +57,31 @@ int32_t DeviceInfoPipeWire::GetDeviceName(uint32_t deviceNumber,
|
|
if (deviceNumber >= NumberOfDevices())
|
|
return -1;
|
|
|
|
- const PipeWireNode& node = pipewire_session_->nodes().at(deviceNumber);
|
|
+ const auto& node = pipewire_session_->nodes().at(deviceNumber);
|
|
|
|
- if (deviceNameLength <= node.display_name().length()) {
|
|
+ if (deviceNameLength <= node->display_name().length()) {
|
|
RTC_LOG(LS_INFO) << "deviceNameUTF8 buffer passed is too small";
|
|
return -1;
|
|
}
|
|
- if (deviceUniqueIdUTF8Length <= node.unique_id().length()) {
|
|
+ if (deviceUniqueIdUTF8Length <= node->unique_id().length()) {
|
|
RTC_LOG(LS_INFO) << "deviceUniqueIdUTF8 buffer passed is too small";
|
|
return -1;
|
|
}
|
|
if (productUniqueIdUTF8 &&
|
|
- productUniqueIdUTF8Length <= node.model_id().length()) {
|
|
+ productUniqueIdUTF8Length <= node->model_id().length()) {
|
|
RTC_LOG(LS_INFO) << "productUniqueIdUTF8 buffer passed is too small";
|
|
return -1;
|
|
}
|
|
|
|
memset(deviceNameUTF8, 0, deviceNameLength);
|
|
- node.display_name().copy(deviceNameUTF8, deviceNameLength);
|
|
+ node->display_name().copy(deviceNameUTF8, deviceNameLength);
|
|
|
|
memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
|
|
- node.unique_id().copy(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length);
|
|
+ node->unique_id().copy(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length);
|
|
|
|
if (productUniqueIdUTF8) {
|
|
memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
|
|
- node.model_id().copy(productUniqueIdUTF8, productUniqueIdUTF8Length);
|
|
+ node->model_id().copy(productUniqueIdUTF8, productUniqueIdUTF8Length);
|
|
}
|
|
|
|
return 0;
|
|
@@ -92,11 +92,11 @@ int32_t DeviceInfoPipeWire::CreateCapabilityMap(
|
|
RTC_CHECK(pipewire_session_);
|
|
|
|
for (auto& node : pipewire_session_->nodes()) {
|
|
- if (node.unique_id().compare(deviceUniqueIdUTF8) != 0)
|
|
+ if (node->unique_id().compare(deviceUniqueIdUTF8) != 0)
|
|
continue;
|
|
|
|
- _captureCapabilities = node.capabilities();
|
|
- _lastUsedDeviceNameLength = node.unique_id().length();
|
|
+ _captureCapabilities = node->capabilities();
|
|
+ _lastUsedDeviceNameLength = node->unique_id().length();
|
|
_lastUsedDeviceName = static_cast<char*>(
|
|
realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
|
memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8,
|
|
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
|
|
index 107ea3dfbd954..dbac09274bb31 100644
|
|
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
|
|
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
|
|
@@ -52,6 +52,19 @@ VideoType PipeWireRawFormatToVideoType(uint32_t id) {
|
|
}
|
|
}
|
|
|
|
+void PipeWireNode::PipeWireNodeDeleter::operator()(
|
|
+ PipeWireNode* node) const noexcept {
|
|
+ pw_proxy_destroy(node->proxy_);
|
|
+ spa_hook_remove(&node->node_listener_);
|
|
+}
|
|
+
|
|
+// static
|
|
+PipeWireNode::PipeWireNodePtr PipeWireNode::Create(PipeWireSession* session,
|
|
+ uint32_t id,
|
|
+ const spa_dict* props) {
|
|
+ return PipeWireNodePtr(new PipeWireNode(session, id, props));
|
|
+}
|
|
+
|
|
PipeWireNode::PipeWireNode(PipeWireSession* session,
|
|
uint32_t id,
|
|
const spa_dict* props)
|
|
@@ -73,11 +86,6 @@ PipeWireNode::PipeWireNode(PipeWireSession* session,
|
|
pw_node_add_listener(proxy_, &node_listener_, &node_events, this);
|
|
}
|
|
|
|
-PipeWireNode::~PipeWireNode() {
|
|
- pw_proxy_destroy(proxy_);
|
|
- spa_hook_remove(&node_listener_);
|
|
-}
|
|
-
|
|
// static
|
|
void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
|
|
PipeWireNode* that = static_cast<PipeWireNode*>(data);
|
|
@@ -99,7 +107,9 @@ void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
|
|
pid.value());
|
|
that->model_id_ = model_str;
|
|
}
|
|
- } else if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
|
|
+ }
|
|
+
|
|
+ if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
|
|
for (uint32_t i = 0; i < info->n_params; i++) {
|
|
uint32_t id = info->params[i].id;
|
|
if (id == SPA_PARAM_EnumFormat &&
|
|
@@ -350,6 +360,14 @@ void PipeWireSession::OnCoreDone(void* data, uint32_t id, int seq) {
|
|
if (id == PW_ID_CORE) {
|
|
if (seq == that->sync_seq_) {
|
|
RTC_LOG(LS_VERBOSE) << "Enumerating PipeWire camera devices complete.";
|
|
+
|
|
+ // Remove camera devices with no capabilities
|
|
+ auto it = std::remove_if(that->nodes_.begin(), that->nodes_.end(),
|
|
+ [](const PipeWireNode::PipeWireNodePtr& node) {
|
|
+ return node->capabilities().empty();
|
|
+ });
|
|
+ that->nodes_.erase(it, that->nodes_.end());
|
|
+
|
|
that->Finish(VideoCaptureOptions::Status::SUCCESS);
|
|
}
|
|
}
|
|
@@ -366,8 +384,8 @@ void PipeWireSession::OnRegistryGlobal(void* data,
|
|
|
|
// Skip already added nodes to avoid duplicate camera entries
|
|
if (std::find_if(that->nodes_.begin(), that->nodes_.end(),
|
|
- [id](const PipeWireNode& node) {
|
|
- return node.id() == id;
|
|
+ [id](const PipeWireNode::PipeWireNodePtr& node) {
|
|
+ return node->id() == id;
|
|
}) != that->nodes_.end())
|
|
return;
|
|
|
|
@@ -381,7 +399,7 @@ void PipeWireSession::OnRegistryGlobal(void* data,
|
|
if (!node_role || strcmp(node_role, "Camera"))
|
|
return;
|
|
|
|
- that->nodes_.emplace_back(that, id, props);
|
|
+ that->nodes_.push_back(PipeWireNode::Create(that, id, props));
|
|
that->PipeWireSync();
|
|
}
|
|
|
|
@@ -389,9 +407,10 @@ void PipeWireSession::OnRegistryGlobal(void* data,
|
|
void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) {
|
|
PipeWireSession* that = static_cast<PipeWireSession*>(data);
|
|
|
|
- auto it = std::remove_if(
|
|
- that->nodes_.begin(), that->nodes_.end(),
|
|
- [id](const PipeWireNode& node) { return node.id() == id; });
|
|
+ auto it = std::remove_if(that->nodes_.begin(), that->nodes_.end(),
|
|
+ [id](const PipeWireNode::PipeWireNodePtr& node) {
|
|
+ return node->id() == id;
|
|
+ });
|
|
that->nodes_.erase(it, that->nodes_.end());
|
|
}
|
|
|
|
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
|
|
index fdc06a6b2a27a..84273ea695277 100644
|
|
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
|
|
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
|
|
@@ -37,8 +37,15 @@ class VideoCaptureModulePipeWire;
|
|
// So they all represent one camera that is available via PipeWire.
|
|
class PipeWireNode {
|
|
public:
|
|
- PipeWireNode(PipeWireSession* session, uint32_t id, const spa_dict* props);
|
|
- ~PipeWireNode();
|
|
+ struct PipeWireNodeDeleter {
|
|
+ void operator()(PipeWireNode* node) const noexcept;
|
|
+ };
|
|
+
|
|
+ using PipeWireNodePtr =
|
|
+ std::unique_ptr<PipeWireNode, PipeWireNode::PipeWireNodeDeleter>;
|
|
+ static PipeWireNodePtr Create(PipeWireSession* session,
|
|
+ uint32_t id,
|
|
+ const spa_dict* props);
|
|
|
|
uint32_t id() const { return id_; }
|
|
std::string display_name() const { return display_name_; }
|
|
@@ -48,6 +55,9 @@ class PipeWireNode {
|
|
return capabilities_;
|
|
}
|
|
|
|
+ protected:
|
|
+ PipeWireNode(PipeWireSession* session, uint32_t id, const spa_dict* props);
|
|
+
|
|
private:
|
|
static void OnNodeInfo(void* data, const pw_node_info* info);
|
|
static void OnNodeParam(void* data,
|
|
@@ -87,8 +97,9 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
|
|
|
|
void Init(VideoCaptureOptions::Callback* callback,
|
|
int fd = kInvalidPipeWireFd);
|
|
-
|
|
- const std::deque<PipeWireNode>& nodes() const { return nodes_; }
|
|
+ const std::deque<PipeWireNode::PipeWireNodePtr>& nodes() const {
|
|
+ return nodes_;
|
|
+ }
|
|
|
|
friend class CameraPortalNotifier;
|
|
friend class PipeWireNode;
|
|
@@ -134,7 +145,7 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
|
|
|
|
int sync_seq_ = 0;
|
|
|
|
- std::deque<PipeWireNode> nodes_;
|
|
+ std::deque<PipeWireNode::PipeWireNodePtr> nodes_;
|
|
std::unique_ptr<CameraPortal> portal_;
|
|
std::unique_ptr<CameraPortalNotifier> portal_notifier_;
|
|
};
|