Decoders

Decoders convert encoded Limef::frame::PacketFrames into decoded Limef::frame::DecodedFrames. The abstract interface is Limef::decode::Decoder; the main implementation is Limef::decode::FFmpegDecoder.

namespace decode

Decoding utilities.

Typedefs

using VideoDecoderParams = std::variant<FFmpegDecoderParams, V4L2DecoderParams, V4L2NVDecoderParams>

Variant type for decoder parameters.

All backend param types are always present - no compile-time ifdefs. Use isDecoderAvailable() to check runtime availability before creating.

Example:

// FFmpeg backend (always available)
FFmpegDecoderParams ffmpeg_params;
ffmpeg_params.thread_count = 4;
VideoDecoderParams params = ffmpeg_params;

// V4L2 backend (check availability first)
if (isDecoderAvailable(DecoderBackend::V4L2)) {
    V4L2NVDecoderParams v4l2_params;
    v4l2_params.device = "/dev/video0";
    VideoDecoderParams params = v4l2_params;
}

Enums

enum class DecoderBackend

Available decoder backends.

Runtime-queryable enum for decoder implementations. Use getAvailableDecoders() to check what’s available.

Values:

enumerator FFmpeg

FFmpeg-based software/hardware decoding.

enumerator V4L2

V4L2 Memory-to-Memory API (Jetson, embedded Linux)

enum class DecoderStatus

Status codes returned by decoder.

Values:

enumerator NeedsMoreData

Ready to accept more packets via push()

enumerator NeedsRead

Decoded frame available, call getFrame()

enumerator EndOfStream

End of stream.

enumerator Error

Something went wrong.

Functions

std::vector<DecoderBackend> getAvailableDecoders()

Get list of available decoder backends.

Returns backends that are both compiled in AND have runtime support. FFmpeg is always available; V4L2 requires device files to exist.

bool isDecoderAvailable(DecoderBackend backend)

Check if a specific decoder backend is available.

DecoderBackend getBackend(const VideoDecoderParams &params)

Get the backend type from decoder params.

Decoder *createDecoder(const std::string &name, const AVStream *stream, const VideoDecoderParams &params)

Create a decoder from variant parameters.

Factory function that creates the appropriate decoder based on the active type in the params variant.

Note: Decoders require stream information at creation time (unlike encoders which can be configured lazily). The stream comes from CodecFrame.

Parameters:
  • name – Identifier for logging

  • stream – AVStream to decode (from CodecFrame)

  • params – Decoder parameters (variant of FFmpegDecoderParams, V4L2NVDecoderParams, etc.)

Throws:

std::runtime_error – if backend not compiled in or not available

Returns:

Decoder* Newly created decoder (caller owns)

class Decoder
#include <decoder.h>

Abstract decoder interface for a single video or audio stream.

State machine that decodes packets into frames. Call status() to determine what operation to do next. Decoder may attach resources to the DecodedFrame which lifetime it manages As decoder is going to be used with filterchains, i.e. with blocking callbacks and synchronous operations, this contract holds:

  • call to status() releases the resources associated with the previous frame

  • getFrame() reserves resources for the new frame

  • resources must be hold between calls to getFrame() -> status(), after that they can be freed

  • ..the DecodedFrame is typically pushed down the filterchain between getFrame() and status() calls

Implementations:

  • FFmpegDecoder: FFmpeg-based software/hardware decoding

  • V4L2NVDecoder: V4L2 Memory-to-Memory API (Jetson, embedded Linux)

Example usage:

std::unique_ptr<Decoder> dec = std::make_unique<FFmpegDecoder>("my-decoder", stream);
DecoderStatus stat;
dec->setDecodedFrame(decoded_frame);
// the following lines would be put inside a while loop
stat = dec->status();
if (stat == DecoderStatus::NeedsMoreData) {
    dec->push(packet_frame);
}
if (stat == DecoderStatus::NeedsRead) {
    const DecodedFrame& decframe = dec->getFrame();
    // if the decoder has reserved resources (fds, shmem) from the previous
    // frame, those can be released when the client calls getFrame()
    // decframe now has the bitmap (typically YUV420P) or decoded audio
}
if (stat == DecoderStatus::EndOfStream) {
    // just exit
}
if (stat == DecoderStatus::Error) {
    // something went wrong
}

All calls to decoder are non-blocking.

