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>

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)) {
    V4L2DecoderParams 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, V4L2DecoderParams, etc.)

Throws:

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

Returns:

Decoder* Newly created decoder (caller owns)

std::string getDecoderName(AVCodecID codec_id, HWAccel hw_accel)

Get FFmpeg decoder name for codec + acceleration combination.

Maps (codec_id, hw_accel) to FFmpeg decoder name. For software decoding, returns empty string (use avcodec_find_decoder). For hardware decoding, returns the hardware decoder name if available.

Examples:

  • (H264, SW) -> “” (use default decoder)

  • (H264, VAAPI) -> “h264” (VAAPI uses hwaccel, not separate decoder)

Note: VAAPI decoding works differently than encoding - it uses the standard decoder with hw_device_ctx set, not a separate decoder.

Parameters:
  • codec_id – Target codec

  • hw_accel – Hardware acceleration type

Returns:

std::string FFmpeg decoder name, or empty for default

uint32_t avCodecIdToV4L2Fourcc(AVCodecID codec_id)

Convert AVCodecID to V4L2 fourcc.

Maps FFmpeg codec IDs to V4L2 pixel format codes. Returns 0 for unsupported codecs.

Parameters:

codec_id – FFmpeg codec ID

Returns:

uint32_t V4L2 fourcc code, or 0 if unsupported

AVCodecID v4l2FourccToAvCodecId(uint32_t fourcc)

Convert V4L2 fourcc to AVCodecID.

Maps V4L2 pixel format codes to FFmpeg codec IDs. Returns AV_CODEC_ID_NONE for unsupported formats.

Parameters:

fourcc – V4L2 fourcc code

Returns:

AVCodecID FFmpeg codec ID, or AV_CODEC_ID_NONE if unsupported

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.

Implementations:

  • FFmpegDecoder: FFmpeg-based software/hardware decoding

  • V4L2Decoder: 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();
    // 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

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;

// 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 with multithreading
FFmpegDecoderParams params;
params.hw_accel = HWAccel::SW;
params.thread_count = 4;

// VAAPI hardware decoding
FFmpegDecoderParams params;
params.hw_accel = HWAccel::VAAPI;
// hw_device uses sensible default, or specify:
// params.hw_device = "/dev/dri/renderD128";

Public Members

HWAccel hw_accel = {HWAccel::SW}

Hardware acceleration backend.

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.