Skip to content
Tzu Huan Tai edited this page Dec 11, 2024 · 35 revisions

This wiki provides comprehensive information on configuring and using the pi_webrtc for video streaming, along with detailed technical insights on encoders, signaling protocols, and recording options.

Outline

Architecture

Raspberry Pi WebRTC Architecture

Flags

Available flags for pi_webrtc:

Option Default Description
-h, --help Display help information about the available options.
--fps 30 Set the camera frame rate (frames per second).
--width 640 Set the camera frame width (in pixels).
--height 480 Set the camera frame height (in pixels).
--rotation_angle 0 Set the rotation angle of the frame (0, 90, 180, 270) via V4L2.
--sample_rate 44100 Set the audio sample rate (in Hz).
--no_audio false Run without an audio source.
--hw_accel false Enable hardware acceleration by sharing DMA buffers between the decoder, scaler, and encoder to reduce CPU usage.
--use_libcamera false Read YUV420 from the camera via libcamera, the --device and --v4l2_format flags will be suspended.
--v4l2_format mjpeg Set the V4L2 input format (i420, mjpeg, h264) if supported by the camera.
--device /dev/video0 Read the specific camera device file via V4L2.
--uid Set the unique identifier string for the device.
--stun_url stun:stun.l.google.com:19302 Set the STUN server URL for WebRTC. Example: stun:xxx.xxx.xxx.
--turn_url Set the TURN server URL for WebRTC. Example: turn:xxx.xxx.xxx:3478?transport=tcp.
--turn_username Set the TURN server username for WebRTC authentication.
--turn_password Set the TURN server password for WebRTC authentication.
--record_path Set the path where recording video files will be saved. If the value is empty or unavailable, the recorder will not start.
--mqtt_port 1883 Set the MQTT server port.
--mqtt_host localhost Set the MQTT server host.
--mqtt_username Set the MQTT server username.
--mqtt_password Set the MQTT server password.
--http_port 8080 Set the HTTP signaling port.

Note

The fps, width, and height settings might be reduced in the live stream due to network or device performance issues if detected by WebRTC. However, the recording will always maintain the same width and height.

Camera Mode

There are two ways to read images from the camera. The V4L2 only supports the v1 and v2 cameras and the HQ camera. After Camera Module 3, future updates will be based on Libcamera.

V4L2

This is for older Pi OS (before Bookworm), please modify the camera_auto_detect=1 flag in file /boot/firmware/config.txt to

# camera_auto_detect=1
camera_auto_detect=0
start_x=1
gpu_mem=256

Set camera_auto_detect=0 in order to read camera by V4L2. The size of gpu_mem depends on desired resolution, 256MB for 1080p.

Libcamera

This is the Raspberry Pi officially recommended way to read the camera.

Use the default setting camera_auto_detect=1 in /boot/firmware/config.txt. In this project, Libcamera only provides the yuv420 format, and the --device and --v4l2_format flags will be disabled if --use_libcamera flag is used. Since yuv420 is an uncompressed format, you should check the bandwidth of the CSI/USB interface to ensure the camera can handle high resolution and frame rate images. Each MIPI lane provides 1.5 Gbps bandwidth on the Pi 5, but each MIPI lane provides 1 Gbps on earlier models. [ref]

Interface 1-lane MIPI (older Pi) 2-lane MIPI (Pi 4) 4-lane MIPI (Pi 5) USB 2.0 USB 3.0
Bandwith 1 Gbps 2 Gbps 6 Gbps 0.48 Gbps 5 Gbps

For example:

YUV 4:2:0 need 12 bits/pixel. 4Kp60 = 3840 x 2160 x 60 x 12 = 5.56 Gbps.

Resolution 4Kp60 4Kp30 1080p60 1080p30
Bandwith 5.56 Gbps 2.78 Gbps 1.39 Gbps 0.70 Gbps

Encoding Mode