Subclassed by Limef::decode::FFmpegDecoder, Limef::decode::V4L2Decoder, Limef::decode::V4L2NVDecoder

Public Functions

virtual void setLogger(std::shared_ptr<spdlog::logger> logger) = 0

Set logger for this decoder.

virtual void setDecodedFrame(Limef::frame::DecodedFrame &frame) = 0

Set output frame.

Must be called before decoder can be used. Frame will be reused for decoded output.

Parameters:

frame – Frame to use for decoded output

virtual DecoderStatus status() = 0

Get current decoder status.

Call this to determine what operation to do next:

  • NeedsMoreData: Call push() with next packet

  • NeedsRead: Call getFrame() to get decoded frame

  • Error: Handle error condition

Returns:

DecoderStatus Current status

virtual void push(const Limef::frame::PacketFrame *frame) = 0

Push packet for decoding.

Only call when status() returns NeedsMoreData

Parameters:

frame – PacketFrame to decode

Throws:

std::runtime_error – if decoder not properly initialized

virtual const Limef::frame::DecodedFrame &getFrame() = 0

Get decoded frame.

Only call when status() returns NeedsRead

Returns:

const DecodedFrame& Reference to decoded frame

virtual int getStreamIndex() const = 0

Get stream index this decoder handles.

virtual void flush() = 0

Flush the decoder.

Forces decoder to output any buffered frames. Check status() after this to get remaining frames.

class FFmpegDecoder : public Limef::decode::Decoder
#include <ffmpeg_decoder.h>

FFmpeg-based decoder for video and audio streams.

Supports both software decoding and hardware-accelerated decoding via FFmpeg’s hwaccel infrastructure (VAAPI, NVDEC, etc.)

Example usage:

FFmpegDecoderParams params;
params.hw_accel = HWAccel::VAAPI;  // or HWAccel::CUDA

// stream comes from CodecFrame or AVFormatContext
FFmpegDecoder dec("my-decoder", stream, params);

// Set output frame:
dec.setDecodedFrame(decoded_frame);

// Decoding loop:
DecoderStatus stat = dec.status();
if (stat == DecoderStatus::NeedsMoreData) {
    dec.push(&packet_frame);
}
if (stat == DecoderStatus::NeedsRead) {
    const DecodedFrame& frame = dec.getFrame();
    // process frame
}

Public Functions

FFmpegDecoder(const std::string &name, const AVStream *stream, const FFmpegDecoderParams &params = FFmpegDecoderParams{})

Construct decoder for given stream.

Parameters:
  • name – Identifier for logging

  • stream – Stream to decode

  • params – Decoding parameters (hw_accel, threading, etc.)

Throws:

std::runtime_error – if decoder initialization fails

inline virtual void setLogger(std::shared_ptr<spdlog::logger> logger) override

Set logger for this decoder.

virtual void setDecodedFrame(Limef::frame::DecodedFrame &frame) override

Set output frame.

Must be called before decoder can be used. Frame will be reused for decoded output.

Parameters:

frame – Frame to use for decoded output

virtual DecoderStatus status() override

Get current decoder status.

Call this to determine what operation to do next:

  • NeedsMoreData: Call push() with next packet

  • NeedsRead: Call getFrame() to get decoded frame

  • Error: Handle error condition

Returns:

DecoderStatus Current status

virtual void push(const Limef::frame::PacketFrame *frame) override

Push packet for decoding.

Only call when status() returns NeedsMoreData

Parameters:

frame – PacketFrame to decode

Throws:

std::runtime_error – if decoder not properly initialized

inline virtual const Limef::frame::DecodedFrame &getFrame() override

Get decoded frame.

Only call when status() returns NeedsRead

Returns:

const DecodedFrame& Reference to decoded frame

inline virtual int getStreamIndex() const override

Get stream index this decoder handles.

virtual void flush() override

Flush the decoder.

Forces decoder to output any buffered frames. Check status() after this to get remaining frames.

inline bool isUsingHardware() const

Check if using hardware decoder.

struct FFmpegDecoderParams
#include <ffmpeg_decoder.h>

Decoding parameters for FFmpegDecoder.

Contains threading and hardware acceleration settings. The stream itself is passed separately to the constructor since it varies per-stream (comes from CodecFrame at runtime).

Example usage:

// Software decoding (default)
FFmpegDecoderParams params;  // hw_accel = HWAccel::NONE by default

