Skip to content

Vision-Orchestration/DroidGrid

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

DroidGrid

Turn any number of Android phones running DroidCam into a synchronized multi-camera studio β€” preview, record, and snapshot from a single Python script.


Python OpenCV Platform License Stars


Overview

DroidGrid is a lightweight desktop controller for DroidCam. Connect several Android phones to the same Wi-Fi network, run one script, and you immediately get:

  • A tiled live preview of all streams in one window
  • Simultaneous recording to separate .mp4 files per camera
  • Instant JPEG snapshots from all cameras with one key
  • Auto-reconnect when a stream drops or freezes β€” no babysitting required
  • An inline session editor to label recordings without touching the terminal

No external server, no cloud, no paid subscriptions. Just phones, Wi-Fi, and Python.


Feature Overview

Feature Detail
πŸ“Ί Live grid preview Up to 10 phones in a tiled 3-column layout
🎬 Simultaneous recording Each camera writes its own .mp4 independently
πŸ“· Snapshot (T) One JPEG per camera, saved instantly
πŸ” Self-healing streams Frozen-frame detection via MD5 hash + auto-reconnect
⚑ Non-blocking I/O Dedicated write-queue thread per camera
🏷️ Inline session editor Change label/person/repeat inside the preview window
πŸ“ Custom naming pattern {label} {person} {repeat} {camera} {date} {time}
πŸ“Š Live HUD Per-cell FPS, frame counter, drop counter, REC badge

Requirements

On your PC:

pip install opencv-python numpy

On each Android phone:

  • Install DroidCam (free)
  • Connect to the same Wi-Fi network as your PC
  • Open DroidCam β€” the IP address is shown on screen

Quick Start

1. Clone

git clone https://github.com/Vision-Orchestration/DroidGrid.git
cd DroidGrid
pip install -r requirements.txt

2. Configure cameras

Open droidgrid.py and edit the CAMERAS list at the top:

CAMERAS = [
    {"name": "Phone-1", "ip": "192.168.1.101", "port": 4747, "res": (1280, 720), "fps": 30},
    {"name": "Phone-2", "ip": "192.168.1.102", "port": 4747, "res": (1280, 720), "fps": 30},
    {"name": "Phone-3", "ip": "192.168.1.103", "port": 4747, "res": (1280, 720), "fps": 30},
    # add more as needed
]

Performance tip: For 5+ cameras, use "fps": 20 and "res": (960, 540) for smoother operation on standard hardware.

3. Run

python droidgrid.py

The preview window opens. Connected cameras appear immediately. Disconnected ones show an OFFLINE placeholder and reconnect automatically.


Keyboard Controls

Key Action
R Start recording on all connected cameras
S Stop recording β€” files saved, repeat counter auto-advances
T Snapshot β€” one JPEG per camera saved to snapshots/
G Set session label (opens inline prompt)
P Set person ID
N Set repeat number
C Reconnect all cameras
H Toggle HUD overlay
Q Quit

All prompts appear as an overlay inside the preview window β€” no terminal input needed.


Output Structure

DroidGrid/
β”œβ”€β”€ recordings/
β”‚   β”œβ”€β”€ walk_p01_r01_Phone-1.mp4
β”‚   β”œβ”€β”€ walk_p01_r01_Phone-2.mp4
β”‚   └── walk_p01_r01_Phone-3.mp4
└── snapshots/
    β”œβ”€β”€ walk_p01_r01_Phone-1_20250421_143022.jpg
    β”œβ”€β”€ walk_p01_r01_Phone-2_20250421_143022.jpg
    └── walk_p01_r01_Phone-3_20250421_143022.jpg

Files are never overwritten β€” if a path already exists, a numeric suffix is appended automatically.

Naming pattern

Configured via NAMING_PATTERN in droidgrid.py:

NAMING_PATTERN = "{label}_{person}_{repeat}_{camera}"

Available tokens: {label} {person} {repeat} {camera} {date} {time}


Architecture

Main thread β€” UI rendering loop (30 fps display)
β”‚
β”œβ”€β”€ Camera-1 ──► Capture thread ──► Queue ──► Writer thread ──► .mp4
β”œβ”€β”€ Camera-2 ──► Capture thread ──► Queue ──► Writer thread ──► .mp4
β”œβ”€β”€ Camera-3 ──► Capture thread ──► Queue ──► Writer thread ──► .mp4
└── ...

Capture thread β€” reads frames, detects freezes, reconnects on failure
Writer thread β€” drains the queue to disk, completely independent of display
Main thread β€” builds the grid and handles keyboard events only, never blocks on I/O

Self-healing logic

Failure mode Detection Response
Stream drop cap.read() fails 10Γ— Reconnect after 2 s
Frozen stream MD5 hash identical for 60+ frames Immediate reconnect

Configuration Reference

All settings live at the top of droidgrid.py:

RECORD_DIR       = "recordings"                          # video output folder
SNAPSHOT_DIR     = "snapshots"                           # snapshot output folder
NAMING_PATTERN   = "{label}_{person}_{repeat}_{camera}"  # file naming tokens
CELL_W           = 640     # preview cell width (px)
CELL_H           = 360     # preview cell height (px)
CODEC            = "mp4v"  # video codec fourcc (mp4v / MJPG / XVID)
FREEZE_THRESHOLD = 60      # identical frames before reconnect
RECONNECT_DELAY  = 2.0     # seconds between reconnect attempts

Troubleshooting

Camera shows OFFLINE immediately

  • Confirm the IP shown in DroidCam matches the one in CAMERAS
  • Confirm both devices are on the same Wi-Fi (not guest network)
  • Check that Windows Firewall / antivirus is not blocking port 4747
  • Try opening http://<phone-ip>:4747/mjpegfeed in a browser β€” if you see a video, the URL works

Frames are dropping / stream is laggy

  • Switch to a 5 GHz Wi-Fi network
  • Lower fps to 20 and res to (960, 540) per camera
  • Reduce CELL_W / CELL_H to decrease display load

Video files are empty or won't open

  • Try changing CODEC from "mp4v" to "MJPG" and use .avi extension
  • Check disk space

Frozen stream not detected

  • Lower FREEZE_THRESHOLD (default 60) if you want faster detection
  • Higher values reduce false reconnects on slow networks

FAQ

Q: Does it work with RTSP cameras (not just DroidCam)?
Yes. Set "ip" to the full RTSP URL and "port" to None, then adjust the url property in the Camera class to return self.ip directly.

Q: DroidCam free vs paid β€” which do I need?
The free version works fully. Paid removes the watermark and allows higher resolutions.

Q: How many phones can I use at once?
Tested up to 5 phones at 1280Γ—720 / 30fps on mid-range hardware (RTX 3070 + Ryzen 7). For 10 phones, use 960Γ—540 and 20fps.

Q: Can I use this for research / dataset collection?
Yes β€” that's exactly what it was built for. The naming pattern ({label}_{person}_{repeat}_{camera}) is designed for structured dataset recording.


Contributing

Issues and pull requests are welcome.

  1. Fork the repo
  2. Create a branch: git checkout -b feature/my-feature
  3. Commit your changes with a clear message
  4. Open a pull request

License

MIT β€” free for personal, academic, and commercial use.


Part of the Vision-Orchestration toolkit.

Built with OpenCV. No cloud. No subscriptions. Just cameras.

About

Multi-phone DroidCam controller for live preview, recording, snapshots, and auto-reconnect

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages