2025-11-03 00:11:13 +08:00

267 lines
7.7 KiB
Bash
Executable File

#!/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 "==============================================="