// VAAPI hardware decoding
FFmpegDecoderParams params;
params.hw_accel = HWAccel::VAAPI;
// params.hw_device = "/dev/dri/renderD128";  // optional, auto-detected

Public Members

HWAccel hw_accel = {HWAccel::NONE}

Hardware acceleration backend (None = software)

std::string hw_device

Device path (empty = auto-detect)

int thread_count = {2}

Number of decoding threads.

int thread_type = {FF_THREAD_FRAME}

Threading flavor: FF_THREAD_FRAME or FF_THREAD_SLICE.

class V4L2Decoder : public Limef::decode::Decoder
#include <v4l2_decoder.h>

V4L2 Memory-to-Memory decoder.

Implements the Decoder interface using V4L2 M2M API. Developed against vicodec, deployable to Jetson.

Unlike FFmpegDecoder, this does NOT require AVStream. Codec information comes from V4L2DecoderParams. Initialization is lazy (on first packet) like V4L2Encoder.

V4L2 M2M uses two buffer queues:

  • OUTPUT: Encoded packets go IN (confusing naming from V4L2)

  • CAPTURE: Decoded frames come OUT

Example:

V4L2DecoderParams params;
params.device = "/dev/video3";  // vicodec decoder
params.codec_fourcc = V4L2_PIX_FMT_FWHT;

V4L2Decoder dec("v4l2-dec", params);
dec.setDecodedFrame(decoded_frame);

// Push encoded packet (e.g., from V4L2Encoder)
dec.push(&packet_frame);

// Check for decoded output
if (dec.status() == DecoderStatus::NeedsRead) {
    const DecodedFrame& frame = dec.getFrame();
}

Public Functions

V4L2Decoder(const std::string &name, const V4L2DecoderParams &params)

Construct V4L2 decoder.

NOTE: Unlike FFmpegDecoder, does NOT take AVStream. Initialization is lazy - device is opened on first push().

Parameters:
  • name – Identifier for logging

  • params – V4L2-specific decoder parameters (codec_fourcc, device, etc.)

inline virtual void setLogger(std::shared_ptr<spdlog::logger> logger) override

Set logger for this decoder.

virtual void setDecodedFrame(Limef::frame::DecodedFrame &frame) override

Set output frame.

Must be called before decoder can be used. Frame will be reused for decoded output.

Parameters:

frame – Frame to use for decoded output

virtual DecoderStatus status() override

Get current decoder status.

Call this to determine what operation to do next:

  • NeedsMoreData: Call push() with next packet

  • NeedsRead: Call getFrame() to get decoded frame

  • Error: Handle error condition

Returns:

DecoderStatus Current status

virtual void push(const Limef::frame::PacketFrame *frame) override

Push packet for decoding.

Only call when status() returns NeedsMoreData

Parameters:

frame – PacketFrame to decode

Throws:

std::runtime_error – if decoder not properly initialized

inline virtual const Limef::frame::DecodedFrame &getFrame() override

Get decoded frame.

Only call when status() returns NeedsRead

Returns:

const DecodedFrame& Reference to decoded frame

inline virtual int getStreamIndex() const override

Get stream index this decoder handles.

virtual void flush() override

Flush the decoder.

Forces decoder to output any buffered frames. Check status() after this to get remaining frames.

struct V4L2DecoderBuffer
#include <v4l2_decoder.h>

Buffer info for mmap’d V4L2 buffers.

Public Members

void *start = {nullptr}

mmap’d address

size_t length = {0}

Buffer size.

int index = {-1}

Buffer index.

bool queued = {false}

Currently queued to driver.

struct V4L2DecoderParams
#include <v4l2_decoder.h>

Decoding parameters for V4L2Decoder.

V4L2-specific parameters using fourcc codes. Unlike FFmpegDecoder, this does NOT use AVStream/AVCodecID.

If codec_fourcc is left at default (FWHT) and the decoder is created via the factory with an AVStream, the codec will be auto-detected.

Public Members

std::string device = {"/dev/video0"}

V4L2 device path (vicodec decoder: /dev/video3)

uint32_t codec_fourcc = {V4L2_PIX_FMT_FWHT}

Input codec fourcc (e.g., V4L2_PIX_FMT_FWHT, V4L2_PIX_FMT_H264)

uint32_t output_fourcc = {V4L2_PIX_FMT_NV12}

