firefox/009-libwebrtc-pipewire-camera-use-exact-stream-parameters-specified-by-capability.patch
Jan Grulich 85157a42c7 Enable PipeWire camera support for RHEL 10
Also backport upstream fixes for PipeWire camera support.

Resolves: RHEL-64749
2024-11-28 12:50:27 +01:00

173 lines
8.1 KiB
Diff

From ca88b4994e140370ca5795c60f46559301458a98 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Wed, 25 Sep 2024 06:52:35 +0000
Subject: [PATCH] Bug 1920472 - WebRTC backport: PipeWire camera: use exact
stream parameters specified by capability r=pehrsons,webrtc-reviewers
We currently specify stream parameters to be a range for both framerate
and resolution, where preferred value is specified. The preferred value
doesn't seem to be taken into account and we end up accepting resolution
from 1x1 to MAX_INTxMAX_INT. In case the other side tries to first match
with lower resolution than requested, we will happily match it and start
streaming low quality video. We should instead request the exact stream
parameters as specified by requested capability. This capability always
come from what has been originally reported as supported so it shouldn't
happen we don't find a matching stream. This also applies to requested
video format. We previously requested mjpg for streams with resolution
higher than 640x480, but it doesn't necessarily mean the camera supports
mjpg for the requested resolution. Again, refer to requested capability
in this case as it should indicate what is supported and we know we can
request exactly the same video format. It can happen that framerate is
set to 0 as unspecified. In that case keep using a range as before, but
with more sane values.
This is a simple backport of an WebRTC upstream change.
Upstream commit: 9703f8474f156e08e4a96dc36253f1cdccd549e1
Differential Revision: https://phabricator.services.mozilla.com/D223119
---
.../linux/video_capture_pipewire.cc | 85 +++++++++++--------
.../linux/video_capture_pipewire.h | 1 +
.../9703f8474f.no-op-cherry-pick-msg | 1 +
3 files changed, 52 insertions(+), 35 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/9703f8474f.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
index 1672b7583f..2338fa6d87 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
@@ -51,10 +51,20 @@ VideoType VideoCaptureModulePipeWire::PipeWireRawFormatToVideoType(
if (spa_and_pixel_format.spa_format == spa_format)
return spa_and_pixel_format.video_type;
}
- RTC_LOG(LS_INFO) << "Unsupported pixel format: " << spa_format;
+ RTC_LOG(LS_WARNING) << "Unsupported pixel format: " << spa_format;
return VideoType::kUnknown;
}
+uint32_t VideoCaptureModulePipeWire::VideoTypeToPipeWireRawFormat(
+ VideoType type) {
+ for (const auto& spa_and_pixel_format : kSupportedFormats) {
+ if (spa_and_pixel_format.video_type == type)
+ return spa_and_pixel_format.spa_format;
+ }
+ RTC_LOG(LS_WARNING) << "Unsupported video type: " << static_cast<int>(type);
+ return SPA_VIDEO_FORMAT_UNKNOWN;
+}
+
VideoCaptureModulePipeWire::VideoCaptureModulePipeWire(
VideoCaptureOptions* options)
: VideoCaptureImpl(),
@@ -87,45 +97,53 @@ int32_t VideoCaptureModulePipeWire::Init(const char* deviceUniqueId) {
}
static spa_pod* BuildFormat(spa_pod_builder* builder,
- uint32_t format,
+ VideoType video_type,
uint32_t width,
uint32_t height,
float frame_rate) {
- spa_pod_frame frames[2];
+ spa_pod_frame frame;
+
+ const uint32_t media_subtype = video_type == VideoType::kMJPEG
+ ? SPA_MEDIA_SUBTYPE_mjpg
+ : SPA_MEDIA_SUBTYPE_raw;
- spa_pod_builder_push_object(builder, &frames[0], SPA_TYPE_OBJECT_Format,
+ spa_pod_builder_push_object(builder, &frame, SPA_TYPE_OBJECT_Format,
SPA_PARAM_EnumFormat);
spa_pod_builder_add(builder, SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_video), SPA_FORMAT_mediaSubtype,
- SPA_POD_Id(format), 0);
-
- if (format == SPA_MEDIA_SUBTYPE_raw) {
- spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_format, 0);
- spa_pod_builder_push_choice(builder, &frames[1], SPA_CHOICE_Enum, 0);
- spa_pod_builder_id(builder, kSupportedFormats[0].spa_format);
- for (const auto& spa_and_pixel_format : kSupportedFormats)
- spa_pod_builder_id(builder, spa_and_pixel_format.spa_format);
- spa_pod_builder_pop(builder, &frames[1]);
- }
+ SPA_POD_Id(media_subtype), 0);
- spa_rectangle preferred_size = spa_rectangle{width, height};
- spa_rectangle min_size = spa_rectangle{1, 1};
- spa_rectangle max_size = spa_rectangle{4096, 4096};
- spa_pod_builder_add(
- builder, SPA_FORMAT_VIDEO_size,
- SPA_POD_CHOICE_RANGE_Rectangle(&preferred_size, &min_size, &max_size), 0);
+ if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
+ const uint32_t format =
+ VideoCaptureModulePipeWire::VideoTypeToPipeWireRawFormat(video_type);
+ RTC_CHECK(format != SPA_VIDEO_FORMAT_UNKNOWN);
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format),
+ 0);
+ }
- spa_fraction preferred_frame_rate =
- spa_fraction{static_cast<uint32_t>(frame_rate), 1};
- spa_fraction min_frame_rate = spa_fraction{0, 1};
- spa_fraction max_frame_rate = spa_fraction{INT32_MAX, 1};
- spa_pod_builder_add(
- builder, SPA_FORMAT_VIDEO_framerate,
- SPA_POD_CHOICE_RANGE_Fraction(&preferred_frame_rate, &min_frame_rate,
- &max_frame_rate),
- 0);
+ spa_rectangle resolution = spa_rectangle{width, height};
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size,
+ SPA_POD_Rectangle(&resolution), 0);
+
+ // Framerate can be also set to 0 to be unspecified
+ if (frame_rate) {
+ spa_fraction framerate = spa_fraction{static_cast<uint32_t>(frame_rate), 1};
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_framerate,
+ SPA_POD_Fraction(&framerate), 0);
+ } else {
+ // Default to some reasonable values
+ spa_fraction preferred_frame_rate =
+ spa_fraction{static_cast<uint32_t>(30), 1};
+ spa_fraction min_frame_rate = spa_fraction{1, 1};
+ spa_fraction max_frame_rate = spa_fraction{30, 1};
+ spa_pod_builder_add(
+ builder, SPA_FORMAT_VIDEO_framerate,
+ SPA_POD_CHOICE_RANGE_Fraction(&preferred_frame_rate, &min_frame_rate,
+ &max_frame_rate),
+ 0);
+ }
- return static_cast<spa_pod*>(spa_pod_builder_pop(builder, &frames[0]));
+ return static_cast<spa_pod*>(spa_pod_builder_pop(builder, &frame));
}
int32_t VideoCaptureModulePipeWire::StartCapture(
@@ -176,13 +194,10 @@ int32_t VideoCaptureModulePipeWire::StartCapture(
uint32_t width = capability.width;
uint32_t height = capability.height;
uint32_t frame_rate = capability.maxFPS;
- bool prefer_jpeg = (width > 640) || (height > 480);
+ VideoType video_type = capability.videoType;
params.push_back(
- BuildFormat(&builder, SPA_MEDIA_SUBTYPE_raw, width, height, frame_rate));
- params.insert(
- prefer_jpeg ? params.begin() : params.end(),
- BuildFormat(&builder, SPA_MEDIA_SUBTYPE_mjpg, width, height, frame_rate));
+ BuildFormat(&builder, video_type, width, height, frame_rate));
int res = pw_stream_connect(
stream_, PW_DIRECTION_INPUT, node_id_,
diff --git a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h
index eeb3b9497c..789f2034d3 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h
+++ b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h
@@ -28,6 +28,7 @@ class VideoCaptureModulePipeWire : public VideoCaptureImpl {
int32_t CaptureSettings(VideoCaptureCapability& settings) override;
static VideoType PipeWireRawFormatToVideoType(uint32_t format);
+ static uint32_t VideoTypeToPipeWireRawFormat(VideoType type);
private:
static void OnStreamParamChanged(void* data,