vcodec_v4l2_web_logo

VCodecV4L2 C++ library

v3.0.0

Table of contents

Overview

The VCodecV4L2 C++ library provides hardware video encoding and decoding for H264, HEVC, and JPEG codecs based on the V4L2 API on Linux only. The VCodecV4L2 class inherits its interface and data structures from the open-source VCodec library (source code included, Apache 2.0 license) and also includes the Logger open-source library, which provides functions for printing logs (source code included, Apache 2.0 license). VCodecV4L2 uses the V4L2 API and was tested on Raspberry PI4, Raspberry Zero W2, and NVIDIA Jetson platforms. The platform is auto-detected at runtime. The library provides a simple interface to be implemented in different C++ projects. The library is written using the C++17 standard and is supplied as source code only. The library is a CMake project.

Encoding time on NVIDIA Jetson Orin NX (msec, NV12 input, 30 fps, 3000 kbps, pipeline depth=2):

codec / resolution 1920x1080 1280x720 640x480
H264 ~1.24 msec ~0.54 msec ~0.39 msec
HEVC ~1.21 msec ~0.60 msec ~0.38 msec
JPEG N/S N/S N/S

Decoding time on NVIDIA Jetson Orin NX (msec, NV12 output):

codec / resolution 1920x1080 1280x720 640x480
H264 ~2.68 msec ~1.86 msec ~1.41 msec
HEVC N/S N/S N/S
JPEG N/S N/S N/S

Encoding time on Raspberry PI 4B (msec, NV12 input, 30 fps, 3000 kbps):

codec / resolution 1920x1080 1280x720 640x480
H264 ~20.2 msec ~13.4 msec ~5.2 msec
HEVC ~24.9 msec ~10.5 msec ~3.7 msec
JPEG ~30.1 msec ~12.4 msec ~4.1 msec

Decoding time on Raspberry PI 4B (msec, NV12 output):

codec / resolution 1920x1080 1280x720 640x480
H264 ~16.7 msec ~9.9 msec ~5.4 msec
HEVC ~14.7 msec ~10.0 msec ~5.4 msec
JPEG N/S N/S N/S

Versions

Table 1 - Library versions.

Version Release date What’s new
1.0.0 29.06.2023 First version.
2.0.0 02.08.2023 - Interface changes to VCodec.
- Added JPEG encoding support.
- Test application updated.
2.0.1 21.08.2023 - Bug fixed in transcode on copy constructor of dst frame.
2.1.0 28.08.2023 - YUYV input pixel format changed to NV12 for H264 and JPEG codecs.
- Added example application.
2.1.1 20.11.2023 - BGR565 conversion is fixed for JPEG encoding.
2.1.2 10.01.2024 - Submodules updated.
- Documentation updated.
- Test application updated.
2.1.3 15.01.2024 - Bug fixes.
2.2.0 25.04.2024 - Added new method to set hardware encoder device name.
- Documentation updated.
2.2.1 17.05.2024 - Submodules updated.
- Documentation updated.
2.2.2 06.08.2024 - Submodules updated.
2.2.3 04.11.2024 - Update VCodec interface with variable bitrate params.
2.2.4 03.04.2025 - Logger submodule update.
2.2.5 02.11.2025 - VCodec submodule update.
- Documentation update.
3.0.0 23.03.2026 - Added H264 decoding support via V4L2 M2M decoder.
- Added HEVC encoding/decoding support.
- Added NVIDIA Jetson platform support (auto-detected at runtime).
- Platform-specific V4L2 controls applied only on matching hardware.
- Logger integrated into decoder (unified logging).

Library files

The library is supplied as source code only. The user is provided with a set of files in the form of a CMake project (repository). The repository structure is shown below:

CMakeLists.txt -------------- Main CMake file of the library.
3rdparty -------------------- Folder with third-party libraries.
    CMakeLists.txt ---------- CMake file to include third-party libraries.
    Logger ------------------ Folder with Logger library source code.
    VCodec ------------------ Folder with VCodec interface library source code.
example --------------------- Folder with simple example of VCodecV4L2 usage.
    CMakeLists.txt ---------- CMake file for example application.
    main.cpp ---------------- Source code file of example application.
