Repository navigation
Literally rewriting basically everything because this was a bad idea on an architectural level - #4
spacedouut wants to merge 19 commits into
Conversation
…synthetic fallback Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
| Layer / File(s) | Summary |
|---|---|
Pipeline contract and frame streaming pipelines/pipeline.go, pipelines/stream.go, pipelines/stream_test.go, pipelines/linux/pulled_stream_test.go |
The pipeline API adds registration, probing, display selection, pooled frames, and stream statistics. Stream tests cover delivery, dropped frames, cleanup, and startup errors. |
Linux KMS capture pipelines/drm_linux.go, pipelines/egl_linux.go, pipelines/kms_*_linux.go, pipelines/linux/* |
Linux KMS discovery and framebuffer helpers support linear and NVIDIA capture. The former Linux KMS, GBM, mapping, source-selection, X11, and synthetic-capture implementations and related tests are removed. |
Linux Mutter PipeWire capture pipelines/pipewire_mutter_linux.go, pipelines/linux/pipewire.go |
The new backend discovers current Mutter monitors, starts a screencast session, and reads BGRA frames through GStreamer. The previous Linux PipeWire implementation is removed. |
macOS ScreenCaptureKit capture pipelines/screencapturekit_darwin.go, pipelines/macos/pipeline.go, pipelines/windows/pipeline.go |
The ScreenCaptureKit backend lists displays and starts BGRA streams. The previous macOS pipeline and the empty Windows pipeline package file are removed. |
Daemon control and media serving main.go, README.md |
The daemon selects named or automatically probed pipelines, serves JSON-lines control requests, and streams dimension-prefixed BGRA frames over a media socket. The README documents the pipelines, flags, protocol, and commands. |
Capture benchmark cmd/capbench/main.go |
The capbench command measures frame timing and throughput, counts duplicate frames, and can report process CPU usage or write the last frame as raw BGRA. |
Estimated code review effort: 4 (Complex) | ~60 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant capbench
participant captured
participant pipelines.Pipeline
capbench->>captured: Send JSON-lines start request
captured->>pipelines.Pipeline: Start display stream at requested FPS
pipelines.Pipeline-->>captured: Return stream and first frame
captured-->>capbench: Return stream dimensions
capbench->>captured: Connect to media socket
captured-->>capbench: Send frame dimensions and BGRA data
Merge Risk: 
Moderate · previous review bb9cc
-
Several capture paths can fail or misbehave in realistic setups. Automatic pipeline selection on NVIDIA machines without the required capability will fail at start instead of falling back, a stalled source can lock up stop and stats requests, KMS capture can return stale frames, and rotated monitors may not negotiate. Resolve these before merging.
Pre-merge checks: 
3 · 
1 · 
1
-
Failed checks: 1 warning · 1 inconclusive Passed checks: 3 passedFull details: Docstring Coverage
-
Explanation
Docstring coverage is 18.42% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 38 functions across 11 files. (1 skipped: 1 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
Full details: Title check
-
Explanation
The title indicates a broad rewrite, but it uses informal and vague wording and does not identify the main technical changes, such as the pipeline registry, native capture pipelines, or removal of synthetic fallback.
Resolution
Replace the title with a concise, specific summary of the primary architectural change, such as "Rewrite capture architecture with native pipeline registry and KMS capture".
-
Finishing Touches
-
Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
There was a problem hiding this comment.
🔄 Devin is addressing Devin Review findings
Devin Review found 8 bugs and 1 flag on a95081e. Devin is making a first pass at them and will update this comment once it's done.
Fixed by Devin (8)
- Windows desktop handles leak across streams
- First display blocks all Windows capture
- Page flips can end KMS streams
- Automatic capture chooses unusable NVIDIA pipeline
- Linear capture emits transparent desktop pixels
- Default macOS frame rate reaches ScreenCaptureKit as zero
- Suballocated linear scanouts fail to map
- Oversized frame rate terminates capture daemon
…GB, aligned mmap, fps clamp, first-frame timeout, rotated mutter monitors Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…size Closing the sckit stream from another thread while grab sat in NextFrame freed the handle under it and the frame wait never woke, so stop-stream hung forever. grab now waits in 100 ms slices and checks a stop flag; the stream is only closed on the stream thread after grab returns. Display ids are indexes like the Linux pipelines (main display first), so display 0 works. Width/height come from the CoreGraphics display mode in pixels and the stream asks for that size, since ScreenCaptureKit's display size is in points and would downscale on Retina. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Ran
capbench's CPU line reads What was broken in
Frames are the real screen, the right way up, with the cursor. Colour swatches read back exactly: (255,0,0), (0,255,0), (0,0,255), (255,255,0), (0,0,0), white 255. The static frame vs On a static screen sckit re-delivers the last buffer at about 57/s, so a static stream keeps running at full rate (227/228 identical in the static run) instead of going quiet. The daemon grabs about 57 fps (grab_avg ~17.6 ms), but capbench only receives 35-45. The Screen Recording: nothing to grant. This VM already has it granted to its agent process, and binaries started from its shell inherit it. |
Enumerates every attached output with friendly name, desktop position and DisplayConfig refresh rate. AcquireNextFrame drives the stream (paced=false); on WAIT_TIMEOUT the last staged frame is re-sent, and ACCESS_LOST recreates the duplication. Frames are copied to a staging texture, mapped and packed to tight BGRA honoring RowPitch and output rotation. Sockets default to %TEMP% on Windows. capbench takes the media socket from the start-stream reply and reads CPU with GetProcessTimes on Windows. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Added the Windows Tested on Windows Server 2022, 1 output (IddSampleDriver, 1600x1200@60).
On the static run 285 of 286 frames were identical to the one before, so those are timeout re-sends. On the motion run it was 54 of 287, which is Chrome dropping frames on this GPU-less box. The first static run only got 39.7 fps (p50 24.4 ms). That's because AcquireNextFrame's timeout rounds to the 15.6 ms system tick. The grabber now holds Dumps converted to PNG are the real desktop and the colors are right: Not tested here: ACCESS_LOST recovery (I didn't want to trigger UAC or the lock screen on this box), rotated outputs, and multiple monitors. |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…with libav, encoded records on fd 3 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… path Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…, svt-av1 low delay CBR Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…a format drops the whole stale queue Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
AKA:
capturedv2.Summary
Rewrites captured so it captures and encodes in one process. The old design sent raw BGRA over a socket, the agent piped it into ffmpeg, ffmpeg converted it on the CPU and uploaded it back to the GPU. Now the agent spawns captured, frames stay on the GPU where the platform allows, and what comes back is encoded access units. The agent side is agent#3.
Process and protocol
list,get,set,start,stop, plus astoppednotification. Everything else is a generic property:pipeline,display,video.codec,video.encoder,video.fps,video.width,video.height,video.gop,video.preset,video.optionsvideo.bitrate(in place on NVENC and x264, a session restart elsewhere),video.keyframestate,video.active_pipeline,video.active_encoder,video.hw,video.size,stats.fps,stats.bitrate,stats.capture_avg_ms,stats.encode_avg_ms,stats.encode_max_ms,stats.dropped,stats.erroraudio.*returns "audio is not supported yet"--media fd:3(an inherited handle on Windows) as records:--listenflag and both open security findings go away with them.Encoding
av/is a cgo wrapper over libavcodec, libavutil and libswscale. It handles hw devices and frames (CUDA, VAAPI, D3D11VA, VideoToolbox), a CPU path (BGR0/BGRA straight in, or swscale), and low-latency defaults per encoder. AV1 uses SVT-AV1, since libaom can't keep up in real time.pipelines/session.goruns capture and encode on one locked OS thread.kms_nvidiazero copy: EGL import of the scanout, a GPU blit (with scaling) into an RGBA8 texture, CUDA-GL interop,cuMemcpy2Dinto the NVENC frame. Nothing goes through system RAM.pipewire_mutter,kms_linearandscreencapturekituse the CPU frame path for now.Measured on observatory (RTX 2070S, DP-1 2560x1440), with
cmd/capbench, which now spawns captured and reads the records:Decoded frames show the real desktop with the right colors and orientation, including when scaled to 1080p. Through the agent PR, an owner and a late joiner both got 60 fps, and the late joiner's first frame was a keyframe 71 ms after
start.Not done or not tested
Failed to initialise VAAPI connection), so it's untested.kms_nvidia.deinit called without sending EOSon shutdown.Link to Devin session: https://app.devin.ai/sessions/ca77b093f2c242f0a1b0cb198b049b93
Open in Devin Desktop: https://app.devin.ai/desktop/session/ca77b093f2c242f0a1b0cb198b049b93?variant=devin
Requested by: @spacedouut