streamertemplate_web_logo

StreamerTemplate C++ application

v1.0.1

Table of contents

Overview

StreamerTemplate is a C++ application that captures video from a USB camera, encodes it with the hardware H264 encoder and sends it to the network as a simple RTP stream. It is a test source for a video receiver (for example the StreamReceiver application) and an example of the shortest pipeline from a camera to the network. The whole application is in one file (src/main.cpp), all parameters are predefined, no configuration file is needed.

StreamerTemplate is general-purpose software: it is not tied to any sector or application, and the developer of a program decides what the program does with it.

The processing pipeline:

USB camera -> VSourceV4L2 -> VCodecV4L2 -> RtpPusher -> RTP stream (UDP) -- network -- receiver
Step Library Description
1 VSourceV4L2 Captures frames from a V4L2 video device (USB camera). The YUYV pixel format is requested from the camera.
2 FormatConverter Converts the frame to NV12, the input format of the encoder.
3 VCodecV4L2 Encodes NV12 frames to H264 with the V4L2 hardware encoder. On Jetson the Jetson encoder device is used.
4 RtpPusher Sends every H264 frame as RTP packets over UDP without RTSP signaling and without SDP.

The application runs on Linux (V4L2 devices are used). The camera must deliver an uncompressed pixel format (YUYV, NV12 etc.). Cameras that deliver only compressed formats (MJPEG, H264) are not supported: the application prints a message and stops. The pixel formats and the frame sizes of a camera are shown by the command v4l2-ctl -d /dev/video0 --list-formats-ext. A USB camera delivers 30 FPS in YUYV only at small frame sizes, so the frame size must be a size that the camera supports at 30 FPS in the requested pixel format.

Versions

Table 1 - Application versions.

Version Release date What’s new
1.0.0 23.10.2026 - First version.
1.0.1 26.10.2026 - The port must be a plain decimal number: text after the digits, signs and spaces are rejected. An IP address with a zero byte is rejected. A wrong number of arguments stops the application.
- A camera that delivers a compressed pixel format gives its own message.
- Any failure of the sender except a dropped frame stops the application.
- Named constants, corrected comments, the compiler option -Wdocumentation for clang.

Application files

The repository structure is shown below:

CMakeLists.txt -------------------- Main CMake file of the application.
src ------------------------------- Folder with application source code.
    CMakeLists.txt ---------------- CMake file of the application.
    main.cpp ---------------------- Source C++ file of the application.
    StreamerTemplateVersion.h ----- Header file with application version.
    StreamerTemplateVersion.h.in -- File for CMake to generate version header.
static ---------------------------- Folder with images of this documentation.
    streamertemplate_web_logo.png - Logo.

How to run the application

Build

Requirements:

  • Operating system: Linux. The camera and the encoder are V4L2 devices. The target platform is Jetson (the hardware H264 encoder of the Jetson is used). Tested on Jetson Orin NX (L4T R36.4.7) with a C922 USB camera.
  • Tools: CMake 3.13 or newer and a C++17 compiler (GCC or Clang).
  • Camera: a USB camera that delivers an uncompressed pixel format (see Overview).
  • VCodecV4L2: version 3.0.4 or newer. It is needed on Jetson (L4T R36) to encode 640x480 frames and to get the coded frame without delay with pipeline depth 1.

The repository does not contain sub-repositories. The libraries the application depends on (Frame, ConfigReader, VSource, VCodec, Logger, VSourceV4L2, VCodecV4L2, RtpPusher and FormatConverter) must be cloned into the same folder as StreamerTemplate. The folder structure must be:

<work folder>
    StreamerTemplate
    Frame
    ConfigReader
    VSource
    VCodec
    Logger
    VSourceV4L2
    VCodecV4L2
    RtpPusher
    FormatConverter

If a folder does not exist CMake stops with an error. Typical commands to build the StreamerTemplate application (use the URLs of the repositories provided to you):

git clone <StreamerTemplate repository URL>
git clone <Frame repository URL>
git clone <ConfigReader repository URL>
git clone <VSource repository URL>
git clone <VCodec repository URL>
git clone <Logger repository URL>
git clone <VSourceV4L2 repository URL>
git clone <VCodecV4L2 repository URL>
git clone <RtpPusher repository URL>
git clone <FormatConverter repository URL>
cd StreamerTemplate
mkdir build
cd build
cmake ..
make

In the RapidPixel SDK the application is built from the root of the SDK (the libraries are taken from the SDK, the folders next to the application are not needed). The executable file is placed in the build/bin folder:

cd /path/to/RapidPixelSdk
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release --target StreamerTemplate

Run

Connect a USB camera (the application opens /dev/video0) and run the application without arguments:

cd build/bin
./StreamerTemplate

The application asks for the destination IP address and the UDP port:

Enter destination IP: 192.168.1.10
Enter destination port: 7032

Or run it with the IP address and the port as arguments (the IP address must be an IPv4 address like 192.168.1.10, the port a decimal number 1 - 65535, any other text is rejected):

cd build/bin
./StreamerTemplate 192.168.1.10 7032

The application prints the number of sent frames. Press Ctrl+C to stop it. If the destination is invalid, the number of arguments is not 0 or 2, or the camera, the encoder or the sender fails, the application prints the reason and stops with the exit code 1.

Predefined parameters

The parameters are set in src/main.cpp.

Table 2 - Predefined parameters.