The encoder used in WebRTC depends on whether the --hw_accel flag is set and the SDP context offered by the client. I recommend running v4l2-ctl -d /dev/video0 --list-formats-ext to check which formats your camera supports before specifying the V4L2 source format, allowing you to choose the most suitable encoding mode.

Tip

pi_webrtc delivers the best recording performance if your camera provides h264 streams.

Hardware (V4L2 H264)

Run with --hw_accel.

pi_webrtc will list only H264 in the SDP context. Hardware H264 encoding is only available on the Raspberry Pi 3, 4, and Zero 2. The Raspberry Pi 5 no longer supports the hardware encoder. For other single-board computers, such as Radxa, Odroid, etc., H264 hardware encoding may be supported according to their specifications. However, if their codecs do not implement the V4L2 driver, it is recommended to use Software encoding instead. The Raspberry Pi codec device files are located at [ref]:

Codec Location
decoder /dev/video10
encoder /dev/video11
scaler /dev/video12
  • For h264 camera source

    /path/to/pi_webrtc --device=/dev/video0 --v4l2_format=h264 --fps=30 --width=1280 --height=960 --hw_accel ...
    graph LR
    A(Camera) -- h264 --> B(hw decoder) -- yuv420 --> C(hw scaler) --yuv420--> D(hw encoder) --h264-->E(webrtc client)
    A --h264--> F(mp4)
    
    Loading

    This command grabs the h264 stream directly from the camera and uses the hardware decoder to convert it to yuv420. If WebRTC detects network or device performance issues, the hardware scaler will automatically adjust by scaling down the decoded yuv420 frame resolution, and vice versa when conditions improve. When the resolution changes, the hardware encoder will be reset to match the new resolution. All frame data is transferred via DMA (zero-copy) between hardware codecs. Furthermore, if the --record_path flag is set (enabling recording), the h264 packets from the camera are directly copied into MP4 files.

  • For mjpeg camera source

    /path/to/pi_webrtc --device=/dev/video0 --v4l2_format=mjpeg --fps=30 --width=1280 --height=960 --hw_accel ...
    graph LR
    A(camera) -- mjpeg --> B(hw decoder) -- yuv420 --> C(hw scaler) --yuv420--> D(hw encoder) --h264-->E(webrtc client)
    B --yuv420--> F(openh264) -- h264--> G(mp4)
    
    Loading

    All processes are similar to the h264 source camera in hardware mode. The main difference is OpenH264 software encoder will be used in video recording.

  • For i420 camera source

    # use v4l2 camera
    /path/to/pi_webrtc --device=/dev/video0 --v4l2_format=i420 --fps=30 --width=1280 --height=960 --hw_accel ...
    
    # use libcamera
    /path/to/pi_webrtc --use_libcamera --fps=30 --width=1280 --height=960 --hw_accel ...
    graph LR
    A(camera) -- yuv420 --> C(hw scaler) --yuv420--> D(hw encoder) --h264-->E(webrtc client)
    A --yuv420--> F(openh264) -- h264--> G(mp4)
    
    Loading

    This command captures uncompressed yuv420 from the camera. Since it is uncompressed, the CSI/USB bandwidth may not support high resolution and fps. i420 is useful when running on a Pi Zero or if CPU usage is excessively high due to many background services. The OpenH264 software encoder will be used for video recording, but this method is typically chosen because of limited system resources, and the recorder is usually not enabled.

Software (H264/VP8/VP9/AV1)

Run without --hw_accel.