static ---------------------- Folder with static project resources.
    vcodec_v4l2_web_logo.png  Web logo used in README.
test ------------------------ Folder with codec test application.
    CMakeLists.txt ---------- CMake file for codec test application.
    main.cpp ---------------- Source code file of codec test application.
    data -------------------- Pre-generated bitstreams for decoder auto tests.
        test_*.h264 --------- H264 test streams for different resolutions.
        test_*.hevc --------- HEVC test streams for different resolutions.
        test_*.jpeg --------- JPEG test streams for different resolutions.
src ------------------------- Folder with source code of the library.
    CMakeLists.txt ---------- CMake file of the library.
    VCodecV4L2.cpp ---------- C++ implementation file.
    VCodecV4L2.h ------------ Header file which includes VCodecV4L2 class declaration.
    VCodecV4L2Version.h ----- Header file which includes version of the library.
    VCodecV4L2Version.h.in -- CMake service file to generate version file.
    impl -------------------- Internal V4L2 implementation details.
        V4L2Decoder.cpp ----- V4L2 decoder implementation.
        V4L2Decoder.h ------- V4L2 decoder declaration.
        V4L2Encoder.cpp ----- V4L2 encoder implementation.
        V4L2Encoder.h ------- V4L2 encoder declaration.
        V4L2Wrapper.h ------- Shared V4L2 helper declarations.
        VCodecV4L2Impl.cpp -- Internal backend implementation.
        VCodecV4L2Impl.h ---- Internal backend declaration.

VCodecV4L2 class description

VCodecV4L2 class declaration

The VCodecV4L2 class is declared in the VCodecV4L2.h file. Class declaration:

class VCodecV4L2 : public VCodec
{
public:

    /// Get library version.
    static std::string getVersion();

    /// Class constructor.
    VCodecV4L2();

    /// Class destructor.
    ~VCodecV4L2();

    /// Encode video frame.
    bool transcode(Frame& src, Frame& dst);

    /// Set parameter value.
    bool setParam(VCodecParam id, float value);

    /// Get parameter value.
    float getParam(VCodecParam id);

    /// Execute command.
    bool executeCommand(VCodecCommand id);
};

getVersion method

The getVersion() method returns a string of the current version of the VCodecV4L2 class. Method declaration:

static std::string getVersion();

The method can be used without a VCodecV4L2 class instance:

cout << "VCodecV4L2 class version: " << VCodecV4L2::getVersion() << endl;

Console output:

VCodecV4L2 class version: 3.0.0

transcode method

The transcode(…) method is intended to encode and decode video frames (Frame class). The direction (encode or decode) is determined by the fourcc fields of the src and dst frames: if src is NV12 and dst is a compressed format, the library encodes; if src is compressed and dst is NV12, the library decodes. The video codec processes frames one at a time. Method declaration:

bool transcode(Frame& src, Frame& dst);
Parameter Value
src Source video frame (see Frame class description). For encoding: must have raw pixel format NV12. For decoding: must have compressed format H264 or HEVC (set size to the actual bitstream length).
dst Result video frame (see Frame class description). For encoding: must have compressed format JPEG, H264, or HEVC. For decoding: must have raw pixel format NV12.

Returns: TRUE if the frame was encoded or FALSE if not.

setParam method

The setParam(…) method is designed to set new video codec parameter values. Method declaration:

setParam(VCodecParam id, float value);
Parameter Description
id Video codec parameter ID according to VCodecParam enum.
value Video codec parameter value.

Returns: TRUE if the parameter was set or FALSE if not.

The VCodec.h file of the VCodec library defines IDs for parameters (VCodecParam enum) and IDs for commands (VCodecCommand enum). VCodecParam declaration:

namespace cr
{
namespace video
{
enum class VCodecParam
{
    /// [read/write] Log level: 0-Disable, 1-Console, 2-File, 3-Console and file.
    LOG_LEVEL = 1,
    /// [read/write] Bitrate, kbps. For H264 and H265 codecs.
    BITRATE_KBPS,
    /// [read/write] Minimum bitrate, kbps. For variable bitrate mode.
    MIN_BITRATE_KBPS,
    /// [read/write] Maximum bitrate, kbps. For variable bitrate mode.
    MAX_BITRATE_KBPS,
    /// [read/write] Bitrate mode: 0 - constant bitrate, 1 - variable bitrate.
    BITRATE_MODE,
    /// [read/write] Quality 0-100%. For JPEG codecs.
    QUALITY,
    /// [read/write] FPS. For H264 and H265 codecs.
    FPS,
    /// [read/write] GOP size. For H264 and H265 codecs.
    GOP,
    /// [read/write] H264 profile: 0 - Baseline, 1 - Main, 2 - High.
    H264_PROFILE,
    /// [read/write] Codec type. Depends on implementation.
    TYPE,
    /// Custom 1. Depends on implementation.
    CUSTOM_1,
    /// Custom 2. Depends on implementation.
    CUSTOM_2,
    /// Custom 3. Depends on implementation.
    CUSTOM_3
};
}
}

Table 2 - Video codec parameter descriptions. Some parameters are not supported by the particular VCodecV4L2 library.

Parameter Access Description
LOG_LEVEL read / write Logging mode. Values:
0 - Disable.
1 - Only file.
2 - Only terminal (console).
3 - File and terminal.
BITRATE_KBPS read / write Bitrate in kbps. Range: 0 - 1,000,000 kbps. Default: 2000 kbps. For H264/HEVC encoding only. Applied on-the-fly if the encoder is running.
QUALITY read / write JPEG quality. Range: 1 - 100 (1 = low quality, 100 = maximum quality). Default: 80. For JPEG hardware encoding only. Triggers encoder reinit on next transcode() call.
FPS read / write Frame rate. Range: 1 - 1000 fps. Default: 30 fps. For H264/HEVC encoding only. Applied on-the-fly if the encoder is running.
GOP read / write GOP size (period of key frames). Range: 1 - 10,000. Default: 30. For H264/HEVC encoding only. Value 1 means each output frame is a key frame, 20 means every 20th frame is a key frame, etc. Applied on-the-fly if the encoder is running.
H264_PROFILE read / write H264 profile for H264 encoding:
0 - Baseline.
1 - Main.
2 - High.
Triggers encoder reinit on next transcode() call.
MIN_BITRATE_KBPS read / write Not supported by VCodecV4L2 library.
MAX_BITRATE_KBPS read / write Not supported by VCodecV4L2 library.
BITRATE_MODE read / write Not supported by VCodecV4L2 library.
TYPE read / write Not supported by VCodecV4L2 library.
CUSTOM_1 read / write Pipeline depth* for encoder and decoder. Default: 2 (also used when value ≤ 0). Range 1 - 4 (values > 4 are clamped to 4). Triggers reinit on next transcode() call.
CUSTOM_2 read / write Not supported by VCodecV4L2 library.
CUSTOM_3 read / write Not supported by VCodecV4L2 library.

Note on parameter change behavior. Parameters BITRATE_KBPS, FPS, and GOP are applied immediately via V4L2 controls without interrupting the encoding pipeline. Parameters H264_PROFILE, QUALITY, and CUSTOM_1 require a full hardware codec restart (close device, reopen, reconfigure formats and buffers). This reinit happens automatically on the next transcode() call and may cause a brief latency spike on that frame.

*Pipeline depth (CUSTOM_1) controls the number of V4L2 output buffers used by the encoder and decoder. This determines the overlap between frame submission and result retrieval:

  • CUSTOM_1 = 1: No overlap. Each transcode() call submits a frame, waits for the codec to finish, and returns the result. 0-frame delay, but the codec idles between calls. Best for synchronous pipelines where latency matters more than throughput (e.g. real-time control, AR).
  • CUSTOM_1 = 2 (default): 1-level overlap. While the codec processes frame N, frame N-1’s result is returned. 1-frame delay, but ~2× throughput because the codec never idles. Best for video streaming.
  • CUSTOM_1 = 3-4: Deeper pipeline. Diminishing returns — the codec processes frames sequentially, so more than 2 buffers rarely helps.

On NVIDIA Jetson, CUSTOM_1 also controls the NVENC encoder pipeline depth (affects both encode latency and throughput). On Generic/RPi, it controls decoder output buffer count.

getParam method

The getParam(…) method is designed to obtain video codec parameter values. Method declaration:

float getParam(VCodecParam id);
Parameter Description
id Video codec parameter ID according to VCodecParam enum (see Table 2).

Returns: parameter value or -1 if the parameter is not supported.

executeCommand method

The executeCommand(…) method is designed to execute video codec commands. The current version supports the MAKE_KEY_FRAME command. Method declaration:

bool executeCommand(VCodecCommand id);
Parameter Description
id Video codec command ID according to VCodecCommand enum.

Returns: TRUE if the command was accepted or FALSE if not.

The VCodec.h file of the VCodec library defines IDs for parameters (VCodecParam enum) and IDs for commands (VCodecCommand enum). VCodecCommand declaration:

enum class VCodecCommand
{
    /// Reset.
    RESET = 1,
    /// Generate key frame. For H264 and H265 codecs.
    MAKE_KEY_FRAME
};

Table 3 - Video codec command descriptions. Some commands may be unsupported by particular video codec classes.

Command Description
RESET Not supported by VCodecV4L2.
MAKE_KEY_FRAME Generate the next key frame (for H264 encoder). Some hardware may not support this function.

Build and connect to your project

Install additional software:

sudo apt-get -y install build-essential cmake git

Typical commands to build VCodecV4L2 library:

cd VCodecV4L2
git submodule update --init --recursive
mkdir build
cd build
cmake ..
make

If you want to connect the VCodecV4L2 library to your CMake project as source code, you can follow these steps. For example, if your repository has the following structure:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp

Create a folder 3rdparty in your repository. Copy the repository folder VCodecV4L2 to the 3rdparty folder. The new structure of your repository:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp
3rdparty
    VCodecV4L2

Create a CMakeLists.txt file in the 3rdparty folder. The CMakeLists.txt should contain:

cmake_minimum_required(VERSION 3.13)

################################################################################
## 3RD-PARTY
## dependencies for the project
################################################################################
project(3rdparty LANGUAGES CXX)

################################################################################
## SETTINGS
## basic 3rd-party settings before use
################################################################################
# To inherit the top-level architecture when the project is used as a submodule.
SET(PARENT ${PARENT}_YOUR_PROJECT_3RDPARTY)
# Disable self-overwriting of parameters inside included subdirectories.
SET(${PARENT}_SUBMODULE_CACHE_OVERWRITE OFF CACHE BOOL "" FORCE)

################################################################################
## INCLUDING SUBDIRECTORIES
## Adding subdirectories according to the 3rd-party configuration
################################################################################
add_subdirectory(VCodecV4L2)

The file 3rdparty/CMakeLists.txt adds the folder VCodecV4L2 to your project and will exclude test applications from compiling. Your repository’s new structure will be:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp
3rdparty
    CMakeLists.txt
    VCodecV4L2

Next, you need to include the folder 3rdparty in the main CMakeLists.txt file of your repository. Add this string at the end of your main CMakeLists.txt:

add_subdirectory(3rdparty)

Next, you have to include the VCodecV4L2 library in your src/CMakeLists.txt file:

target_link_libraries(${PROJECT_NAME} VCodecV4L2)

Done!

Simple example

The example application generates an image color pattern with a moving rectangle and writes compressed data to a binary file “out.h264”. The example shows how to create codec objects and how to encode video frames:

#include <iostream>
#include "VCodecV4L2.h"

int main(void)
{
    // Create codec and set params.
    cr::video::VCodec* videoCodec = new cr::video::VCodecV4L2();
    videoCodec->setParam(cr::video::VCodecParam::BITRATE_KBPS, 2500);
    videoCodec->setParam(cr::video::VCodecParam::GOP, 30);
    videoCodec->setParam(cr::video::VCodecParam::FPS, 30);
    videoCodec->setParam(cr::video::VCodecParam::H264_PROFILE, 0);

    // Create NV12 frame and fill color plane by random values.
    const int width = 1280;
    const int height = 720;
    cr::video::Frame frameNv12(width, height, cr::video::Fourcc::NV12);
    for (uint32_t i = 0; i < frameNv12.size; ++i)
        frameNv12.data[i] = (uint8_t)i;

    // Create output H264 frame.
    cr::video::Frame frameH264(width, height, cr::video::Fourcc::H264);

    // Create output file.
    FILE *outputFile = fopen("out.h264", "w+b");
    
    // Params for moving object.
    int objectWidth = 128;
    int objectHeight = 128;
    int directionX = 1;
    int directionY = 1;
    int objectX = width / 4;
    int objectY = height / 2;

    // Encode and record 200 frames.
    for (uint8_t n = 0; n < 200; ++n)
    {
        // Draw moving object.
        memset(frameNv12.data, 128, width * height);
        for (int y = objectY; y < objectY + objectHeight; ++y)
            for (int x = objectX; x < objectX + objectHeight; ++x)
                frameNv12.data[y * width + x] = 255;
        objectX += directionX;
        objectY += directionY;
        if (objectX >= width - objectWidth - 5 || objectX <= objectWidth + 5)
            directionX = -directionX;
        if (objectY >= height - objectHeight - 5 || objectY <= objectHeight + 5)
            directionY = -directionY;

        // Encode.
        if (!videoCodec->transcode(frameNv12, frameH264))
        {
            std::cout << "Can't encode frame" << std::endl;
            continue;
        }

        // Write to file.
        fwrite(frameH264.data, frameH264.size, 1, outputFile);
    }

    // Close file.
    fclose(outputFile);

    return 1;
}

Test application

The test application (VCodecV4L2/test/main.cpp) for the VCodecV4L2 C++ library has two modes: Manual encoder test and Auto test. All parameters are entered via an interactive terminal dialog (no command-line arguments). The platform is auto-detected at runtime. To run the application:

cd build
./bin/VCodecV4L2Test

After starting, you will see the mode selection menu:

========================================
  VCodecV4L2 v3.0.0 test
========================================

========================================
              SET MODE
========================================
  1 - Manual encoder
  2 - Auto test
  0 - Exit
>

Manual encoder mode

Allows to select a codec (H264, HEVC, or JPEG), use default parameters or enter custom ones (resolution, frame count, bitrate/GOP/FPS/profile for H264/HEVC, or quality for JPEG), and encode a test video pattern. The test pattern consists of 8 colored vertical bars with a scrolling brightness wave and a white square bouncing diagonally. Encoded output is saved to out.h264, out.hevc, or out.jpeg. For JPEG, only the last encoded frame is kept in the file.

=== MANUAL ENCODER TEST ===
Codec (0-H264, 1-HEVC, 2-JPEG): 0

Defaults:
  Resolution: 1920x1080
  Frames: 100
  Bitrate: 3000 kbps
  FPS: 30
  GOP: 30
  Profile: Baseline

Use defaults? (1-yes, 0-no): 1

Output: out.h264
  Frame 100/100  size=5765  time=10.52 ms

========================================
           SUMMARY
========================================
Encoded: 98/100
Avg: 10.75 ms/frame
File: out.h264

Auto test mode

Runs encoding and decoding tests for all 3 codecs (H264, HEVC, JPEG) across 3 resolutions (1920x1080, 1280x720, 640x480) with 100 frames each. Decoding uses pre-generated test data files from test/data/. If a codec returns an error on the first frame, it is reported as N/S (not supported). After all tests complete, a summary table is displayed:

=== ENCODING ===
  H264 1920x1080 ... 10.75 ms (98/100)
  H264 1280x720  ...  5.50 ms (98/100)
  ...

=== DECODING ===
  H264 1920x1080 ...  5.10 ms (96/100)
  ...
  JPEG 1920x1080 ... N/S

========================================
           SUMMARY
========================================

  Codec Res        | Encode             | Decode
  ----- ---------- | ------------------ | ------------------
  H264  1920x1080  |  10.75 ms  98/100  |   5.10 ms  96/100
  H264  1280x720   |   5.50 ms  98/100  |   2.50 ms  96/100
  H264  640x480    |   1.80 ms  98/100  |   0.80 ms  96/100
  ----- -----------+--------------------+------------------
  HEVC  1920x1080  |  10.80 ms  98/100  |   5.30 ms  96/100
  ...
  ----- -----------+--------------------+------------------
  JPEG  1920x1080  |  24.00 ms 100/100  | N/S
  ...

Table of contents