
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.