pi_webrtc will list all H264, VP8, VP9 and AV1 codecs in the SDP context. The encoder used depends on the SDP provided by the client. For example, if the client's SDP only includes H264, WebRTC will use the H264 encoder for live streaming. Make sure the client's SDP contains the only codec you want to use."

  • For h264 camera source
    /path/to/pi_webrtc --device=/dev/video0 --v4l2_format=h264 --fps=30 --width=1280 --height=960 ...
    It's not available in pi_webrtc. I didn't implement H264 software decoding.
  • For mjpeg camera source
    /path/to/pi_webrtc --device=/dev/video0 --v4l2_format=mjpeg --fps=30 --width=1280 --height=960 ...
    graph LR
    A(camera) -- mjpeg --> B(libyuv) -- yuv420 --> C(libyuv scaler) --yuv420--> D(openh264) --h264-->E(webrtc client)
    B --yuv420--> F(openh264) -- h264--> G(mp4)
    
    Loading
    It's suitable for most devices that do not support the V4L2 hardware encoder. The mjpeg frames will be decoded into yuv420 by libyuv. If WebRTC requires a lower resolution for live streaming, the scaling will also be handled by libyuv. The recording will use separate instances of the OpenH264 encoder.
  • For i420 camera source
    # use v4l2 camera
    /path/to/pi_webrtc --device=/dev/video0 --v4l2_format=i420 --fps=30 --width=1280 --height=960  ...
    
    # use libcamera
    /path/to/pi_webrtc --use_libcamera --fps=30 --width=1280 --height=960 ...
    graph LR
    A(camera) -- yuv420 --> C(libyuv scaler) --yuv420--> D(openh264) --h264-->E(webrtc client)
    A --yuv420--> F(openh264) -- h264--> G(mp4)
    
    Loading
    It's suitable for devices do not support the V4L2 hardware encoder, but it provides a very high CSI/USB bandwidth.

Signaling

MQTT

pi_webrtc registers itself with the MQTT server at the beginning and waits for the app client to send a request to initiate the connection. The diagram below shows how the connection process operates between the app client, MQTT server, and pi_webrtc. Assume that the --uid is set to home-pi-5, and ${mqttId} is another random UID used to identify each MQTT connection.

sequenceDiagram
Note over pi_webrtc, mqtt server: sub: home-pi-5/sdp/+/offer<br>sub: home-pi-5/ice/+/offer

client--> pi_webrtc: start connecting

Note over client, mqtt server: sub: home-pi-5/sdp/${mqttId}<br>sub: home-pi-5/ice/${mqttId}

client ->> mqtt server: client's SDP
Note over client, mqtt server: pub: home-pi-5/sdp/${mqttId}/offer

mqtt server ->> pi_webrtc: client's SDP

pi_webrtc ->> mqtt server : pi's SDP
Note over pi_webrtc, mqtt server: pub: home-pi-5/sdp/${mqttId}

mqtt server ->> client: pi's SDP

client ->> mqtt server: client's ICE
Note over client, mqtt server: pub: home-pi-5/ice/${mqttId}/offer

mqtt server ->> pi_webrtc: client's ICE

pi_webrtc ->> mqtt server : pi's ICE
Note over pi_webrtc, mqtt server: pub: home-pi-5/ice/${mqttId}

mqtt server ->> client: pi's ICE
client ->pi_webrtc: connected
Loading

WHEP

You can play the video directly using a URL like https://pi.example.net without server registration.
This allows you to stream video like a traditional RTSP/RTMP stream using a simple URL, if your player supports WHEP.

sequenceDiagram
    participant Server as pi_webrtc
    participant Client as WHEP Player

    Client->>Server: client's SDP/ICE
    Note over Client, Server: POST to `https://pi.example.net`
    Server->>Client: pi's SDP/ICE
    Note over Client, Server: 201 Created

    Client->Server: connected
Loading

Recording

The video files will be recorded every minute, and each video file will generate a snapshot image for preview. If the disk space falls below 400MB, it will start rotation.

Format
Video H264
Audio AAC

Misc

Other useful tools, commands, or information are not included in this project but are potentially useful.

Useful Commands

Command Description
v4l2-ctl --list-devices Show available devices in V4L2.
v4l2-ctl -d /dev/video0 --list-formats-ext Show supported formats from devices. Not only the camera but also the codecs.
sudo fdisk -l List partition tables to help set up USB disks.
vcgencmd get_camera Check whether the camera is detected or not.