Turn your old Android phone into a low-latency USB webcam for OBS Studio.
Two parts:
- Android app (
app/) — Camera2-based capture that publishes JPEG frames over the network on two ports:- 4748 — raw TCP, length-prefixed frames (low latency)
- 4747 — MJPEG over HTTP (works with OBS Media Source, browsers, VLC, etc.)
- Native OBS plugin (
obs-plugin/native/) — A C plugin that decodes the stream directly into OBS as an async video source. Ships with bundledadbbinaries so USB mode "just works" without manual port-forwarding.
- Camera2 capture with selectable resolution and 15/24/30/60 FPS
- Front and back cameras, torch, ring-light overlay (front camera, with brightness slider)
- Tap-to-focus, autofocus on/off, AE lock, exposure compensation
- Auto-rotation that re-orients the JPEG stream to match the device
- Wake lock so the phone never sleeps mid-stream
- Slide-out drawer UI so the camera preview fills the screen
- Can be launched as a HOME app
- Two transports running simultaneously: HTTP MJPEG (4747) and raw TCP (4748)
- Black-screen mode (privacy)
- ADB and Wi-Fi both supported
- Native C plugin (no Python script, no Media Source hacks)
- Three connection modes selectable per source:
- USB (auto-forward via ADB) — bundled adb runs
adb forwardfor you - Wi-Fi — Raw TCP (low latency)
- Wi-Fi — HTTP MJPEG (legacy)
- USB (auto-forward via ADB) — bundled adb runs
- Sub-50 ms latency in raw TCP mode (TCP_NODELAY, no MJPEG re-encoding overhead)
- Auto-reconnect
- Cleans up
adbon OBS exit (adb kill-serverinobs_module_unload) - Source appears in OBS's + picker as "Android USB Cam" with the camera icon
Grab app-debug.apk from the latest dev-latest
release and sideload it. Grant camera permission, tap Start.
Grab obs-android-usbcam-installer.exe from the same release and run it. It
auto-detects your OBS install directory.
- + in the Sources dock → Android USB Cam
- Default mode is USB. Plug the phone in, enable USB debugging, tap Start in the app, click OK in OBS. You should see the feed within a second.
For Wi-Fi mode: switch the Connection dropdown to one of the Wi-Fi options and type the phone's IP into the Host field. The Android app's status bar shows both URLs.
./gradlew assembleDebug
# → app/build/outputs/apk/debug/app-debug.apkCI builds and uploads the APK to the dev-latest pre-release on every push to
claude/**.
sudo apt install libobs-dev cmake build-essential
cd obs-plugin/native
cmake -B build -DLIBOBS_INCLUDE_DIR=/usr/include/obs
cmake --build build -j$(nproc)
sudo cp build/obs-android-usbcam.so /usr/lib/x86_64-linux-gnu/obs-plugins/The Windows build is heavyweight because it goes through the official
obs-plugintemplate CI
flow to fetch prebuilt obs-deps and qt6. Easiest is to let GitHub Actions do
it — see .github/workflows/build-obs-plugin.yml.
"ACAM" (4 bytes magic, sent once on connect)
[uint32 BE size][JPEG data] (repeating, big-endian frame size)
Single client at a time. The Android side closes the previous session when a new client connects.
Standard multipart/x-mixed-replace; boundary=frame. The plugin parses it by
scanning for JPEG SOI (FF D8) / EOI (FF D9) markers, so any boundary string
works.
android-obs-streamer/
├── app/ Android Kotlin app (Camera2)
│ └── src/main/java/com/example/usbcam/
│ ├── MainActivity.kt UI, drawer, wake lock, orientation
│ ├── CameraStreamer.kt Camera2 wrapper, JPEG rotation, AE/AF
│ ├── MjpegServer.kt HTTP server on 4747
│ ├── StreamSession.kt HTTP multipart writer
│ └── RawStreamServer.kt Raw TCP server on 4748
├── obs-plugin/
│ ├── native/ C plugin (the real one)
│ │ ├── src/plugin.c Main plugin source
│ │ ├── src/stb_image.h Bundled JPEG decoder
│ │ ├── installer/installer.nsi NSIS installer (Windows)
│ │ └── CMakeLists.txt
│ └── android-usbcam.py (legacy Python script, kept for reference)
└── .github/workflows/
├── build.yml Android APK build
└── build-obs-plugin.yml Linux .so + Windows .dll + installer
MIT.