From 17e61256c591e4cfe51641d1f1c416fd321a9914 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 21 Apr 2026 20:16:19 +0100 Subject: [PATCH 1/2] gst: skip invalid crop metadata in pipewiresrc META_VideoCrop is present on every buffer negotiated through the adapter, even when the producer never sets a meaningful crop region. Before commit c634ef961, gst_buffer_get_video_crop_meta returned NULL on new GstBuffers so the zero values were never applied. After that commit, gst_buffer_add_video_crop_meta always succeeds, and an invalid crop produces black frames. Without this, the following produces black frames, Producer: gst-launch-1.0 videotestsrc is-live=true ! \ video/x-raw,format=I420,width=1280,height=720,framerate=24/1 ! \ pipewiresink mode=provide \ stream-properties="properties,media.class=Video/Source,media.role=Camera" \ client-name=VirtualCam Consumer: gst-launch-1.0 pipewiresrc path= ! videoconvert ! autovideosink --- src/gst/gstpipewiresrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 3c57028b4..fa61b5ea6 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -781,7 +781,7 @@ static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc) } crop = data->crop; - if (crop) { + if (crop && spa_meta_region_is_valid(crop)) { GstVideoCropMeta *meta = gst_buffer_add_video_crop_meta(buf); if (meta) { meta->x = crop->region.position.x; From 47eebfe6465d6c4fd1a2af5922841643ef9050b7 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 21 Apr 2026 20:17:56 +0100 Subject: [PATCH 2/2] gst: don't make stream errors fatal in pipewiresink mode=provide When a consumer (e.g. Firefox via xdg-desktop-portal) connects to a pipewiresink mode=provide node and format negotiation fails, the error reaches the stream as a transient proxy error. The comments in proxy_error suggest the application should decide whether the error is permanent. Before this on_state_changed unconditionally made every proxy error permanent by calling pw_stream_set_error, which posted GST_ELEMENT_ERROR and killed the entire provider pipeline. A virtual camera provider should survive consumer negotiation failures. In mode=provide, log the error as a warning and continue. Other modes retain the existing behavior. To reproduce (with the previous pool fix applied): Producers: gst-launch-1.0 -v -e pipewiresrc path= ! \ video/x-raw,width=1280,height=720,framerate=24/1 ! \ jpegenc ! rtpjpegpay ! rtpstreampay ! \ udpsink host=127.0.0.1 port=5000 gst-launch-1.0 -e \ udpsrc address=127.0.0.1 port=5000 ! queue ! \ application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! \ application/x-rtp,encoding-name=JPEG ! rtpjpegdepay ! \ decodebin ! videorate ! videoconvert ! \ pipewiresink mode=provide \ stream-properties="properties,media.class=Video/Source,media.role=Camera" \ client-name=VirtualCam Then open Firefox and select VirtualCam as camera source, without this fix the provider pipeline exits with an error, bringing down any other clients streaming from it. --- src/gst/gstpipewiresink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c index 58a6cd8db..7d1d71068 100644 --- a/src/gst/gstpipewiresink.c +++ b/src/gst/gstpipewiresink.c @@ -816,7 +816,10 @@ on_state_changed (void *data, enum pw_stream_state old, enum pw_stream_state sta case PW_STREAM_STATE_ERROR: /* make the error permanent, if it is not already; pw_stream_set_error() will recursively call us again */ - if (pw_stream_get_state (pwsink->stream->pwstream, NULL) != PW_STREAM_STATE_ERROR) + if (pwsink->mode == GST_PIPEWIRE_SINK_MODE_PROVIDE) { + /* don't make consumer errors fatal for the provider */ + GST_WARNING_OBJECT (pwsink, "stream error in mode=provide (ignored): %s", error); + } else if (pw_stream_get_state (pwsink->stream->pwstream, NULL) != PW_STREAM_STATE_ERROR) pw_stream_set_error (pwsink->stream->pwstream, -EPIPE, "%s", error); else GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED,