From 377547fa1128823d6c5a4ea17b1310640264713b Mon Sep 17 00:00:00 2001 From: IronCodeStudios Date: Sun, 17 May 2026 16:02:23 +0800 Subject: [PATCH] scrap/wayland: insert videoconvert to fix screencast on COSMIC / DMA-BUF portals (#15063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Wayland compositors whose xdg-desktop-portal backend exposes screencast frames as DMA-BUF buffers — notably xdg-desktop-portal-cosmic 0.1.0 on Pop!_OS 24.04 / COSMIC — inbound screen capture fails. PipeWireRecorder links pipewiresrc directly to an appsink whose caps only accept video/x-raw BGRx/RGBx in system memory. That format set is too narrow for the portal's buffer-type / modifier negotiation, which collapses with: pw.link: negotiating -> error no more output formats (-22) gstpipewiresrc: stream error: no more output formats gstbasesrc: streaming stopped, reason not-negotiated (-4) ERROR src/server/wayland.rs: Failed scrap Element failed to change its state Inserting a videoconvert element between pipewiresrc and appsink widens the negotiable format set to any system-memory video/x-raw format, giving the portal room to settle on a format it can deliver via its SHM path. videoconvert then converts to the BGRx/RGBx the appsink expects. Verified on Pop!_OS 24.04 / COSMIC with gst-launch, before and after: # fails (current behaviour): gst-launch-1.0 pipewiresrc path=N ! video/x-raw,format=BGRx ! fakesink # works (with this change): gst-launch-1.0 pipewiresrc path=N ! videoconvert ! video/x-raw,format=BGRx ! fakesink After the change, inbound connections capture and stream the desktop normally and the "Failed scrap" error no longer occurs. Co-authored-by: Claude Opus 4.7 (1M context) --- libs/scrap/src/wayland/pipewire.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/scrap/src/wayland/pipewire.rs b/libs/scrap/src/wayland/pipewire.rs index aedf786b7..8859d0d3b 100644 --- a/libs/scrap/src/wayland/pipewire.rs +++ b/libs/scrap/src/wayland/pipewire.rs @@ -276,12 +276,21 @@ impl PipeWireRecorder { // see: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/982 src.set_property("always-copy", &true)?; + // COSMIC/Wayland fix: insert videoconvert between pipewiresrc and appsink. + // xdg-desktop-portal-cosmic's modifier negotiation fails when the downstream + // format set is too narrow (appsink only accepts BGRx/RGBx), producing + // "no more output formats" / not-negotiated (-4). videoconvert accepts any + // system-memory video/x-raw format, widening negotiation so the portal can + // settle on a format it can deliver via its SHM path. + let convert = gst::ElementFactory::make("videoconvert", None)?; + let sink = gst::ElementFactory::make("appsink", None)?; sink.set_property("drop", &true)?; sink.set_property("max-buffers", &1u32)?; - pipeline.add_many(&[&src, &sink])?; - src.link(&sink)?; + pipeline.add_many(&[&src, &convert, &sink])?; + src.link(&convert)?; + convert.link(&sink)?; let appsink = sink .dynamic_cast::()