web_video_server

repository·ros2·Indexed 18 days ago

https://github.com/robotwebtools/web_video_server

A ROS package that provides HTTP streaming of ROS image topics in multiple formats, including MJPEG, VP8, VP9, H264, and PNG, enabling robot camera feeds to be viewed in web browsers. It supports ROS 1 and ROS 2, offering endpoints for stream viewing, direct HTTP multipart streams, and image snapshots. The server is configurable via ROS parameters and is extensible through a plugin system using pluginlib for custom streaming formats.

Tokens
2.9K
Snippets
9
Records
10
Agent score
14%

What's inside web_video_server

  1. Custom Streamer Implementation Hints

    ros2

    When developing custom streamers, keep the following in mind:

    • Query Parameters: Access HTTP query parameters in the Streamer constructor using request.get_query_param_value_or_default.
    • Logging: Use the logger_ member variable provided by StreamerBase.
    • Image Transport: Inherit from web_video_server::streamers::ImageTransportStreamerBase to avoid boilerplate when working with image transport functionality.
    • Topic Visibility: By default, custom streamers won't appear in the topic list view. To fix this, either overwrite get_available_topics in your StreamerFactory or inherit from ImageTransportStreamerFactoryBase to make the format available for all sensor_msgs/msg/Image topics.
  2. Implement the Streamer and StreamerFactory interfaces

    ros2

    A custom plugin requires two main components:

    1. TestStreamer: Inherits from web_video_server::StreamerBase. You must implement start() and restream_frame(std::chrono::duration<double> max_age).
    2. TestStreamerFactory: Inherits from web_video_server::StreamerFactoryInterface. You must implement get_type() (which returns the format string used in the URL) and create_streamer().

    Use the PLUGINLIB_EXPORT_CLASS macro to export your factory class.

    // Header definition snippet
    class TestStreamer : public web_video_server::StreamerBase
    {
    public:
      TestStreamer(
        const async_web_server_cpp::HttpRequest & request,
        async_web_server_cpp::HttpConnectionPtr connection,
        rclcpp::Node::WeakPtr node);
    
      virtual ~TestStreamer();
    
      void start() override;
      void restream_frame(std::chrono::duration<double> max_age) override;
    };
    
    class TestStreamerFactory : public web_video_server::StreamerFactoryInterface
    {
    public:
      std::string get_type() override {return "test";}
    
      std::shared_ptr<web_video_server::StreamerInterface> create_streamer(
        const async_web_server_cpp::HttpRequest & request,
        async_web_server_cpp::HttpConnectionPtr connection,
        rclcpp::Node::WeakPtr node) override;
    };
    
    // Implementation snippet
    PLUGINLIB_EXPORT_CLASS(
    test_streamer_plugin::TestStreamerFactory,
    web_video_server::StreamerFactoryInterface)
  3. Configure pluginlib and CMake for custom streamers

    ros2

    After implementing the C++ classes, you must register the plugin and update your build configuration:

    1. Create plugins.xml: Define the library path, the class name (format: package_name/stream/format_name), and the type.
    2. Update CMakeLists.txt: Use pluginlib_export_plugin_description_file to export the XML.
    3. Link Libraries: Link against web_video_server::web_video_server and pluginlib::pluginlib. If using ImageTransportStreamerBase, also link web_video_server::web_video_server_streamers.
    <!-- plugins.xml -->
    <library path="test_streamer_plugin">
      <class name="test_streamer_plugin/stream/test"
        type="test_streamer_plugin::TestStreamerFactory"
        base_class_type="web_video_server::StreamerFactoryInterface">
        <description>Test streamer implementation</description>
      </class>
    </library>
    # CMakeLists.txt
    pluginlib_export_plugin_description_file(web_video_server plugins.xml)
    
    target_link_libraries(
      test_streamer_plugin
      web_video_server::web_video_server
      pluginlib::pluginlib
    )
  4. How to write a custom streamer plugin for ROS 2

    ros2

    To extend web_video_server with custom streaming formats, you must implement a plugin using pluginlib. This involves creating a class that inherits from web_video_server::StreamerBase (or web_video_server::streamers::ImageTransportStreamerBase for image transport support) and a factory class that inherits from web_video_server::StreamerFactoryInterface.

    # 1. Create workspace
    mkdir -p ~/ros_ws/src
    cd ~/ros_ws/src
    
    # 2. Create package
    ros2 pkg create --build-type ament_cmake test_streamer_plugin --dependencies web_video_server pluginlib --library-name test_streamer_plugin
    
    # 3. Build
    cd ~/ros_ws
    colcon build --packages-select test_streamer_plugin
    source install/setup.bash
    
    # 4. Run server
    ros2 run web_video_server web_video_server
  5. Install web_video_server

    ros2

    You can install web_video_server either as a pre-built package for supported ROS 2 distributions or by building it from source.

    Install via apt (ROS 2 only)

    For newer ROS 2 distributions like humble, jazzy, or rolling, use:

    sudo apt install ros-${ROS_DISTRO}-web-video-server

    Build from Source

    1. Create a workspace and clone the repository:
      • For ROS 2:
        git clone https://github.com/RobotWebTools/web_video_server.git
      • For ROS 1:
        git clone https://github.com/RobotWebTools/web_video_server.git -b ros1
    2. Install dependencies using rosdep:
      rosdep update
      rosdep install --from-paths src -i
    3. Build the package:
      colcon build --packages-select web_video_server
      source install/setup.bash
    sudo apt install ros-${ROS_DISTRO}-web-video-server
  6. Configure web_video_server parameters

    ros2

    The server can be configured using ROS parameters. You can pass these via the command line when starting the node.

    Server Configuration Parameters

    ParameterTypeDefaultDescription
    portint8080HTTP server port
    addressstring"0.0.0.0"HTTP server address (0.0.0.0 allows external connections)
    server_threadsint1Number of server threads for handling HTTP requests
    ros_threadsint2Number of threads for ROS message handling
    verboseboolfalseEnable verbose logging
    default_stream_typestring"mjpeg"Default format for video streams (mjpeg, vp8, vp9, h264, png, ros_compressed)
    publish_ratedouble-1.0Rate for republishing images (-1.0 means no republishing)

    Examples

    ROS 1 custom parameters:

    rosrun web_video_server web_video_server _port:=8081 _address:=localhost _server_threads:=4

    ROS 2 custom parameters:

    ros2 run web_video_server web_video_server --ros-args -p port:=8081 -p address:=localhost -p server_threads:=4
    ros2 run web_video_server web_video_server --ros-args -p port:=8081 -p address:=localhost -p server_threads:=4
  7. Stream an image topic via HTTP

    ros2

    You can access the video streams using two different URL patterns.

    Stream Viewer (HTML Page)

    To view a stream within a web page interface: http://localhost:8080/stream_viewer?topic=/camera/image_raw

    Direct HTTP Multipart Stream

    To consume the raw stream (e.g., in an <img> tag or video player): http://localhost:8080/stream?topic=/camera/image_raw

    Stream URL Parameters

    ParameterTypeDefaultDescription
    topicstring(required)The ROS image topic to stream
    typestring"mjpeg"Stream format (mjpeg, vp8, vp9, h264, png, ros_compressed)
    widthint0Width of output stream (0 = original)
    heightint0Height of output stream (0 = original)
    qualityint95Quality for MJPEG and PNG (1-100)
    bitrateint100000Bitrate for H264/VP8/VP9 in bits/second
    invertflag-Invert image if present
    default_transportstring"raw"Image transport (raw, compressed, theora)
    qos_profilestring"default"ROS 2 QoS profile (default, system_default, sensor_data, services_default)

    Examples

    # MJPEG at 640x480 with 90% quality
    http://localhost:8080/stream?topic=/camera/image_raw&type=mjpeg&width=640&height=480&quality=90
    
    # H264 with higher bitrate
    http://localhost:8080/stream?topic=/camera/image_raw&type=h264&bitrate=500000
    
    # Inverted image
    http://localhost:8080/stream?topic=/camera/image_raw&invert
    http://localhost:8080/stream?topic=/camera/image_raw&type=mjpeg&width=640&height=480&quality=90
  8. Stop active streams using the shutdown endpoint

    ros2

    To stop active streams from the server side (e.g., when a UI component unmounts), use the /shutdown endpoint. This prevents unnecessary bandwidth usage.

    Shutdown by Topic

    Closes all active streams for a specific topic: http://localhost:8080/shutdown?topic=/camera/image_raw

    Shutdown by Client ID

    If you associate a stream with a client_id when opening it, you can scope the shutdown to just that connection:

    1. Open stream with ID: http://localhost:8080/stream?topic=/camera/image_raw&client_id=my-ui
    2. Shutdown specific ID: http://localhost:8080/shutdown?topic=/camera/image_raw&client_id=my-ui

    Response: The response is plain text in the form stopped=<count>, where <count> is the number of streams that were stopped. Returns 400 Bad Request if topic is omitted.

    http://localhost:8080/shutdown?topic=/camera/image_raw&client_id=my-ui
  9. Get an image snapshot

    ros2

    To retrieve a single image snapshot instead of a continuous stream, use the /snapshot endpoint.

    URL Pattern: http://localhost:8080/snapshot?topic=/camera/image_raw

    Snapshot URL Parameters

    ParameterTypeDefaultDescription
    topicstring(required)The ROS image topic to snapshot
    typestring"jpeg"Snapshot format (jpeg, png, ros_compressed)
    widthint0Width of output picture (0 = original)
    heightint0Height of output picture (0 = original)
    qualityint95Quality for JPEG snapshots (1-100)
    invertflag-Invert image if present
    default_transportstring"raw"Image transport (raw, compressed, theora)
    qos_profilestring"default"ROS 2 QoS profile (default, system_default, sensor_data, services_default)
    http://localhost:8080/snapshot?topic=/camera/image_raw