Pipewiresrc "unhandled format" error on Hyprland with webrtcbin (works on GNOME/KDE)

Hello everyone,

My friend and I are new grad developers working on a screen-sharing application in C. We are quite new to GStreamer and multimedia programming in general, so please bear with us if we are making obvious mistakes.

We are trying to build a pipeline that streams the desktop via WebRTC using pipewiresrc and nvh264enc. We are facing a strange issue that we couldn’t figure out.

The Problem:
Our pipeline works perfectly on GNOME and KDE Plasma. However, on Hyprland, it fails most of the time (it works very rarely) with the following error immediately after changing state:

ERROR: stream error: unhandled format
Debug Info: ../pipewire/src/gst/gstpipewiresrc.c(748): on_state_changed (): /GstPipeline:pipeline0/GstPipeWireSrc:pipewiresrc0

The Failing Pipeline (WebRTC):
This is the pipeline string we are using. Since we are new to this, we are not 100% sure if our caps filters or element ordering is following best practices:

char *pipeline_str = g_strdup_printf(
    "webrtcbin name=sendrecv stun-server=stun://stun.l.google.com:19302 bundle-policy=max-bundle latency=0 "

    // --- VIDEO ---
    "pipewiresrc path=%u do-timestamp=true ! "
    "queue max-size-buffers=3 leaky=downstream ! "
    "videoconvert ! "
    "videoscale ! videorate ! "
    // We are forcing NV12 and SystemMemory here. Could this be the issue?
    "video/x-raw(memory:SystemMemory),format=NV12,width=1920,height=1080,framerate=60/1 ! "

    "nvh264enc "
    "bitrate=8000 rc-mode=cbr preset=low-latency-hq tune=ultra-low-latency "
    "gop-size=60 zerolatency=true qos=false ! "

    "h264parse ! "
    "video/x-h264,stream-format=byte-stream,profile=constrained-baseline ! "
    "rtph264pay config-interval=-1 pt=96 ! "
    "application/x-rtp,media=video,encoding-name=H264,payload=96 ! "
    "queue ! sendrecv. "

    // --- AUDIO ---
    "pulsesrc device=%s do-timestamp=true buffer-time=200000 ! "
    "audioconvert ! audioresample ! opusenc ! rtpopuspay pt=97 ! "
    "queue ! sendrecv. ",
    id, state->is_sound_excluded > 0 ? "GStreamer_Stream.monitor" : audio_device ? audio_device : "0");

What confuses us:
To test if pipewiresrc was broken on Hyprland, we tried a simpler pipeline that records to a file (MKV) instead of streaming via WebRTC. This recording pipeline works perfectly on Hyprland.

// This WORKS fine on Hyprland:
char *pipeline_str = g_strdup_printf(
    "matroskamux name=mux ! filesink location=%s "
    "pipewiresrc path=%u do-timestamp=true ! "
    "queue max-size-buffers=3 leaky=downstream ! "
    "videoconvert ! videoscale ! videorate ! "
    "video/x-raw,width=1920,height=1080,framerate=60/1 ! " // Less strict caps
    "nvh264enc ... ! h264parse ! queue ! mux.video_0 ...", 
    state->output_path, id);

Our Questions:

  1. Since the file recording works, why does the WebRTC pipeline fail with “unhandled format” specifically on Hyprland?
  2. Is there something wrong with how we constructed the pipeline string? Are we forcing something that prevents negotiation?
  3. As beginners, how should we approach debugging this? We are looking for any guidance or tips to point us in the right direction.

We can provide the debug logs if you want us to
Thank you very much for your time and help!

This is an error reported by pipewiresrc and it apparently does not support whatever format is provided by hyprland for screen capture.

You probably want to create an issue against pipewire: Sign in · GitLab

Please also include debug logs with at least GST_DEBUG=3,pipewire*:9 there.