Abstract: This document details the methodologies for establishing a high-performance, real-time video feed from an Android smartphone to a Raspberry Pi 5 over a wired USB connection.
Standard Wi-Fi IP cameras introduce significant latency due to network congestion and encoding buffers. To achieve near real-time performance for computer vision and tracking tasks, we utilize USB debugging (ADB), FFmpeg virtual cameras, and hardware-accelerated loops.
Before beginning, ensure your Android device has Developer Options and USB Debugging enabled. Connect your phone to the Raspberry Pi 5 via a high-speed USB cable.
You will also need an IP webcam application installed on your phone (like DroidCam) to serve the raw video data over the local device port.
To make the Raspberry Pi and OpenCV treat the phone stream as a native hardware webcam (e.g., /dev/video0), we must create a virtual Video4Linux (v4l2) loopback device.
Run the following commands on your Raspberry Pi 5 to install the Android Debug Bridge, FFmpeg, and the virtual camera drivers:
sudo apt update
sudo apt install adb ffmpeg v4l2loopback-dkms v4l2loopback-utils -yLoad the v4l2loopback kernel module to create a dummy video device. We will force it to register as /dev/video0.
sudo modprobe v4l2loopback video_nr=0 card_label="Android_USB_Cam" exclusive_caps=1(Note: exclusive_caps=1 is required for many OpenCV and Chrome/WebRTC applications to recognize the virtual camera properly).
To bypass Wi-Fi entirely, we map the phone's internal streaming port directly to the Raspberry Pi's local port over the USB cable. Assuming your phone app (like DroidCam) streams on port 4747:
# Verify the device is connected
adb devices
# Forward the TCP port over USB
adb forward tcp:4747 tcp:4747Now, we pull the video stream from the forwarded local port and inject it into our virtual camera. To achieve the absolute lowest latency possible for YOLO inference, we must aggressively disable FFmpeg's internal buffering:
ffmpeg -fflags nobuffer -flags low_delay -analyzeduration 0 -probesize 32 \
-i http://localhost:4747/video \
-f v4l2 -pix_fmt yuv420p /dev/video0The video feed is now accessible to our C++ YOLO pipeline at /dev/video0!
Machine learning models (such as YOLO26) often require square input tensors. Since phone cameras natively output 4:3 or 16:9 aspect ratios, you can use FFmpeg's video filter (-vf) to crop a perfect square directly from the center of the feed before it even reaches your C++ code.
First, set your phone app's resolution to at least 720p (1280x720) to ensure sufficient pixel density. Then, execute the FFmpeg pipeline with the crop parameter:
ffmpeg -fflags nobuffer -flags low_delay -analyzeduration 0 -probesize 32 \
-i http://localhost:4747/video \
-vf "crop=640:640" \
-f v4l2 -pix_fmt yuv420p /dev/video0It is critical not to confuse the -pix_fmt yuv420p flag with a 480p resolution. yuv420p simply defines the YUV color space and chroma subsampling format required by the v4l2 virtual camera driver. Resolution is dictated exclusively by the source application settings or FFmpeg scaling filters.
- CPU Bottlenecks: FFmpeg software decoding generates significant CPU load and heat. While the Raspberry Pi 5 handles this well, if you attempt to run this pipeline on older hardware (like a Raspberry Pi 3 or 4), you must maintain lower source resolutions (480p) to prevent thermal throttling.
- Cable Quality: Always use a high-throughput, data-capable USB-C cable. Cheap charging cables will drop packets and cause FFmpeg to stutter, artificially lowering your YOLO inference FPS.