A comprehensive HTTP streaming server for ROS image topics with advanced V4L2 loopback device support. This enhanced version allows you to stream ROS camera feeds not only to web browsers but also to virtual video devices that can be used by any application that supports video capture.
- Multiple Format Support: MJPEG, VP8, VP9, H264, PNG, and ROS compressed image streams
- Web Interface: Browse and view available image topics through a web browser
- Adjustable Quality: Control resolution, bitrate, and quality parameters
- Real-time Streaming: Low-latency video streaming with configurable QoS profiles
- Snapshot Support: Capture single images from any ROS image topic
- Virtual Video Devices: Create virtual video devices from ROS image topics
- Auto-discovery: Automatically detect and stream all available image topics
- Device Management: Intelligent device allocation and cleanup
- Multi-device Support: Stream multiple topics to separate virtual devices
- Format Conversion: Automatic pixel format conversion (YUYV, RGB24, BGR24)
- Health Monitoring: Device health monitoring and automatic error recovery
- Linux Kernel: 4.0+ with v4l2loopback module support
- ROS 2: Humble, Iron, or Rolling distribution
- Dependencies: OpenCV, FFmpeg/libav, Boost, async_web_server_cpp
# Install system dependencies
sudo apt update
sudo apt install -y \
build-essential \
cmake \
libopencv-dev \
libavcodec-dev \
libavformat-dev \
libswscale-dev \
libboost-all-dev \
pkg-config \
v4l2loopback-dkms \
v4l-utils
# Install ROS 2 dependencies
sudo apt install -y \
ros-${ROS_DISTRO}-cv-bridge \
ros-${ROS_DISTRO}-image-transport \
ros-${ROS_DISTRO}-sensor-msgs
# For newer ROS 2 distributions (Humble, Iron, Rolling)
sudo apt install ros-${ROS_DISTRO}-web-video-server
# Create ROS workspace
mkdir -p ~/ros_ws/src
cd ~/ros_ws/src
# Clone the repository
git clone https://github.com/RobotWebTools/web_video_server.git
# Install dependencies
cd ~/ros_ws
rosdep update
rosdep install --from-paths src -i
# Build the package
colcon build --packages-select web_video_server
# Source the workspace
source install/setup.bash
The v4l2loopback module creates virtual video devices that can receive video streams. You need to load this module before starting the web video server.
# Load the v4l2loopback module with 4 virtual devices
sudo modprobe v4l2loopback devices=4 video_nr=0,1,2,3 max_width=1920 max_height=1080 exclusive_caps=1,1,1,1
# Verify devices were created
ls -la /dev/video*
v4l2-ctl --list-devices
# Load with specific device numbers and capabilities
sudo modprobe v4l2loopback \
devices=4 \
video_nr=10,11,12,13 \
max_width=1920 \
max_height=1080 \
exclusive_caps=1,1,1,1 \
card_label="ROS2_Camera_0,ROS2_Camera_1,ROS2_Camera_2,ROS2_Camera_3"
# Check device information
v4l2-ctl -d /dev/video10 --list-formats-ext
# Unload the v4l2loopback module
sudo modprobe -r v4l2loopback
# Or remove specific devices
sudo rmmod v4l2loopback
# List all video devices
ls -la /dev/video*
# Check v4l2loopback devices specifically
v4l2-ctl --list-devices | grep -A 5 "v4l2 loopback"
# Test device capabilities
v4l2-ctl -d /dev/video10 --list-formats-ext
# Basic web streaming only
ros2 run web_video_server web_video_server
# Custom port and address
ros2 run web_video_server web_video_server \
--ros-args \
-p port:=8081 \
-p address:=0.0.0.0 \
-p server_threads:=4 \
-p verbose:=true
# Auto-discover and stream all image topics to v4l2 devices
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_auto_discover:=true \
-p v4l2_device_prefix:="ros2_" \
-p v4l2_width:=640 \
-p v4l2_height:=480 \
-p v4l2_fps:=30 \
-p v4l2_pixel_format:="YUYV"
# Stream specific topics to v4l2 devices
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_topics:="/camera/image_raw,/camera/image_rect,/stereo/left/image" \
-p v4l2_device_prefix:="ros2_" \
-p v4l2_width:=1280 \
-p v4l2_height:=720 \
-p v4l2_fps:=25 \
-p v4l2_pixel_format:="RGB24"
# High-resolution, high-framerate streaming
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_auto_discover:=true \
-p v4l2_device_prefix:="ros2_" \
-p v4l2_width:=1920 \
-p v4l2_height:=1080 \
-p v4l2_fps:=60 \
-p v4l2_pixel_format:="YUYV" \
-p v4l2_device_timeout:=120.0 \
-p server_threads:=8 \
-p verbose:=true
Here's a complete example of setting up and running the enhanced web video server:
# 1. Load v4l2loopback module
sudo modprobe v4l2loopback devices=4 video_nr=10,11,12,13 max_width=1920 max_height=1080 exclusive_caps=1,1,1,1
# 2. Verify devices are created
ls -la /dev/video*
# 3. Start ROS 2 core (if not already running)
ros2 launch ros2_core core.launch.py
# 4. Start a camera node (example with usb_cam)
ros2 run usb_cam usb_cam_node_exe --ros-args -p video_device:=/dev/video0 -p image_width:=640 -p image_height:=480
# 5. Start the enhanced web video server
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_auto_discover:=true \
-p v4l2_device_prefix:="ros2_" \
-p v4l2_width:=640 \
-p v4l2_height:=480 \
-p v4l2_fps:=30 \
-p v4l2_pixel_format:="YUYV" \
-p port:=8080 \
-p verbose:=true
# 6. Test the virtual devices
ffplay /dev/video10 # View the first virtual device
v4l2-ctl -d /dev/video10 --list-formats-ext # Check device capabilities
Once the server is running, open your web browser and navigate to:
http://localhost:8080/
/
- Browse all available image topics and streaming options
/stream?topic=/camera/image_raw
- Direct video stream/stream_viewer?topic=/camera/image_raw
- Web page with embedded video player/snapshot?topic=/camera/image_raw
- Single image snapshot
/v4l2_info
- View V4L2 device status and configuration
Parameter | Type | Default | Description |
---|---|---|---|
topic |
string | (required) | ROS image topic to stream |
type |
string | "mjpeg" | Stream format (mjpeg, vp8, vp9, h264, png) |
width |
int | 0 | Output width (0 = original) |
height |
int | 0 | Output height (0 = original) |
quality |
int | 95 | Quality for MJPEG/PNG (1-100) |
bitrate |
int | 100000 | Bitrate for H264/VP8/VP9 (bits/sec) |
# MJPEG stream at 640x480 with 90% quality
http://localhost:8080/stream?topic=/camera/image_raw&type=mjpeg&width=640&height=480&quality=90
# H264 stream with higher bitrate
http://localhost:8080/stream?topic=/camera/image_raw&type=h264&bitrate=500000
# Web page viewer
http://localhost:8080/stream_viewer?topic=/camera/image_raw
# Single snapshot
http://localhost:8080/snapshot?topic=/camera/image_raw&width=1280&height=720
Parameter | Type | Default | Description |
---|---|---|---|
port |
int | 8080 | HTTP server port |
address |
string | "0.0.0.0" | Server address (0.0.0.0 for external access) |
server_threads |
int | 1 | Number of HTTP server threads |
verbose |
bool | false | Enable verbose logging |
default_stream_type |
string | "mjpeg" | Default streaming format |
Parameter | Type | Default | Description |
---|---|---|---|
enable_v4l2_devices |
bool | false | Enable V4L2 device streaming |
v4l2_auto_discover |
bool | false | Auto-discover image topics |
v4l2_topics |
string | "" | Comma-separated list of topics to stream |
v4l2_device_prefix |
string | "ros2_" | Prefix for virtual device names |
v4l2_width |
int | 640 | Output video width |
v4l2_height |
int | 480 | Output video height |
v4l2_fps |
int | 30 | Target frames per second |
v4l2_pixel_format |
string | "YUYV" | Pixel format (YUYV, RGB24, BGR24) |
v4l2_device_timeout |
double | 60.0 | Device inactivity timeout (seconds) |
v4l2_config_file |
string | "" | Path to V4L2 configuration file |
You can use a YAML configuration file for complex V4L2 setups:
# v4l2_config.yaml
devices:
- ros_topic: "/camera/image_raw"
device_name: "front_camera"
width: 1280
height: 720
fps: 30
pixel_format: "YUYV"
device_path: "/dev/video10"
- ros_topic: "/stereo/left/image"
device_name: "stereo_left"
width: 640
height: 480
fps: 25
pixel_format: "RGB24"
device_path: "/dev/video11"
- ros_topic: "/stereo/right/image"
device_name: "stereo_right"
width: 640
height: 480
fps: 25
pixel_format: "RGB24"
device_path: "/dev/video12"
Load with configuration file:
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_config_file:="$(pwd)/v4l2_config.yaml"
# List all video devices
ls -la /dev/video*
# Check v4l2loopback devices
v4l2-ctl --list-devices | grep -A 5 "v4l2 loopback"
# View device capabilities
v4l2-ctl -d /dev/video10 --list-formats-ext
# Check device status
v4l2-ctl -d /dev/video10 --all
# List available topics
ros2 topic list
# Monitor image topics
ros2 topic echo /camera/image_raw --once
# Check topic frequency
ros2 topic hz /camera/image_raw
# Run with verbose logging
ros2 run web_video_server web_video_server \
--ros-args \
-p verbose:=true \
-p enable_v4l2_devices:=true \
-p v4l2_auto_discover:=true
# Check server logs
ros2 run web_video_server web_video_server --ros-args -p verbose:=true
# Test with ffplay
ffplay /dev/video10
# Test with v4l2-ctl
v4l2-ctl -d /dev/video10 --stream-mmap --stream-count=100
# Test with gstreamer
gst-launch-1.0 v4l2src device=/dev/video10 ! videoconvert ! autovideosink
# Check if module is available
modinfo v4l2loopback
# Install if missing
sudo apt install v4l2loopback-dkms
# Load manually
sudo modprobe v4l2loopback
# Add user to video group
sudo usermod -a -G video $USER
# Set device permissions
sudo chmod 666 /dev/video*
# Reboot or log out/in for group changes to take effect
# Check kernel module
lsmod | grep v4l2loopback
# Reload module with explicit parameters
sudo modprobe -r v4l2loopback
sudo modprobe v4l2loopback devices=4 video_nr=10,11,12,13
# Check device creation
ls -la /dev/video*
# Check if port is in use
sudo netstat -tlnp | grep :8080
# Use different port
ros2 run web_video_server web_video_server --ros-args -p port:=8081
# Check firewall settings
sudo ufw status
# Reduce resolution and framerate
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_width:=640 \
-p v4l2_height:=480 \
-p v4l2_fps:=15
# Use different pixel format
-p v4l2_pixel_format:="RGB24"
# Increase server threads
-p server_threads:=4
- Add a "Video Capture Device" source
- Select one of the virtual devices (e.g.,
/dev/video10
) - Configure resolution and framerate
# Open virtual device in VLC
vlc v4l2:///dev/video10
# Or with specific parameters
vlc v4l2:///dev/video10:width=640:height=480
# Record from virtual device
ffmpeg -f v4l2 -i /dev/video10 -c:v libx264 -preset ultrafast output.mp4
# Stream to RTMP
ffmpeg -f v4l2 -i /dev/video10 -c:v libx264 -preset ultrafast -f flv rtmp://localhost/live/stream
# Load more devices
sudo modprobe v4l2loopback devices=8 video_nr=10,11,12,13,14,15,16,17
# Start multiple camera nodes
ros2 run usb_cam usb_cam_node_exe --ros-args -p video_device:=/dev/video0 -p camera_name:=front_cam
ros2 run usb_cam usb_cam_node_exe --ros-args -p video_device:=/dev/video1 -p camera_name:=rear_cam
# Start web video server with auto-discovery
ros2 run web_video_server web_video_server \
--ros-args \
-p enable_v4l2_devices:=true \
-p v4l2_auto_discover:=true \
-p v4l2_device_prefix:="ros2_"
This project is part of the Robot Web Tools effort. Contributions are welcome!
# Clone repository
git clone https://github.com/RobotWebTools/web_video_server.git
cd web_video_server
# Install development dependencies
sudo apt install -y \
clang-format \
cppcheck \
ament_lint_auto \
ament_cmake_copyright \
ament_cmake_cpplint
# Build with tests
colcon build --packages-select web_video_server --cmake-args -DCMAKE_BUILD_TYPE=Debug
# Run tests
colcon test --packages-select web_video_server
This project is released under the BSD license. See the LICENSE file for full terms and conditions.
See the AUTHORS file for a complete list of contributors.
- Robot Web Tools - Collection of web-based tools for robotics
- rosbridge_suite - WebSocket interface for ROS
- tf2_web_republisher - TF2 data streaming to web clients
- Issues: GitHub Issues
- Documentation: Robot Web Tools Documentation
- Discussions: GitHub Discussions