#!/bin/bash # Setup script for V4L2 loopback virtual camera # Used for testing camera simulation on Linux systems set -e echo "===============================================" echo "V4L2 Loopback Virtual Camera Setup" echo "===============================================" # Check if running on Linux if [[ "$OSTYPE" != "linux-gnu"* ]]; then echo "Error: This script only works on Linux systems" echo "For macOS, consider using OBS Virtual Camera or similar" exit 1 fi # Check for root privileges if [[ $EUID -ne 0 ]]; then echo "This script must be run as root (use sudo)" exit 1 fi # Function to check if a command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Install v4l2loopback if not present install_v4l2loopback() { echo "Installing v4l2loopback..." if command_exists apt-get; then # Debian/Ubuntu apt-get update apt-get install -y v4l2loopback-dkms v4l2loopback-utils v4l-utils ffmpeg elif command_exists yum; then # RHEL/CentOS/Fedora yum install -y kmod-v4l2loopback v4l-utils ffmpeg elif command_exists pacman; then # Arch Linux pacman -S --noconfirm v4l2loopback-dkms v4l-utils ffmpeg else echo "Error: Unsupported package manager" echo "Please install v4l2loopback manually" exit 1 fi } # Check if v4l2loopback module is available if ! modinfo v4l2loopback >/dev/null 2>&1; then echo "v4l2loopback not found. Installing..." install_v4l2loopback fi # Check if FFmpeg is installed if ! command_exists ffmpeg; then echo "FFmpeg not found. Installing..." if command_exists apt-get; then apt-get install -y ffmpeg elif command_exists yum; then yum install -y ffmpeg elif command_exists pacman; then pacman -S --noconfirm ffmpeg fi fi # Remove existing v4l2loopback module if loaded if lsmod | grep -q v4l2loopback; then echo "Removing existing v4l2loopback module..." modprobe -r v4l2loopback fi # Load v4l2loopback module with specific parameters echo "Loading v4l2loopback module..." modprobe v4l2loopback \ devices=2 \ video_nr=10,11 \ card_label="Meteor Cam 1","Meteor Cam 2" \ exclusive_caps=1 # Verify devices were created echo "" echo "Checking virtual devices..." if [[ -e /dev/video10 ]] && [[ -e /dev/video11 ]]; then echo "✅ Virtual cameras created successfully:" echo " - /dev/video10 (Meteor Cam 1)" echo " - /dev/video11 (Meteor Cam 2)" else echo "❌ Failed to create virtual cameras" exit 1 fi # Set permissions for non-root access chmod 666 /dev/video10 /dev/video11 # List all video devices echo "" echo "Available video devices:" v4l2-ctl --list-devices # Show device capabilities echo "" echo "Virtual camera capabilities:" v4l2-ctl -d /dev/video10 --all | head -20 # Create test video if it doesn't exist TEST_VIDEO_DIR="/tmp/meteor_test_videos" TEST_VIDEO="$TEST_VIDEO_DIR/meteor_test.mp4" if [[ ! -f "$TEST_VIDEO" ]]; then echo "" echo "Creating test video..." mkdir -p "$TEST_VIDEO_DIR" # Generate a test video with synthetic meteor events ffmpeg -f lavfi -i testsrc2=size=1280x720:rate=30 \ -f lavfi -i sine=frequency=1000:duration=10 \ -t 10 \ -vf "drawtext=text='Meteor Test Video':fontsize=30:fontcolor=white:x=(w-text_w)/2:y=50" \ -c:v libx264 -preset fast \ -y "$TEST_VIDEO" 2>/dev/null echo "✅ Test video created: $TEST_VIDEO" fi # Function to stream video to virtual camera stream_to_camera() { local video_file=$1 local device=$2 local label=$3 echo "" echo "Starting stream to $device ($label)..." echo "Command: ffmpeg -re -i \"$video_file\" -f v4l2 -pix_fmt yuv420p \"$device\"" echo "" echo "Press Ctrl+C to stop the stream" # Stream video to virtual camera (loop infinitely) ffmpeg -re -stream_loop -1 -i "$video_file" \ -f v4l2 \ -pix_fmt yuv420p \ -vf "scale=1280:720,drawtext=text='$label - %{localtime}':fontsize=20:fontcolor=white:x=10:y=10" \ "$device" 2>/dev/null & local pid=$! echo "Stream PID: $pid" # Save PID for cleanup echo $pid > "/tmp/meteor_cam_stream_$(basename $device).pid" return 0 } # Function to stop all streams stop_streams() { echo "" echo "Stopping all streams..." for pidfile in /tmp/meteor_cam_stream_*.pid; do if [[ -f "$pidfile" ]]; then pid=$(cat "$pidfile") if kill -0 "$pid" 2>/dev/null; then kill "$pid" echo "Stopped stream PID: $pid" fi rm "$pidfile" fi done } # Parse command line arguments ACTION=${1:-help} case "$ACTION" in start) VIDEO_FILE=${2:-$TEST_VIDEO} DEVICE=${3:-/dev/video10} if [[ ! -f "$VIDEO_FILE" ]]; then echo "Error: Video file not found: $VIDEO_FILE" exit 1 fi stream_to_camera "$VIDEO_FILE" "$DEVICE" "Meteor Cam" ;; start-all) VIDEO_FILE=${2:-$TEST_VIDEO} if [[ ! -f "$VIDEO_FILE" ]]; then echo "Error: Video file not found: $VIDEO_FILE" exit 1 fi stream_to_camera "$VIDEO_FILE" "/dev/video10" "Meteor Cam 1" stream_to_camera "$VIDEO_FILE" "/dev/video11" "Meteor Cam 2" echo "" echo "Both virtual cameras are now streaming" echo "You can test them with:" echo " cargo run -- --camera-source v4l2:/dev/video10" echo " cargo run -- --camera-source v4l2:/dev/video11" ;; stop) stop_streams ;; status) echo "Virtual camera status:" echo "" if lsmod | grep -q v4l2loopback; then echo "✅ v4l2loopback module loaded" else echo "❌ v4l2loopback module not loaded" fi echo "" echo "Active streams:" for pidfile in /tmp/meteor_cam_stream_*.pid; do if [[ -f "$pidfile" ]]; then pid=$(cat "$pidfile") if kill -0 "$pid" 2>/dev/null; then device=$(basename "$pidfile" .pid | sed 's/meteor_cam_stream_//') echo " - Stream to /dev/$device (PID: $pid)" fi fi done ;; unload) stop_streams echo "Unloading v4l2loopback module..." modprobe -r v4l2loopback echo "✅ Module unloaded" ;; help|*) echo "" echo "Usage: $0 [command] [options]" echo "" echo "Commands:" echo " start [video_file] [device] - Start streaming to a virtual camera" echo " Default: $TEST_VIDEO to /dev/video10" echo " start-all [video_file] - Start streaming to all virtual cameras" echo " stop - Stop all active streams" echo " status - Show virtual camera status" echo " unload - Stop streams and unload module" echo " help - Show this help message" echo "" echo "Examples:" echo " $0 start # Start with test video" echo " $0 start meteor.mp4 # Use custom video" echo " $0 start meteor.mp4 /dev/video11 # Specific device" echo " $0 start-all meteor.mp4 # Stream to all devices" echo " $0 stop # Stop all streams" echo "" echo "Test with meteor edge client:" echo " cargo run -- --camera-source v4l2:/dev/video10" ;; esac echo "" echo "==============================================="