Parameter Value Description
Camera device /dev/video0 Video device of the USB camera.
Camera pixel format YUYV Pixel format requested from the camera.
Frame size 640 x 480 Frame size requested from the camera.
Frame rate 30 FPS Frame rate requested from the camera and set in the encoder.
Codec H264 Baseline profile (no B-frames, the lowest latency).
Bitrate 5000 kbps Bitrate of the encoder (5 Mbps).
GOP 30 A key frame every 30 frames (every second).
Encoder pipeline depth 1 The encoder returns the coded frame of the same camera frame (no delay). The default depth 2 delays by one frame.
Stream type RTP RTP framing over UDP, maximum packet size 1420 bytes.
Sending bitrate 100000 kbps Pacing bitrate of the sender (100 Mbps): a frame is sent within a few milliseconds.

Receive the stream

The stream has no SDP and no RTSP signaling: the receiver listens to the UDP port. For example, with the StreamReceiver application on the destination computer:

./StreamReceiver rtp://0.0.0.0:7032

A key frame is sent every GOP (1 second), so a receiver that is started later shows the picture within about one second.

The application does not send the capture time of the frames, so StreamReceiver shows unknown for the capture time and the latency of this stream. Measure the latency from the camera to the screen with an external device, for example a glass-to-glass latency tester (see Latency).

Latency

Test setup

The glass-to-glass latency (from the light in front of the camera to the picture on the screen of the receiver) was measured with the GTG-1 device. Four combinations of a sender and a receiver were measured to compare StreamerTemplate and the VSourceStream library (inside StreamReceiver) with ffmpeg and ffplay:

Jetson Orin NX (L4T R36.4.7)                                    Windows PC
USB camera (C922) -> sender ---- Ethernet cable, RTP over UDP ----> receiver -> screen
                              StreamerTemplate or ffmpeg                    StreamReceiver or ffplay

All senders use the same stream: H264 Baseline profile, 640x480, 30 FPS, 5 Mbps, GOP 30, RTP over UDP with packets of at most 1420 bytes. The camera delivers YUYV 640x480 at 30 FPS. ffmpeg encodes on the CPU (libx264 with the low latency settings ultrafast and zerolatency), StreamerTemplate encodes with the hardware encoder of the Jetson.

The camera runs with fixed settings during the measurement: manual exposure of 15 ms and a constant frame rate. Without them the camera lowers the frame rate in low light and the latency changes from frame to frame. The camera forgets the settings when it is plugged in again, so set them before each measurement:

v4l2-ctl -d /dev/video0 -c auto_exposure=1 -c exposure_time_absolute=150 -c exposure_dynamic_framerate=0
v4l2-ctl -d /dev/video0 -l | grep -iE "exposure|dynamic"

auto_exposure=1 selects manual exposure, exposure_time_absolute=150 sets the exposure time to 15 ms (units of 100 us), exposure_dynamic_framerate=0 keeps the frame rate constant. The second command shows the values (1, 150 and 0).

Results

Table 3 - Glass-to-glass latency.

Case Sender (Jetson) Receiver (PC) Latency, ms
A StreamerTemplate StreamReceiver 85
B ffmpeg (libx264) ffplay 300
C ffmpeg (libx264) StreamReceiver 90
D StreamerTemplate ffplay 280
  • StreamerTemplate with StreamReceiver (case A, 85 ms) is the fastest combination: about 215 ms faster than ffmpeg with ffplay (case B, 300 ms).
  • The receiver makes the largest difference: with the same sender, StreamReceiver is 195 - 210 ms faster than ffplay (case A against D, case C against B).
  • With the same receiver, StreamerTemplate is 5 - 20 ms faster than the ffmpeg sender (case A against C, case D against B). The hardware encoder returns the coded frame of the same camera frame (pipeline depth 1) and RtpPusher sends a frame within a few milliseconds (100 Mbps).

Commands of the ffmpeg comparison

Sender on the Jetson (replace the IP address by the address of the receiver):

ffmpeg -hide_banner -f v4l2 -input_format yuyv422 -video_size 640x480 -framerate 30 -i /dev/video0 \
  -c:v libx264 -preset ultrafast -tune zerolatency -profile:v baseline -pix_fmt yuv420p \
  -b:v 5M -minrate 5M -maxrate 5M -bufsize 167k -x264-params nal-hrd=cbr \
  -g 30 -keyint_min 30 -sc_threshold 0 -f rtp "rtp://10.10.10.1:7032?pkt_size=1420"

Receiver: StreamReceiver with the source string rtp://0.0.0.0:7032, or ffplay with a SDP file (stream.sdp) that describes the stream:

ffplay -protocol_whitelist file,udp,rtp -fflags nobuffer -flags low_delay -framedrop -max_delay 0 -reorder_queue_size 0 -probesize 32 -analyzeduration 0 -sync ext -i stream.sdp

The options -max_delay 0 and -reorder_queue_size 0 turn off the wait of ffplay for late and reordered RTP packets. Cases B and D give about the same latency with and without these options. Do not add -vf setpts=0: with it the picture of ffplay stops.

v=0
o=- 0 0 IN IP4 10.10.10.1
s=RTP H264 Stream
c=IN IP4 10.10.10.1
t=0 0
m=video 7032 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1

The same SDP file is used for the stream of StreamerTemplate (case D): both senders use the payload type 96 and the port 7032.


Table of contents