Skip to content

PipeWire camera source: out.linesize[i] never set for planes > 0 — NV12 renders green #13823

Description

@EberhartLeberhart

Operating System Info

Other

Other OS

Linux Mint 22 (Ubuntu 24.04 base)

OBS Studio Version

32.2.2

OBS Studio Version (Other)

No response

OBS Studio Log URL

https://obsproject.com/logs/L9kCrW6cSQPcC08g

OBS Studio Crash Log URL

No response

Expected Behavior

The camera preview shows the camera image with correct colours, as it does in every other consumer of the same PipeWire node (Firefox, GNOME Snapshot, cam, a gst-launch-1.0 pipewiresrc pipeline).

Current Behavior

The preview is unusable. It splits into three horizontal regions:

top: the scene, rendered entirely in green — the luma plane, correct
middle: a flat band containing a faint, half-resolution copy of the scene — this is the chroma plane being drawn as image data
bottom: noise that changes every frame — reads past the end of the valid data

The negotiated format is fine, and the stream reports streaming without error:

[pipewire] Negotiated format:
[pipewire] Format: 23 (Spa:Enum:VideoFormat:NV12)
[pipewire] Size: 640x480
[pipewire] Framerate: 30/1
[pipewire] Stream state: "streaming" (error: none)

Cause: in plugins/linux-pipewire/pipewire.c, prepare_obs_frame() sets only frame->linesize[0], and the loop in process_video_async() assigns out.data[i] for every plane but never out.linesize[i]. The frame is zero-initialised, so the chroma plane is handed to OBS with a stride of 0. Single-planar formats are unaffected; NV12 is not.

Image

Steps to Reproduce

  1. Use a camera that offers NV12 through PipeWire (here: OV8865 / OV5693 behind an Intel IPU3, via libcamera).

  2. Add a "Video Capture Device (PipeWire)" source and select that camera.

  3. Observe the preview.

For comparison, in the same OBS session: a USB camera delivering YUYV renders correctly. Converting the same IPU3 camera to a single-planar format and republishing it also renders correctly:

gst-launch-1.0 pipewiresrc target-object= !
video/x-raw,width=1280,height=720,framerate=30/1 !
videoconvert ! video/x-raw,format=YUY2 !
pipewiresink stream-properties="props,media.class=Video/Source,media.role=Camera,node.description=single-plane"

Same application, same camera, same path — only the plane count differs.

Anything else we should know?

The code

prepare_obs_frame():

c
frame->linesize[0] = SPA_ROUND_UP_N(frame->width * obs_pw_video_format.bpp, 4);

process_video_async():

c
for (uint32_t i = 0; i < buffer->n_datas && i < MAX_AV_PLANES; i++) {
out.data[i] = buffer->datas[i].data;
if (out.data[i] == NULL) { ... }
}

out.linesize[i] is never assigned. The DEBUG_PIPEWIRE block immediately below logs exactly that value, so a debug build should print Linesize:0 for plane 1.

Unchanged from 30.0.2 through current master.

Suggested fix
c
for (uint32_t i = 0; i < buffer->n_datas && i < MAX_AV_PLANES; i++) {
out.data[i] = buffer->datas[i].data;
if (out.data[i] == NULL) { ... }

    if (buffer->datas[i].chunk->stride > 0)
            out.linesize[i] = buffer->datas[i].chunk->stride;

}

Keeping the computed value as a fallback covers producers that leave stride at 0.

What was ruled out
Camera, driver, libcamera — cam --capture, GNOME Snapshot and Firefox render the same cameras correctly through the same stack. A 300-frame capture at 1280x720 has stable mean luminance and neutral RGB.
Resolution — 640x480 and 1280x720 both behave correctly in every other consumer.
Colorimetry — the negotiated format carries colorRange 16-235, colorMatrix bt601, transferFunction srgb, colorPrimaries bt709. Wrong colorimetry would shift colours, not produce a flat band plus a duplicate image below it.
Distribution or PipeWire version — same behaviour on Linux Mint 22 (PipeWire server 1.0.5, client library 1.4.9) and Fedora 44 (1.6.8), and with both the 32.2.2 Flatpak and the 30.2.3 distribution package.
Not verified

I have not tested the patch. My out-of-tree build of linux-pipewire.so fails format negotiation for unrelated reasons, so I did not want to present it as tested. The analysis rests on the observed behaviour and the source. Happy to test a patch on this hardware.

Possibly related
#10588 — NV12 cameras behaving inconsistently. Some reports there mention low framerate and low resolution, which may be something else entirely.
#10180 — a gstreamer-fed PipeWire node fails with no more input formats as soon as OBS connects. I hit this too while testing the workaround above, so it looks like an independent renegotiation problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions