
VCodecLibva C++ library
v1.2.2
Table of contents
- Overview
- Versions
- Library files
- VCodecLibva class description
- Portability
- Build and connect to your project
- Simple example
- Test application
Overview
The VCodecLibva C++ library provides hardware video encoding and decoding for H264, HEVC and JPEG codecs based on the LibVA library (hardware acceleration based on the VAAPI interface) on Linux only. Encoding and decoding run on the GPU: the decoder parses the stream headers and the hardware decodes the picture data (VA-API VLD entrypoint). The decoder re-initializes itself automatically when the codec, resolution or stream parameters change, detects the color range of the stream (limited when the stream does not tell) and converts limited (video) range pictures to full range. The encoder takes the frames as full range and marks the encoded data as full range. The VCodecLibva video codec class inherits interface and data structures from the VCodec interface library. The library depends on the VCodec library (provides codec interface), the Frame library (provides the video frame class of the codec interface), the open-source LibVA library, and the Logger (provides functions to print logs). The VCodec, Frame and Logger libraries are not part of the repository (see Build and connect to your project). The library uses the C++17 standard.
VCodecLibva 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.
Encoding and decoding time per frame on Intel(R) Core(TM) Ultra 5 125U, Ubuntu 24.04.4, Intel iHD driver 25.2.3, measured by the speed test of the test application (H264 and H265: 5000 kbps constant bitrate, GOP 30, H264 Baseline profile; JPEG: quality 95). The decoding time is the time of the transcode(…) call that returns the decoded frame in CPU memory in NV12 format. The streams of the encoder are full range; the conversion of a limited range stream to full range adds about 0.1 msec per 1920x1080 frame:
| Hardware codec / resolution | 1920x1080 | 1280x720 | 640x512 |
|---|---|---|---|
| H264 encoding | 7.3 msec | 3.8 msec | 1.9 msec |
| H264 decoding | 3.1 msec | 1.9 msec | 1.1 msec |
| H265 encoding | 7.5 msec | 4.0 msec | 2.1 msec |
| H265 decoding | 3.0 msec | 1.8 msec | 1.0 msec |
| JPEG encoding | 8.5 msec | 4.2 msec | 2.0 msec |
| JPEG decoding | 3.9 msec | 2.1 msec | 1.2 msec |
Versions
Table 1 - Library versions.
| Version | Release date | What’s new |
|---|---|---|
| 1.0.0 | 18.03.2026 | First version. |
| 1.0.1 | 27.03.2026 | - Fixed HEVC and H264 artifacts - Fixed MAKE_KEY_FRAME command - Optimized HEVC and H264 codecs - Added HRD and SEI to H264 codec - Set VBR as default for H264 and HEVC |
| 1.0.2 | 15.06.2026 | - Fixed HEVC encoding - Fixed typos in H264 - Fixed H264 high profile encoding - Fixed JPEG quality changing - Fixed memory leaks - Fixed H264 frame cropping |
| 1.1.0 | 17.09.2026 | - Added MIN_BITRATE_KBPS and MAX_BITRATE_KBPS support for variable bitrate mode (H264 and HEVC). - The VBV buffer and the sequence header now carry the peak rate instead of the target. - Fixed an uninitialised codec-type member - Added test/rate_quality, a behavioural test covering rate control and quality on real hardware. - B-frames are now disabled by construction for H264 and H265. - Fixed GOP size control. - Additional critical issues fixed. |
| 1.2.0 | 02.10.2026 | - Added hardware decoding of H264, H265 (HEVC) and JPEG. |
| 1.2.1 | 08.10.2026 | - Code review of the whole library: all data from streams, frames and parameters is validated, memory use is bounded, no exception leaves the library, the methods are thread safe. - Fixed an out-of-bounds read of the decoders for a crop rectangle that does not fit the picture. - Fixed a hang of the decoders on pictures narrower than 64 pixels. - Fixed encoding of YU12 and YV12 frames, of frames whose size is not a multiple of 16, the alignment bits of CABAC slices, the SEI of H264 and an overflow of the reference list of HEVC. - Stricter parameter ranges: frame sizes are even and up to 16384 pixels, GOP up to 65535, FPS up to 1000. - Added warnings and exploit mitigation options to CMake. - Added the Limits and guarantees, Security and hardening, Portability and SIMD and Testing sections. |
| 1.2.2 | 18.10.2026 | - The repository does not include the VCodec, Frame and Logger libraries: they are cloned next to it or added by the parent project (see Build and connect to your project). - HEVC encoder: the level and the tier follow the frame size, the frame rate and the peak bitrate, also after a bitrate change (an IDR picture follows when they must rise); the coding tools and block sizes follow the capabilities of the driver; one reference picture; P pictures are B slices whose two lists hold the previous picture for drivers that require both reference lists; the VA buffers of a picture are released after it is encoded. - H264 encoder: the level follows the peak bitrate and the frame sides, also after a bitrate change; cpb_removal_delay of the picture timing SEI counts from the last buffering period; the same HRD rate in the stream and in the rate controller. - JPEG encoder: the quantization tables of the header are the tables of the hardware; frames whose size is not a multiple of the MCU size are padded with their edge pixels. - Decoders: fixed JPEG restart markers with fill bytes, tables redefined between scans, RGB images; H264 and HEVC fixes of reference handling, POC, DPB size limits and parameter set updates; further checks of stream data. - Encoders: the size of the result frame is 0 after every failure, frames smaller than 16x16 pixels are refused, a driver without the requested bitrate mode uses the other one; H264 and HEVC coded data without a slice of the picture is refused and is not the reference of the next frame; the H264 and HEVC coded buffers hold twice the samples of a frame and have room for drivers that reserve a part of them. - LOG_LEVEL, H264_PROFILE, BITRATE_MODE and GOP take integer values only. - The test application runs automatic tests. |
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.
src -------------------------- Folder with library source code.
CMakeLists.txt ----------- CMake file of the library.
VCodecLibva.h ------------ Main library header file.
VCodecLibvaVersion.h ----- Header file with library version.
VCodecLibvaVersion.h.in -- File for CMake to generate version header.
VCodecLibva.cpp ---------- C++ implementation file.
impl --------------------- Folder with codec implementation files.
VaCodecH264.h -------- H264 encoder class header.
VaCodecH264.cpp ------ H264 encoder class implementation.
VaCodecHevc.h -------- HEVC encoder class header.
VaCodecHevc.cpp ------ HEVC encoder class implementation.
VaCodecJpeg.h -------- JPEG encoder class header.
VaCodecJpeg.cpp ------ JPEG encoder class implementation.
VaDecoderBase.h ------ Base class of the decoders header.
VaDecoderBase.cpp ---- Base class of the decoders: VA pipeline, output queue, frame conversion.
VaDecoderH264.h ------ H264 decoder class header.
VaDecoderH264.cpp ---- H264 decoder class implementation.
VaDecoderHevc.h ------ HEVC decoder class header.
VaDecoderHevc.cpp ---- HEVC decoder class implementation.
VaDecoderJpeg.h ------ JPEG decoder class header.
VaDecoderJpeg.cpp ---- JPEG decoder class implementation.
VaBitReader.h -------- Bitstream reader of the decoders.
VaBitstreamState.h --- Bitstream writer of the encoders.
VaCommon.h ----------- Common definitions and helper functions of the encoders, the decoders and the facade.
VaH264Structures.h --- H264 level limits of the encoder.
VaHevcStructures.h --- HEVC level limits of the encoder.
VaJpegStructures.h --- JPEG tables of the encoder and the decoder (zigzag order, quantization and Huffman tables).
test ------------------------- Folder for test application.
CMakeLists.txt ----------- CMake file for test application.
main.cpp ----------------- Source C++ file of test application.
rate_quality ------------- Rate control and quality test (needs a GPU).
CMakeLists.txt ------- CMake file of the test.
main.cpp ------------- Source C++ file of the test.
lowdelay ----------------- B-frame and latency test (needs a GPU).
CMakeLists.txt ------- CMake file of the test.
main.cpp ------------- Source C++ file of the test.
example ---------------------- Folder for simple example.
CMakeLists.txt ----------- CMake file of example.
main.cpp ----------------- Source C++ file of example.
VCodecLibva class description
VCodecLibva class declaration
The VCodecLibva class is declared in the VCodecLibva.h file. Class declaration:
namespace rapidpixel
{
class VCodecLibva : public VCodec
{
public:
/// Class constructor.
VCodecLibva() = default;
/// Class destructor.
~VCodecLibva() override;
/// The codec owns a VA display and its objects: it is neither copyable
/// nor movable.
VCodecLibva(const VCodecLibva&) = delete;
VCodecLibva(VCodecLibva&&) = delete;
VCodecLibva& operator=(const VCodecLibva&) = delete;
VCodecLibva& operator=(VCodecLibva&&) = delete;
/// Get library version.
static std::string getVersion();
/// Encode or decode video frame.
bool transcode(Frame& src, Frame& dst) override;
/// Set parameter value.
bool setParam(VCodecParam id, float value) override;
/// Get parameter value.
float getParam(VCodecParam id) override;
/// Execute command.
bool executeCommand(VCodecCommand id) override;
};
}
The methods of the class are thread safe: the calls of one object are serialized by a mutex, one object can be used from several threads. No method throws an exception: a failure, also when memory runs out, is reported by the return value. All VA-API objects (surfaces, buffers, contexts, images) are released when the codec is re-initialized or destroyed, also after errors.
getVersion method
The getVersion() method returns a string of the current version of the VCodecLibva class. Method declaration:
static std::string getVersion();
This method can be used without a VCodecLibva class instance:
std::cout << "VCodecLibva class version: " << rapidpixel::VCodecLibva::getVersion() << std::endl;
Console output:
VCodecLibva class version: 1.2.2
transcode method
The transcode(…) method is intended to encode and decode video frames (Frame class). The video codec processes video frames frame-by-frame. The method encodes when the dst frame has a compressed pixel format and decodes when the src frame has a compressed pixel format and the dst frame a raw one. One VCodecLibva object can encode and decode alternately. Method declaration:
bool transcode(Frame& src, Frame& dst);
| Parameter | Value |
|---|---|
| src | Source video frame (see Frame class description). To encode video data, the src frame must have NV12, YU12 or YV12 pixel format for H264 and HEVC, or NV12 or UYVY pixel format for JPEG. Frames to encode are taken as full range (Y, Cb and Cr 0 - 255), and the encoded data says so: H264 and HEVC streams carry video_full_range_flag = 1 in the VUI of the sequence parameter set, JPEG images carry the JFIF APP0 marker, which defines full range samples. To decode video data, the src frame must have a compressed pixel format (JPEG, H264 or HEVC) and contain one frame of compressed data: an access unit of an H264 or HEVC Annex B byte stream (NAL units with start codes; parameter sets and SEI go with the picture they precede) or one complete JPEG image. To get the frames the decoder still holds after the end of the stream, pass an empty src frame (size 0) with the same compressed pixel format until the method returns FALSE. |
| dst | Result video frame (see Frame class description). To encode video data, the dst frame must have a compressed pixel format (field fourcc of Frame class): JPEG, H264, or HEVC. To decode video data, the dst frame must have a raw pixel format: NV12, NV21, YU12, YV12 or GRAY (any other raw format gives NV12). The user must specify the output pixel format in advance. The decoder sets the size of the dst frame from the stream (the cropped picture size; 4:2:0 formats round odd sizes down to even, a 641x481 image gives a 640x480 frame, a picture 1 pixel wide or high is refused for them; GRAY keeps the exact size) and copies the frameId and sourceId fields of the source frame that carried the picture. |
Returns: TRUE if the frame was encoded or a decoded frame was returned in dst, or FALSE if not: the size of dst is 0 then. When decoding, FALSE is not an error by itself: the decoder may have no frame to return yet (frames reordered for B-frames, the stream started without a key frame).
Encoding details:
- The frame to encode must have even width and height from 16 to 16384 pixels, its data pointer must be set and its size must hold the whole picture (NV12, YU12 and YV12: width * height * 3 / 2 bytes, UYVY: width * height * 2 bytes). The area is limited to 67108864 pixels (8192 x 8192) for JPEG and to 35651584 pixels (level 6.2) for H264 and HEVC, counted for the size rounded up to multiples of 16. A frame that breaks the rules is refused: the method returns FALSE, the size of dst is 0, the other fields of dst are not changed and the state of the encoder stays valid. The hardware may refuse sizes it does not support.
- The encoder is initialized by the first frame and again when the size of the frames, the codec, FPS, GOP, BITRATE_MODE or H264_PROFILE changes: a new stream starts with a key frame. BITRATE_KBPS, MIN_BITRATE_KBPS, MAX_BITRATE_KBPS and QUALITY take effect from the next frame. A frame whose size is not a multiple of the block size of the codec (16 for H264 and HEVC, the MCU size for JPEG) is padded with its edge pixels and the stream tells the size of the frame (cropping of H264 and HEVC, frame header of JPEG), so the decoder returns the original size.
- The encoded frame is returned by the same call that passed the source frame (no frame is held, no B-frames). The dst frame memory is allocated by the Frame class (width * height * 4 bytes); coded data that does not fit it is an error, and so is H264 and HEVC coded data without a slice of the picture (a driver that fails a picture without reporting it may leave the data of an earlier picture): such a picture is not the reference of the next frame. On success dst gets the frameId and sourceId of src. A key frame requested by MAKE_KEY_FRAME that could not be encoded is requested again for the next frame.
- H264 and HEVC streams consist of IDR and P pictures, every P picture refers to the previous picture. A driver that requires both reference picture lists for HEVC inter pictures (VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) gets the P pictures as B slices whose two lists hold the previous picture: the prediction is the same and no frame is held. The parameter sets precede every IDR picture (H264: sequence and picture parameter sets; HEVC: video and sequence parameter sets, the HEVC picture parameter set precedes every picture). The level (and the tier of HEVC) is the lowest one whose limits the frame size, the frame rate and the peak bitrate (MAX_BITRATE_KBPS in variable bitrate mode, BITRATE_KBPS otherwise) keep; when a bitrate change needs a higher level, the next frame is an IDR picture with new parameter sets. The coding tools and block sizes of HEVC follow the capabilities the driver reports. The encoder writes the parameter sets, the slice headers and, for H264 in constant bitrate mode, the HRD parameters with buffering period and picture timing SEI itself when the driver accepts them (packed headers); with a driver that writes the sequence parameter set itself the stream does not tell that it is full range (a warning is printed).
Decoding details:
- Decoding runs on the GPU through the VA-API VLD entrypoint. Supported streams: H264 Constrained Baseline, Main and High profiles (8 bit 4:2:0, progressive frames and MBAFF); HEVC Main, Main 10 and Main Still Picture profiles (Main 10 with the same bit depth of luma and chroma, 8 or 10 bit; 10 bit pictures are returned as 8 bit); JPEG baseline and extended sequential Huffman coding with 8 bit samples in 4:2:0, 4:2:2, 4:4:0, 4:4:4, 4:1:1 or grayscale (chroma is converted to 4:2:0 for the output). Not supported: H264 field pictures (PAFF), flexible macroblock ordering, arbitrary slice order, data partitioning, SP and SI slices, lossless coding, bit depths other than 8 and chroma formats other than 4:2:0 (High 10, High 4:2:2 and High 4:4:4 profiles); HEVC range extensions (4:2:2, 4:4:4, 12 bit); progressive, lossless and arithmetic coded JPEG. The driver may restrict this further: the Intel iHD driver refuses JPEG images whose components all have the same sampling factors other than 1x1.
- JPEG images that are refused (the method returns FALSE): progressive, lossless, hierarchical and arithmetic coding; sample precision other than 8 bits; quantization values 0 or above 255; scans that select Huffman tables 2 or 3; a Huffman table that changes after a scan used it (VA-API takes one set of tables for the picture); 2 or 4 components; RGB images (APP14 colour transform 0, or component identifiers ‘R’, ‘G’, ‘B’ without JFIF and APP14 segments) and the SPIFF colour spaces 9 to 14; height 0 in the frame header (DNL); more than 16384 samples per side or 67108864 samples; scans that break the rules of ISO/IEC 10918-1 B.2.3; a second SOI, data that ends before EOI and scans with less than 2 bits of entropy coded data per block. Tolerated: bytes before SOI, between marker segments and after EOI are ignored, fill bytes 0xFF before a marker (restart markers included) are removed, and marker segments the decoder does not use are skipped. Quantization tables are kept from image to image until RESET: an image without DQT segments (abbreviated format) is decoded with the tables of the last accepted image or tables-only datastream. Huffman tables missing in an image (typical for MJPEG cameras) are replaced by the default tables of ISO/IEC 10918-1 Annex K.3.
- The decoder re-initializes itself automatically. A change of the compressed pixel format of src creates a new decoder: frames the previous decoder still holds are dropped unless they are taken first with empty src frames. A change of resolution, profile, bit depth, chroma subsampling or number of reference frames inside a stream re-creates the hardware pipeline (a stream that changes the resolution at every key frame pays this for every key frame); the frames of the previous sequence that are still held are copied to CPU memory and returned first, within the copy limit described below.
- Frames are returned in display order. Streams without B-frames return each frame from the call that passed its data. Decoding starts at the first key frame; damaged data is skipped and decoding resumes at the next decodable frame. A picture is decoded only when every reference of it exists. An H264 stream that starts at an I picture that is not an IDR picture (open GOP) is an exception: the B pictures that follow the I picture in decoding order and precede it in display order refer to pictures before it, which the decoder does not have; they are decoded with the pictures it has and returned, and may show errors. Numbers read from a stream (sizes, counts, offsets, crop rectangles, list sizes) are checked against the limits of the standards before they are used; the number of reference pictures is limited by the level limits of the standards, the number of slices of a picture to 1024. Slices above that number and slices whose address is not above the address of the previous slice of the picture (arbitrary slice order) are ignored: the part of the picture they cover is not decoded.
- The decoder holds at most 64 decoded pictures for the application: one is returned per call, the oldest are dropped when the application does not collect them. One call decodes at most 64 pictures: the rest of a source frame with more pictures is not decoded and decoding resumes at the next key frame. Pictures that are copied to CPU memory to free their surfaces use at most 512 MiB; the oldest are dropped first.
- The decoder detects the color range of every picture from the data and takes it as limited range when the data does not tell. H264 and HEVC: video_full_range_flag of the VUI of the sequence parameter set; a stream without the flag is limited range, as the H264 and H265 standards specify. JPEG: the JFIF (APP0), Exif (APP1) and Adobe (APP14) markers mean full range; the comment “CS=ITU601” (written by FFmpeg for limited range images, next to the JFIF marker) and the video color spaces of a SPIFF header (APP8) mean limited range and take precedence; an image with none of them (for example a bare MJPEG frame) is limited range. Limited range pictures (Y 16 - 235, Cb and Cr 16 - 240) are converted to full range (0 - 255) while the frame is copied to the dst frame, in the same single pass (SSE2): Y’ = (Y - 16) * 255 / 219, C’ = (C - 16) * 255 / 224, neutral chroma 128 stays 128. Full range pictures are copied without a range conversion. The conversion costs about 0.1 msec per 1920x1080 frame over the copy itself.
- The decoded picture is copied from the GPU to CPU memory by the video processor (VA-API VideoProc) into memory of the decoder. Drivers without it fall back to vaGetImage(…), then to vaDeriveImage(…). Pictures narrower than 64 pixels or lower than 16 pixels are always read with vaGetImage(…): the video processor of the tested hardware never completes the copy of a narrower picture and does not take lower surfaces.
setParam method
The setParam(…) method is designed to set new video codec parameter values. Method declaration:
bool setParam(VCodecParam id, float value);
| Parameter | Description |
|---|---|
| id | Video codec parameter ID according to the VCodecParam enum. |
| value | Video codec parameter value. Valid values depend on the parameter ID. |
Returns: TRUE if the parameter was set successfully 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 rapidpixel
{
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 parameters description. Some parameters are not supported by the VCodecLibva library. Decoding needs no parameters: the decoder uses only LOG_LEVEL, all other parameters are encoder parameters. A value that is not a number (NaN, infinity) or lies outside the range of the parameter is refused (the method returns FALSE) and the parameter keeps its value.
| Parameter | Access | Description |
|---|---|---|
| LOG_LEVEL | read / write | Logging mode of the encoder and the decoder. Values: 0 - Disable. 1 - Only terminal (console). 2 - Only file. 3 - File and terminal. Other values (also fractional ones) are refused. Messages about repeated errors of the encoder and the decoder are limited in number. |
| BITRATE_KBPS | read / write | Bitrate, kbps. Valid range 100 - 1000000 (fractional values are truncated). Default: 5000 kbps. For H264 and H265 (HEVC) encoding. In constant bitrate mode this is the rate the stream is held at. In variable bitrate mode it is the target (average) rate; the peak is MAX_BITRATE_KBPS. According to this value, FPS, and GOP size, the video codec calculates parameters for H264 or H265 (HEVC) encoding. |
| MIN_BITRATE_KBPS | read / write | Minimum bitrate, kbps. Valid values: 0 (no floor, the default) or 100 - 1000000. For H264 and H265 (HEVC) encoding in variable bitrate mode only; ignored in constant bitrate mode and by the JPEG codec. Not a hardware-enforced floor. VA-API’s rate controller ( VAEncMiscParameterRateControl) has no minimum-bitrate field, so the driver cannot be told to keep a stream above a given rate, and a variable bitrate is by definition free to spend fewer bits on content that does not need them. What this parameter does is raise the target when BITRATE_KBPS has been configured below it, so a contradictory configuration resolves in favour of the floor the caller asked for rather than silently ignoring it. A guaranteed rate needs constant bitrate mode (BITRATE_MODE = 0), where the encoder pads the stream to hold the rate.Measured on Intel iHD 25.2.3 at 1280x720 / 30 fps with incompressible content: a 2000 kbps target with no floor encodes at 1910 kbps, and the same target under a 5000 kbps floor encodes at 4669 kbps. Note also that the hardware has a floor of its own that no parameter lowers - the same clip will not encode below roughly 3 Mbps on Baseline profile whatever rate is requested, because the content does not compress that far. |
| MAX_BITRATE_KBPS | read / write | Maximum bitrate, kbps. Valid values: 0 (no ceiling above the target, the default) or 100 - 1000000. For H264 and H265 (HEVC) encoding in variable bitrate mode only; ignored in constant bitrate mode and by the JPEG codec. This is the peak the rate controller may generate, published to the driver as bits_per_second, with BITRATE_KBPS expressed against it as a percentage. It gives a variable bitrate stream its headroom: a key frame or a burst of motion may reach this rate while the average stays at BITRATE_KBPS. A value below BITRATE_KBPS, or 0, is not an error and does not reduce the target - the peak is then taken as the target itself, so the stream simply has no headroom. |
| BITRATE_MODE | read / write | Bitrate mode for H264 and H265 (HEVC) codecs only. Values: 0 - constant bitrate, 1 - variable bitrate depending on content (default). Other values (also fractional ones) are refused. In constant bitrate mode BITRATE_KBPS alone describes the stream and MIN/MAX_BITRATE_KBPS are ignored. In variable bitrate mode the three act together: BITRATE_KBPS is the average, MAX_BITRATE_KBPS the peak, MIN_BITRATE_KBPS a lower bound on the average. A driver that does not have the mode asked for gets the other one: getParam(…) returns the mode in force. |
| QUALITY | read / write | Quality 0 (low quality) - 100% (maximum quality). Default: 100. For the JPEG codec only. The value scales the JPEG quantisation tables; values outside 0 - 100 are refused. Fractional values are truncated, and a quality of 0 is accepted for interface compatibility and taken as 1, the lowest value the quantisation formula is defined for; getParam(…) returns the value in force. H264 and H265 (HEVC) are rate-controlled codecs and have no quality factor: their picture quality is the outcome of BITRATE_KBPS, MIN/MAX_BITRATE_KBPS and BITRATE_MODE. setParam() refuses QUALITY for them once the codec is known, rather than reporting success for a setting that does nothing. The codec type is latched from the first destination frame passed to transcode(), so a QUALITY set before the first frame is accepted and kept for whichever codec the caller goes on to use. |
| FPS | read / write | Frames per second. Valid range 1 - 1000, fractional values are allowed (29.97 is written to the stream as a fraction). Default value is 30. For H264 and H265 (HEVC) encoding only. According to this value, bitrate, and GOP size, the video codec calculates parameters for H264 and H265 (HEVC) encoding. |
| GOP | read / write | GOP size (period of key frames) for H264 and H265 (HEVC) encoding. Valid range 1 - 65535, integer values only. Value: 1 - each output frame is a key frame, 20 - each 20th frame is a key frame, etc. Default: 30. |
| H264_PROFILE | read / write | H264 profile for H264 encoding: 0 - Baseline (default; Constrained Baseline). 1 - Main. 2 - High. Other values (also fractional ones) are refused. |
| TYPE | read / write | Not supported by VCodecLibva library. |
| CUSTOM_1 | read / write | Not supported by VCodecLibva library. |
| CUSTOM_2 | read / write | Not supported by VCodecLibva library. |
| CUSTOM_3 | read / write | Not supported by VCodecLibva library. |
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 the VCodecParam enum (see Table 2). |
Returns: Parameter value or -1 if the parameter doesn’t exist in the particular video codec class. The parameters of H264 and HEVC encoding are read from the encoder when it exists (the values in force), otherwise the values that were set are returned. BITRATE_MODE is -1 when the driver has no rate control choice (its default rate control applies).
executeCommand method
The executeCommand(…) method is designed to execute video codec commands. Method declaration:
bool executeCommand(VCodecCommand id);
| Parameter | Description |
|---|---|
| id | Video codec command ID according to the VCodecCommand enum. |
Returns: TRUE if the command was executed successfully or FALSE if not. A command is executed by the encoder and the decoder that exist: before the first frame (no encoder and no decoder exists yet) the method returns FALSE.
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 commands description. Some commands may be unsupported by particular video codec classes.
| Command | Description |
|---|---|
| RESET | Reset codec. The encoder releases its VA objects: the next frame starts a new stream with a key frame. The decoder drops the frames it holds and its decoding state; decoding restarts at the next key frame. The H264 and HEVC decoders keep the parameter sets they received, the JPEG decoder drops the quantization tables kept from earlier images. |
| MAKE_KEY_FRAME | Generate key frame for H264 and HEVC codecs: the next encoded frame is a key frame (IDR picture). Encoder only: the JPEG encoder and the decoder refuse the command. |
Portability
The library works on Linux only: it uses VA-API with the DRM devices of the GPU (/dev/dri). It is built with GCC and Clang (C++17) for x86-64 and aarch64 (little-endian processors). The only SIMD code is in the copy of the decoded pictures to the result frame:
- On x86-64 the expansion of limited range pictures to full range and the splitting and swapping of the chroma samples for NV21, YU12 and YV12 output use SSE2 intrinsics. SSE2 is part of the x86-64 architecture, therefore the build needs no special compiler flags, and there is no run-time dispatch. The library does not use any other instruction set.
- On any other architecture (and when SSE2 is not defined by the compiler) the same code is compiled as portable scalar code with the same results.
No compiler flag for an instruction set is set globally or per file.
Build and connect to your project
Before compiling, you must install or compile LibVA packages for your system.
The install command of the necessary libraries for Ubuntu Linux:
sudo apt install libva2 libva-drm2 libva-dev
sudo apt install intel-media-va-driver-non-free
If you use WSL (Windows Subsystem for Linux), you must activate the vgem Linux module before encoding or decoding:
sudo modprobe vgem
In WSL the hardware is reached through the Mesa D3D12 VA-API driver, which needs the following environment variables. Checked with Mesa 25.2.8 on Intel Iris Xe graphics: H264 encoding and H264 and HEVC decoding work; HEVC encoding does not (the driver never completes the first frame) and JPEG is not available. Checked with Mesa 25.2.8 on Intel UHD Graphics: H264 encoding and H264 and HEVC decoding work; HEVC encoding gives IDR pictures only (the driver does not encode P pictures, transcode(…) returns FALSE for them; with GOP 1 every frame is an IDR picture) and needs frames of at least 80 x 80 pixels; JPEG is not available. A bitrate change between two key frames damages the H264 pictures up to the next key frame: request a key frame (MAKE_KEY_FRAME) together with the change. Two objects that encode or decode at the same time in different threads of one process crash the driver (separate processes work). The driver is unloaded when the last object that has opened the device is destroyed, and a thread that used it and ends after that crashes: keep one object that has encoded or decoded a frame until such threads have ended. Use native Linux with the Intel iHD driver for production:
export LIBVA_DRIVER_NAME=d3d12
export GALLIUM_DRIVER=d3d12
export LD_LIBRARY_PATH=/usr/lib/wsl/lib
Build stand alone
The repository does not contain sub-repositories. The libraries VCodecLibva depends on (Frame, VCodec, Logger) must be cloned into the same folder as VCodecLibva. The folder structure must be:
<work folder>
VCodecLibva
Frame
VCodec
Logger
Typical commands to build the library, the test applications and the example (use the URLs of the repositories provided to you):
git clone <VCodecLibva repository URL>
git clone <Frame repository URL>
git clone <VCodec repository URL>
git clone <Logger repository URL>
cd VCodecLibva
mkdir build
cd build
cmake ..
make
If VCodecLibva is the top-level CMake project, the main CMakeLists.txt file adds the folders ../Frame, ../VCodec and ../Logger (in this order) before the library itself. If a folder does not exist CMake stops with an error. To build the library without the test applications and the example (see CMake options), use the following command instead of cmake ..:
cmake .. -D_SUBMODULE_CACHE_OVERWRITE=OFF -D_VCODEC_LIBVA_TEST=OFF -D_VCODEC_LIBVA_EXAMPLE=OFF
CMake options
Table 4 - CMake options of the repository. In the options below ${PARENT} is the prefix defined by the top-level project (empty if VCodecLibva is the top-level project).
| Option | Default | Description |
|---|---|---|
| ${PARENT}_VCODEC_LIBVA | ON | Build the library. |
| ${PARENT}_VCODEC_LIBVA_TEST | ON (stand alone), OFF (included in other project) | Build the test applications (VCodecLibvaTest, VCodecLibvaRateQualityTest and VCodecLibvaLowDelayTest). |
| ${PARENT}_VCODEC_LIBVA_EXAMPLE | ON (stand alone), OFF (included in other project) | Build the example. |
| ${PARENT}_SUBMODULE_CACHE_OVERWRITE | ON | Forced rewriting of the options above in the CMake cache. The top-level project sets it to OFF when it includes VCodecLibva as a sub-repository. A stand alone build changes the options above only with this option OFF. |
| CMAKE_BUILD_TYPE | Release (if not specified) | Build type. |
Connect to your project
If you want to connect the VCodecLibva 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
CMakeLists.txt
yourLib.h
yourLib.cpp
Create a 3rdparty folder in your repository and add the repositories of VCodecLibva and of the libraries it depends on (Frame, VCodec, Logger) into it, for example as sub-repositories (git submodule add <repository URL> 3rdparty/<name>). The new structure of your repository will be:
CMakeLists.txt
src
CMakeLists.txt
yourLib.h
yourLib.cpp
3rdparty
Frame
VCodec
Logger
VCodecLibva
Create a CMakeLists.txt file in the 3rdparty folder. It adds the libraries in the order of their dependencies (Frame before VCodec) and then VCodecLibva. 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)
################################################################################
## CONFIGURATION
## 3rd-party submodules configuration
################################################################################
SET(${PARENT}_SUBMODULE_FRAME ON CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_FRAME)
SET(${PARENT}_FRAME ON CACHE BOOL "" FORCE)
SET(${PARENT}_FRAME_TEST OFF CACHE BOOL "" FORCE)
endif()
SET(${PARENT}_SUBMODULE_VCODEC ON CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_VCODEC)
SET(${PARENT}_VCODEC ON CACHE BOOL "" FORCE)
endif()
SET(${PARENT}_SUBMODULE_LOGGER ON CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_LOGGER)
SET(${PARENT}_LOGGER ON CACHE BOOL "" FORCE)
SET(${PARENT}_LOGGER_EXAMPLE OFF CACHE BOOL "" FORCE)
endif()
SET(${PARENT}_SUBMODULE_VCODEC_LIBVA ON CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_VCODEC_LIBVA)
SET(${PARENT}_VCODEC_LIBVA ON CACHE BOOL "" FORCE)
SET(${PARENT}_VCODEC_LIBVA_TEST OFF CACHE BOOL "" FORCE)
SET(${PARENT}_VCODEC_LIBVA_EXAMPLE OFF CACHE BOOL "" FORCE)
endif()
################################################################################
## INCLUDING SUBDIRECTORIES
## Adding subdirectories according to the 3rd-party configuration
################################################################################
if (${PARENT}_SUBMODULE_FRAME)
add_subdirectory(Frame)
endif()
if (${PARENT}_SUBMODULE_VCODEC)
add_subdirectory(VCodec)
endif()
if (${PARENT}_SUBMODULE_LOGGER)
add_subdirectory(Logger)
endif()
if (${PARENT}_SUBMODULE_VCODEC_LIBVA)
add_subdirectory(VCodecLibva)
endif()
The 3rdparty/CMakeLists.txt file adds the libraries to your project and excludes their test applications and examples (by default, the test applications and example of VCodecLibva are excluded from compilation if VCodecLibva is included as a sub-repository). VCodecLibva does not add its dependencies when it is included in another project: your project must add them (if they are missing, the compiler stops with an error like VCodec.h: No such file or directory). Your repository’s new structure will be:
CMakeLists.txt
src
CMakeLists.txt
yourLib.h
yourLib.cpp
3rdparty
CMakeLists.txt
Frame
VCodec
Logger
VCodecLibva
Next, you need to include the 3rdparty folder in the main CMakeLists.txt file of your repository. Add the following line at the end of your main CMakeLists.txt:
add_subdirectory(3rdparty)
Next, you need to include the VCodecLibva library in your src/CMakeLists.txt file:
target_link_libraries(${PROJECT_NAME} VCodecLibva)
Done!
Simple example
This simple example generates frames in NV12 pixel format, encodes them to H264 and decodes the encoded frames back to NV12. It processes 300 frames and stops earlier when 100 frames in a row can’t be encoded or decoded (for example without a VA-API device). Source code:
#include <cstdint>
#include <iostream>
#include <memory>
#include "VCodecLibva.h"
int main()
{
// Create encoder and set params.
std::unique_ptr<rapidpixel::VCodec> encoder =
std::make_unique<rapidpixel::VCodecLibva>();
if (!encoder->setParam(rapidpixel::VCodecParam::BITRATE_KBPS, 10000.0f) ||
!encoder->setParam(rapidpixel::VCodecParam::FPS, 20.0f) ||
!encoder->setParam(rapidpixel::VCodecParam::GOP, 30.0f) ||
!encoder->setParam(rapidpixel::VCodecParam::H264_PROFILE, 0.0f))
{
std::cout << "Can't set encoder params" << std::endl;
return 1;
}
// Create decoder. Decoding needs no params.
std::unique_ptr<rapidpixel::VCodec> decoder =
std::make_unique<rapidpixel::VCodecLibva>();
// Image size.
const int width = 640;
const int height = 480;
// Source frame.
rapidpixel::Frame srcFrame(width, height, rapidpixel::Fourcc::NV12);
// Encoded frame H264.
rapidpixel::Frame encodedFrame(width, height, rapidpixel::Fourcc::H264);
// Decoded frame NV12.
rapidpixel::Frame decodedFrame(width, height, rapidpixel::Fourcc::NV12);
// Number of frames to encode and decode.
constexpr int FRAMES_NUMBER{300};
// The example stops when this number of frames in a row can't be encoded
// or decoded (for example without a VA-API device).
constexpr int MAX_FAILURES{100};
// Main loop.
int failures = 0;
uint8_t valueOffset = 0;
for (int n = 0; n < FRAMES_NUMBER && failures < MAX_FAILURES; ++n)
{
// Fill NV12 source frame with test data that changes every frame.
for (int i = 0; i < srcFrame.size; ++i)
{
srcFrame.data[i] = static_cast<uint8_t>(i + valueOffset);
}
++valueOffset;
srcFrame.frameId = n;
// Encode data.
if (!encoder->transcode(srcFrame, encodedFrame))
{
std::cout << "Can't encode frame" << std::endl;
++failures;
continue;
}
// Decode data.
if (!decoder->transcode(encodedFrame, decodedFrame))
{
std::cout << "Can't decode frame" << std::endl;
++failures;
continue;
}
failures = 0;
// Show info.
std::cout << "[" << decodedFrame.frameId << "] Size " <<
encodedFrame.size << " Compression ratio : " <<
static_cast<int>(100.0f * (static_cast<float>(encodedFrame.size) /
static_cast<float>(srcFrame.size))) <<
" % Decoded " << decodedFrame.width << "x" << decodedFrame.height <<
std::endl;
}
if (failures >= MAX_FAILURES)
{
std::cout << "Too many failures, stop" << std::endl;
return 1;
}
return 0;
}
Test application
The test application (VCodecLibva/test/main.cpp, executable VCodecLibvaTest) checks the VCodecLibva library: version, default parameters, parameter ranges, commands, encoding and decoding of every codec and input format with the comparison of the decoded pictures, key frames, invalid encoder and decoder input, damaged data, output formats, picture sizes, encoding and decoding with one object, parameter changes, reset, result frame memory, threads and speed. The tests that encode and decode need a VA-API device; without a device they are reported as skipped. The application prints one block per test and returns 0 when all tests passed and 1 if a test failed, so it can be used in scripts. It writes no files.
To run the application, perform the following commands on Linux:
cd <application folder>
sudo chmod +x VCodecLibvaTest
./VCodecLibvaTest
Output of the application (shortened):
VCodecLibva v1.2.2 test
Version:
Version 1.2.2
OK
Default parameters:
OK
Parameter ranges:
OK
...
Speed:
Encoding / decoding time per frame, msec:
Codec 1920x1080 1280x720 640x512
H264 7.3 / 3.1 3.8 / 1.9 1.9 / 1.1
HEVC 7.5 / 3.0 4.0 / 1.8 2.1 / 1.0
JPEG 8.5 / 3.9 4.2 / 2.1 2.0 / 1.2
OK
All tests passed
The speed test measures the average encoding and decoding time per frame of every codec at 1920x1080, 1280x720 and 640x512 (the table in the Overview section; the first frame of every stream creates the encoder and the decoder and is not counted).
The tests VCodecLibvaRateQualityTest (test/rate_quality) and VCodecLibvaLowDelayTest (test/lowdelay) check the rate control and the quality of the encoders and that the encoders return every frame from the call that passed it, without B-frames. They print one line per check, report the checks that need a VA-API device as skipped when there is none and return 0 when no check failed (1 otherwise).