Preferred output pixel format (decoder may override based on hardware)

int width = {0}

Expected dimensions (0 = detect from bitstream, for stateful decoders)

int num_output_buffers = {4}

Number of OUTPUT (encoded) buffers.

int num_capture_buffers = {4}

Number of CAPTURE (decoded frame) buffers.

class V4L2NVDecoder : public Limef::decode::Decoder
#include <v4l2_nv_decoder.h>

V4L2 Memory-to-Memory decoder.

Implements the Decoder interface using V4L2 M2M API. Hardware NVDEC decoder for Jetson Orin (tegra234) via V4L2 M2M API.

Codec identity and initial dimensions come from the AVStream passed at construction (matches FFmpegDecoder’s signature). Initialization is lazy (on first packet) like V4L2Encoder.

V4L2 M2M uses two buffer queues:

  • OUTPUT: Encoded packets go IN (confusing naming from V4L2)

  • CAPTURE: Decoded frames come OUT

Public Functions

V4L2NVDecoder(const std::string &name, const AVStream *stream, const V4L2NVDecoderParams &params)

Construct V4L2 decoder.

Initialization is lazy - device is opened on first push().

Parameters:
  • name – Identifier for logging

  • stream – AVStream the bitstream belongs to. codec_id is mapped to a V4L2 fourcc; width/height seed the stateless-decoder path (stateful decoders override via SOURCE_CHANGE).

  • params – Backend parameters (device path, buffer counts, target).

inline virtual void setLogger(std::shared_ptr<spdlog::logger> logger) override

Set logger for this decoder.

virtual void setDecodedFrame(Limef::frame::DecodedFrame &frame) override

Set output frame.

Must be called before decoder can be used. Frame will be reused for decoded output.

Parameters:

frame – Frame to use for decoded output

virtual DecoderStatus status() override

Get current decoder status.

Call this to determine what operation to do next:

  • NeedsMoreData: Call push() with next packet

  • NeedsRead: Call getFrame() to get decoded frame

  • Error: Handle error condition

Returns:

DecoderStatus Current status

virtual void push(const Limef::frame::PacketFrame *frame) override

Push packet for decoding.

Only call when status() returns NeedsMoreData

Parameters:

frame – PacketFrame to decode

Throws:

std::runtime_error – if decoder not properly initialized

inline virtual const Limef::frame::DecodedFrame &getFrame() override

Get decoded frame.

Only call when status() returns NeedsRead

Returns:

const DecodedFrame& Reference to decoded frame

inline virtual int getStreamIndex() const override

Get stream index this decoder handles.

virtual void flush() override

Flush the decoder.

Forces decoder to output any buffered frames. Check status() after this to get remaining frames.

struct V4L2NVDecoderBuffer
#include <v4l2_nv_decoder.h>

Buffer info for V4L2 CAPTURE buffers.

Public Members

void *start = {nullptr}

Y-plane CPU address (EXPBUF mmap, MPLANE) or mmap’d (single-plane)

size_t length = {0}

Y-plane size in bytes.

void *uv_start = {nullptr}

UV-plane CPU address (MPLANE NM12 only)

size_t uv_length = {0}

UV-plane size in bytes.

int index = {-1}

Buffer index.

bool queued = {false}

Currently queued to driver.

int expfd = {-1}

EXPBUF dma-buf fd — kept open (MPLANE); needed by nv_bl2pl_transform.

struct V4L2NVDecoderParams
#include <v4l2_nv_decoder.h>

Backend parameters for V4L2NVDecoder.

Holds only backend-level configuration. Codec identity, dimensions and pixel format are obtained from the AVStream passed at construction (or, for stateful decoders, negotiated with the driver on V4L2_EVENT_SOURCE_CHANGE).

Public Members

std::string device = {"/dev/video0"}

V4L2 device path (vicodec decoder: /dev/video3)

uint32_t output_fourcc = {V4L2_PIX_FMT_NV12}

Preferred output pixel format (decoder may override based on hardware)

int num_output_buffers = {32}

Number of OUTPUT (encoded) buffers.

int num_capture_buffers = {16}

Number of CAPTURE (decoded frame) buffers.

Limef::frame::BufferLocation target = {Limef::frame::BufferLocation::CPU}

Output frame memory target: CPU (default) or CUDA (Jetson only, requires LIMEF_V4L2_NV).