apps: add Unix Domain Socket for runtime camera control in rpicam-vid#914
Closed
Kletternaut wants to merge 2 commits into
raspberrypi:mainraspberrypi/rpicam-apps:mainfrom
Kletternaut:feature/runtime-control-socketKletternaut/rpicam-apps:feature/runtime-control-socketCopy head branch name to clipboard
Closed
apps: add Unix Domain Socket for runtime camera control in rpicam-vid#914Kletternaut wants to merge 2 commits intoraspberrypi:mainraspberrypi/rpicam-apps:mainfrom Kletternaut:feature/runtime-control-socketKletternaut/rpicam-apps:feature/runtime-control-socketCopy head branch name to clipboard
Kletternaut wants to merge 2 commits into
raspberrypi:mainraspberrypi/rpicam-apps:mainfrom
Kletternaut:feature/runtime-control-socketKletternaut/rpicam-apps:feature/runtime-control-socketCopy head branch name to clipboard
Conversation
Kletternaut
force-pushed
the
feature/runtime-control-socket
branch
13 times, most recently
from
May 12, 2026 09:04
df9237a to
f1d4c95
Compare
Kletternaut
force-pushed
the
feature/runtime-control-socket
branch
from
May 12, 2026 13:55
f1d4c95 to
071511e
Compare
Kletternaut
force-pushed
the
feature/runtime-control-socket
branch
from
May 14, 2026 05:58
9a88020 to
aa3673c
Compare
Adds a Unix Domain Socket server to rpicam-vid that accepts text commands at runtime, allowing camera parameters to be changed without restarting the process. The socket path is derived from the camera index, e.g. --camera 1 uses /tmp/rpicam-vid1.sock (default: /tmp/rpicam-vid0.sock). Supported commands include: brightness, ev, contrast, saturation, gain (0 = AE auto, >0 = manual), sharpness, roi, awb, awbgains, metering, exposure, denoise, hdr, shutter, camera. Two client tools are provided: - utils/rpicam-vid-tui: curses-based TUI with sliders and combos - utils/rpicam_vid_gui/: Qt GUI with sliders, combos and reset button gain:0 restores AnalogueGainModeAuto so connecting the GUI at default settings does not override AE-controlled gain or an active --roi. Signed-off-by: Kletternaut <tomge68@gmail.com>
Kletternaut
force-pushed
the
feature/runtime-control-socket
branch
from
May 15, 2026 09:31
aa3673c to
2bedc97
Compare
- control_socket.hpp: HasNewClient/ClearNewClient/SendToClient - rpicam_vid.cpp: send caps:maxfps=N,hasaf=0|1 after ConfigureVideo - rpicam_vid_gui: integer fps (1 fps steps), log-scale shutter, auto-select cam1 via socket check, clamp slider from caps - rpicam-vid-tui: rewrite matching GUI; shutter/framerate sliders, caps polling, auto-select cam1, GUI-compatible state format - utils/README: caps protocol, shutter/framerate cmds, AF note - README: shutter/framerate cmds, GUI/TUI features, AF note Signed-off-by: Kletternaut <tomge68@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Demo Video
A demo video showing the Qt5 GUI and TUI controlling a live
rpicam-vidstream in real time is attached.rpicam-vid-gui.mp4
Motivation
Several camera controls — brightness, contrast, saturation, exposure compensation, AWB mode, AWB gains, ROI/digital zoom and HDR mode — are currently only applied at startup. Applications that embed
rpicam-vid(e.g. GUI front-ends) must restart the process to change these values, causing stream interruption.This patch eliminates that requirement.
Implementation
A new
ControlSocketclass (apps/control_socket.hpp) listens on a UNIX stream socket. The socket path is derived automatically from the--cameraindex: camera 0 uses/tmp/rpicam-vid0.sock, camera 1 uses/tmp/rpicam-vid1.sock. This allows tworpicam-vidinstances to run simultaneously with independent control sockets.Commands are plain text, newline-terminated, in the form
key:value:Multiple commands can be sent in a single write. The socket is
SOCK_NONBLOCKthroughout — it never blocks the capture loop. Insideevent_loop()inrpicam_vid.cpp,AcceptConnections()andReadControls()are called once per frame and the resultingControlListis passed to the existingSetControls()API.A
SupportsScalerCrops()helper is added toRPiCamAppto detect at runtime whether the attached camera supports the PISP multi-channel crop control (rpi::ScalerCrops). This is more reliable than platform detection — sensors like imx477 on Pi 5 use the legacyScalerCroppath even though the platform is PISP. ROI commands use whichever control the camera actually supports.Supported commands
brightnessevcontrastsaturationsharpnessgainAnalogueGainModeManualautomatically)awbauto|incandescent|tungsten|fluorescent|indoor|daylight|cloudyawbgainsroimeteringcentre|spot|average|customexposurenormal|sportdenoiseauto|off|cdn_off|cdn_fast|cdn_hqhdroff|auto|sensor|single-expExtensibility
ControlSocketis implemented as a self-contained header (apps/control_socket.hpp) with no dependency onrpicam-vid-specific code. Integrating it into any other rpicam-app (rpicam-still,rpicam-jpeg,rpicam-raw, …) requires only three lines in that app's event loop: construct the socket with the desired path, callAcceptConnections()andReadControls()once per frame, and pass the returnedControlListtoSetControls(). The command vocabulary and wire format are identical regardless of which app hosts the socket.Per-camera state persistence
Both reference implementations (GUI and TUI) maintain independent state per camera index and persist it to
/tmp/rpicam-vid{N}.state(JSON). This ensures:rpicam-vidstarted a new session), defaults are shown and sent.Session isolation
ControlSocketdeletes the companion.statefile both on construction (beforebind()) and in its destructor (alongside the.sockfile). This guarantees that every newrpicam-vidsession starts from hardware defaults, independent of what a previous session had set.rpicam_vid.cppnow catchesSIGTERM(in addition to the existingSIGINT) and routes it through the normal event-loop exit path. This ensures theControlSocketdestructor runs — and both.sockand.statefiles are cleaned up — whenrpicam-vidis stopped viasystemctl stop,pkill, orkill. (SIGKILLcannot be caught; the constructor-time delete of any stale files serves as a fallback.)State file format
{ "brightness": 0, "ev": 0, "contrast": 100, "saturation": 100, "zoom": 10, "gain": 10, "sharpness": 10, "awbGainR": 150, "awbGainB": 120, "awbIdx": 0, "meteringIdx": 0, "exposureIdx": 0, "denoiseIdx": 0, "hdrIdx": 0 }Values are stored as integers scaled to the slider resolution. The format is identical between GUI and TUI.
Compatibility
SetControls()API.bind()fails, a warning is logged andrpicam-vidcontinues normally without socket support.std::locale::classic()explicitly.SOCK_NONBLOCKandaccept4()throughout — the capture loop is never stalled.AWB correctness
awb:<mode>explicitly sendsAwbEnable=truealongside the mode, andawbgains:<r>,<b>sendsAwbEnable=false. This prevents libcamera from retaining staleColourGainsstate when switching between manual and auto AWB.ev:<value>explicitly sendsAeEnable=trueto ensure the exposure compensation is applied even when the auto-exposure pipeline is in a particular state.HDR modes
Only
HdrModeOffandHdrModeSingleExposureare functional on imx477 at runtime. Thehdr:command acceptsoff|auto|sensor|single-exp, matching the rpicam-apps CLI convention (bothautoandsensormap toHdrModeSingleExposure).Multi-camera support
Two
rpicam-vidinstances can run simultaneously on separate cameras. Each gets its own socket derived from the--cameraindex:Both
rpicam-vid-tuiandrpicam-vid-guisupport switching between cameras at runtime without restarting the tool.Files changed
apps/control_socket.hppControlSocketclass; deletes companion.statefile on init/destroyapps/rpicam_vid.cpp--cameraindex; per-frame poll;SIGTERMhandlercore/rpicam_app.hppSupportsScalerCrops()declarationcore/rpicam_app.cppSupportsScalerCrops()implementationmeson.buildutils/subdir addedmeson_options.txtenable_control_guioptionutils/meson.buildrpicam_vid_guisubdirutils/rpicam_vid_gui/meson.buildrpicam-vid-guiutils/rpicam_vid_gui/main.cpputils/rpicam-vid-tuiutils/README.mdREADME.mdUsage
Reference implementations
Qt control panel —
utils/rpicam_vid_gui/(rpicam-vid-gui)A Qt6/Qt5 GUI with sliders for all continuous parameters, dropdowns for AWB / metering / exposure / denoise / HDR, and manual AWB R/B gain sliders. A camera selector switches between camera 0 and camera 1 at runtime. Connects automatically and reconnects if
rpicam-vidis restarted.Keyboard shortcuts:
Rreset,Qquit,Cswitch camera.Build via Meson (requires Qt6 or Qt5 Widgets + Network):
Terminal UI —
utils/rpicam-vid-tuiASCII slider interface in pure Python 3 (no dependencies beyond stdlib
curses).↑/↓←/→CRQ