A native Linux app for OBSBOT webcams. Adjust image, exposure and framing while your video stays in the app that is using it.
Controlling a real OBSBOT Meet SE on Fedora. No preview open, no capture: the picture stays with your meeting app.
OBSBOT ships its Center app for Windows and macOS only. On Linux the cameras still expose every standard control through the kernel's UVC driver, and this app gives them a proper front end: a Material 3 desktop workspace, a command-line tool, and a small D-Bus broker that keeps writes safe. No vendor SDK, no account, no cloud, no telemetry, and the microphone is never opened.
Unofficial. This project is not affiliated with or endorsed by OBSBOT. It uses only the public V4L2 interface. Vendor features that need the proprietary toolkit (subject tracking, HDR modes, gestures) are out of scope until an audited adapter exists. See What it does not do.
- Speaks your language, not the driver's. Shutter speed as
1/33 s · 30.6 ms, white balance in kelvin, pan and tilt in degrees. Raw driver names, IDs and ranges are one hover away. - Every change is confirmed. Each write is read back from the camera before it is reported. The status bar names the control and the confirmed value, and one click (or Ctrl+Z) undoes it.
- Automatic modes where they belong. Auto white balance and autofocus are a switch directly above the value they gate. Exposure mode is a row of chips; Manual unlocks the shutter.
- Control without capture. The app never opens the video stream unless you press Start preview, so a call in Zoom, Meet or OBS keeps the camera.
- Local video effects and virtual camera. Person background removal/replacement/blur, video denoising, and ML depth-guided relighting. Preview the result and publish it through v4l2loopback. Optional models and setup are in docs/EFFECTS.md; an optional NVIDIA CUDA backend provides recurrent video matting and GPU processing.
- Optional live preview. Direct V4L2 through GStreamer, with the pixel format, resolution and frame rate the camera advertises, and a delivered-fps readout.
- Profiles that are reviewed, never guessed. Bundled presets (Neutral image, Warm, Bright room) and your own JSON profiles open a before → after review. Only Apply writes, in dependency order, stopping at the first failure. Nothing is restored behind your back.
- Framing helpers. Zoom, pan and tilt sliders plus a nudge pad and a centre button.
- Diagnostics you can paste into an issue. Redacted report (no serial, no frames) with a copy button.
- Your look. Light, dark or system, and seven accent colours (Teal by default, Monochrome, Blue, Green, Coral, Amber, Purple). Rail, window size and last area are remembered.
- Keyboard first. Ctrl+1…6 for areas, arrows step the focused slider, F1 lists everything.
- A CLI and a simulated camera for scripts, packaging and development without hardware.
Verified on the OBSBOT Meet SE (USB 3564:fefe): discovery, all 22 reported controls, readback, coexistence with another V4L2 client and with Chrome, profiles, and a preview soak. Details and limits are in docs/VALIDATION.md and docs/MEET-SE-DIAGNOSTIC.md.
Other OBSBOT models that present standard UVC controls (Meet, Meet 2, Tiny series) should work for the same controls, because nothing here is model specific. They have not been tested; please open an issue with obsbot-cli diagnose output.
Dependencies on Fedora:
sudo dnf install gcc-c++ cmake ninja-build qt6-qtbase-devel qt6-qtdeclarative-devel \
opencv-devel gstreamer1-devel gstreamer1-plugins-base-devel gstreamer1-plugins-good-qt6 \
dbus-daemon python3On Debian and Ubuntu the equivalents are build-essential cmake ninja-build qt6-base-dev qt6-declarative-dev qml6-module-qtquick-controls qml6-module-qtquick-layouts qml6-module-qtquick-dialogs qml6-module-qtcore libopencv-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-qt6 dbus python3 (not yet verified on those distributions).
Then:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build
ctest --test-dir build --output-on-failure
sudo cmake --install buildPreview needs GStreamer; to build a control-only binary without it add -DENABLE_PREVIEW=OFF. An RPM can be produced with cpack --config build/CPackConfig.cmake -B dist, and a conventional spec lives in packaging/.
obsbot-manager # the desktop app
obsbot-cli list # cameras the broker sees
obsbot-cli inspect DEVICE_ID # every control with range, flags and current value
obsbot-cli diagnose DEVICE_ID # redacted capability reportRun as your normal desktop user, never as root. If no camera appears, check that your session owns /dev/video*; see docs/TROUBLESHOOTING.md.
The window is a navigation rail, a preview stage and one inspector column.
| Area | What you do there |
|---|---|
| Image | Brightness, contrast, saturation, sharpness, hue, backlight, anti-flicker. Reset image reviews the driver defaults first. |
| Framing | Zoom, pan and tilt in degrees, nudge pad, centre. |
| Exposure | Mode chips, shutter, gain, white balance and focus with their Auto switches. |
| Output | Local video effects, virtual camera, pixel format, resolution and frame rate; start or restart output. |
| Profiles | Presets and JSON profiles, each reviewed before Apply. Save the current settings to a file. |
| Diagnostics | Redacted facts, copy or save the report, raw JSON on request. |
| Settings | System / light / dark, accent colour, rail, driver details, preview on select. |
Keyboard: Ctrl+1…6 areas · Ctrl+, settings · ↑ ↓ ← → step the focused control · Ctrl+Z undo · F5 read values · Ctrl+R rescan · Ctrl+P preview · F11 full screen · Ctrl+T appearance · F1 this list.
obsbot-cli export DEVICE_ID ~/camera/studio.json # save writable settings
obsbot-cli diff DEVICE_ID ~/camera/studio.json # what would change (read-only)
obsbot-cli apply DEVICE_ID ~/camera/studio.json # write, in dependency order, confirm each
obsbot-cli set DEVICE_ID 0x00980900 42 # one raw controlset and apply change the physical camera and may affect other clients; review with diff first. Profiles are bound to the device identity and rejected when foreign, future or malformed.
obsbot-manager (Qt Quick GUI) ─┐
├─ session D-Bus ─► obsbot-broker ─► V4L2 ioctls
obsbot-cli (scripts, tests) ─┘ (one write at a time,
readback, generations, deadlines)
- camera-core enumerates V4L2 extended controls and formats, applies conservative semantics (dependencies, non-writable continuous motion, out-of-range detection) and offers a deterministic fake camera.
- obsbot-broker owns the device. Every write carries a device generation and a deadline, is validated against the descriptor, executed once, and read back. Nothing is retried or replayed.
- camera-client is shared by the GUI and CLI: asynchronous requests, one in flight, undo of the last confirmed write, profile review and apply.
- The GUI is QML in the Material style. Rows commit on release, not at pointer rate, so the broker contract holds.
Full detail in docs/ARCHITECTURE.md, docs/CAPABILITIES.md and docs/DESIGN.md.
- No subject tracking, HDR modes or gesture control. Those live behind OBSBOT's proprietary toolkit, which this project does not load or redistribute. The boundary and a static audit of the SDK are described in docs/SDK.md.
- No conversions it cannot verify. Zoom is shown in the camera's own steps, not as a multiplier; gain is not translated to ISO.
- No silent writes. Selecting a camera reads its descriptor and nothing else. Profiles never apply on selection. State is not restored on exit.
- Preview is experimental. A one-hour soak stopped after about 41 minutes for a reason that is still open; control never depends on it.
obsbot-manager --simulate # fake Meet SE, four controls
OBSBOT_SIMULATED_SCENARIO=full obsbot-manager --simulate # Meet SE-shaped inventory and formats
OBSBOT_SIMULATED_SCENARIO=empty … # no camera
OBSBOT_SIMULATED_SCENARIO=denied … # permission denied
obsbot-manager --simulate --tab 2 --qa-dark --screenshot out.png # offscreen capture of an areaTests run under a private D-Bus session and never touch hardware: ctest --test-dir build. Hardware and browser coexistence scripts under tests/ take an explicit device ID and are opt-in. -DENABLE_SANITIZERS=ON builds with ASan and UBSan.
The interface was designed as three Material 3 Expressive proposals in M3E Canvas; the app implements proposal A (Studio). The design notes and the roadmap for the next steps are in docs/UX-ROADMAP.md.
src/ camera-core, broker, shared client, CLI, GUI entry point, GStreamer preview
qml/ Main.qml (Studio shell), NavRail, ControlRow, M3Button, Theme with accents
tests/ deterministic C++ and Python tests; opt-in hardware scripts
scripts/ diagnostics, measurements, SBOM, SDK static audit
docs/ architecture, capabilities, validation, design, troubleshooting, evidence
packaging/ desktop launcher, D-Bus activation, RPM spec
Issues with obsbot-cli diagnose DEVICE_ID output are the most useful thing you can send, especially for models other than the Meet SE. Pull requests should keep the rules above: writes confirmed by readback, review before apply, no vendor binaries, no unverified conversions. Run ctest before opening one.
MIT. See LICENSE. Third-party notices are in docs/LICENSES.md and licenses/.




