267 lines
7.7 KiB
Bash
Executable File
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 "===============================================" |