Threads

Threads are the active components of a pipeline. The base class Limef::thread::Thread is templated on the frame type it handles specially. Each thread exposes Limef::thread::Thread::getInput() and Limef::thread::Thread::getOutput() as connection points.

namespace thread

multithreading

Non-template base class for all thread classes.

Defines the common interface for all thread classes. Used by ComposeThread to manage thread chains without needing to know the specific template types.

Each thread:

  • Has input and output framefilters for connecting to other threads

  • Can be started and stopped

  • Can be bound to specific CPU cores

  • Has configurable logging

Functions

static Uint32 cpuFmtToSDL(AVPixelFormat fmt)
class ComposeThread : public Limef::thread::ThreadBase
#include <compose.h>

Base class for composite threads.

Allows creating complex thread combinations by composing simpler ones. Subclasses create and chain their threads directly in the constructor call to chainThreads().

Example usage:

class StreamThread : public ComposeThread {
public:
    StreamThread(const std::string& name, const StreamContext& ctx) 
        : ComposeThread(name) {
        
        chainThreads({
            new LiveStreamThread("live", ctx),
            new PacketBufferThread("buffer", ctx),
            new DecodingThread("decode", ctx)
        });
    }
};

ComposeThread takes ownership of the created threads and handles:

  • Chaining outputs to inputs

  • Starting/stopping in correct order

  • Memory cleanup

  • Logger propagation

  • CPU affinity assignment

IMPORTANT: when calling start for a ComposeThread, the threads are started in reverse order (in the current example: DecodingThread first, then PacketBufferThread, etc.) This assures that downstream receiving threads are ready & do not miss any frames sent by the upstream threads.

Subclassed by Limef::thread::MediaFileThread

Public Functions

virtual void start() override

Start the thread.

Initializes internal structures and starts the thread’s main loop. Thread subclasses may perform additional initialization.

virtual bool isStarted() const override

Check if start has been called or not.

virtual bool isRunning() const override

Check if the thread backend is currently running (mainLoop is executing)

Returns true between start() and natural/requested stop, false before start() and after the thread has fully exited mainLoop(). Unlike isStarted(), this becomes false once the thread stops — either from stop() or from setting stop_requested_ itself (e.g. on EOF with no looping).

virtual void requestStop() override

Request thread termination.

Sends termination signal to the thread. Does not wait for completion.

virtual void waitStop() override

Wait for thread termination.

Blocks until the thread has completely stopped.

virtual void stop() override

Stop the thread.

Combines requestStop() and waitStop() for convenience.

virtual void setAffinity(int core_id) override

Bind thread to specific CPU core.

Parameters:

core_id – CPU core number to bind to

virtual void setLogLevel(spdlog::level::level_enum level) override

Set thread’s log level.

virtual void setLogFormat(const std::string &format) override

Set thread’s log format.

virtual void shortLogFormat() override

Set a nice minimal format for thread’s logger.

virtual spdlog::level::level_enum getLogLevel() const override

Get thread’s current log level.

virtual Limef::ff::FrameFilter &getInput() override

Get thread’s input framefilter.

Returns:

Reference to input framefilter

virtual Limef::ff::FrameFilter &getOutput() override

Get thread’s output framefilter.

Returns:

Reference to output framefilter

class ConsumerThread : public Limef::thread::Thread<Limef::frame::PacketFrame>
#include <consumer.h>

An example consumer thread.

An example thread that consumes frames Consumes PacketFrames at a certain framerate from the input framefilter. Does not pass anything downstream to output framefilter.

class DecodedThread : public Limef::thread::Thread<Limef::frame::DecodedFrame>
#include <decodedthread.h>

A pass-through thread for DecodedFrame streams.

Receives DecodedFrames, copies them through its internal DecodedFrameFifo (breaking the synchronous filterchain), and forwards them unchanged downstream via output_ff.

Use this as a thread boundary in decoded-video pipelines — for example, to decouple a decoder from a downstream processing chain, or to hand off frames between Python filterchains without blocking the decoder thread.

The DecodedFrameFifo honours the target field of the context:

  • BufferLocation::CPU (default) — CPU→CPU deep copy

  • BufferLocation::CUDA — stack frames pre-allocated via cudaMalloc

Non-DecodedFrame frames (SignalFrame, StreamFrame, etc.) are dispatched by the base class and pass through unchanged.

FrameFifoContext ctx;
DecodedThread dt("decoded-boundary", ctx);
upstream.cc(dt.getInput());
dt.getOutput().cc(downstream);
dt.start();
class EGLPresenterThread : public Limef::thread::PresenterThread
#include <eglpresenterthread.h>

EGL/OpenGL video presenter: renders decoded frames on screen via EGL.

Subclass of PresenterThread that creates an X11 window with an EGL context and renders each decoded video frame using OpenGL. Supports three frame paths without any extra configuration:

  • CPU frames (SW decode, YUV420P / NV12): uploaded via glTexSubImage2D.

  • VAAPI frames (Intel/AMD GPU): exported as DMA-buf, imported as an EGL image — no CPU hop.

  • CUDA frames (NVDEC, NV12 on GPU): zero-copy via cudaGraphicsEGLRegisterImage

    • cudaMemcpy2DToArray when supported; CPU fallback otherwise (compiled only when LIMEF_CUDA is defined).

Public Functions

EGLPresenterThread(std::string name, const Limef::FrameFifoContext &ctx = Limef::FrameFifoContext(true, 20, 40), const PresenterContext &pctx = {})
Parameters:
  • name – Thread name (used for logger and window title)

  • ctx – FrameFifo configuration (default: leaky, 20 frames stack, 40-frame fifo — appropriate for live streaming)

  • pctx – Window / timing options (see PresenterContext)

class ExamplePollThread : public Limef::thread::PollThread<Limef::frame::PacketFrame>
#include <pollthread.h>

Concrete example of PollThread for testing.

Demonstrates PollThread with PacketFrames and a periodic task.

class ExampleSignal : public Limef::signal::Signal
#include <examplethread.h>

An example signal for ExampleThread

An example custom signal class for the ExampleThread thread class

class ExampleThread : public Limef::thread::Thread<Limef::frame::PacketFrame>
#include <examplethread.h>

An example thread.

An example thread with custom signals, task and frame processing. Receives PacketFrames from upstream (input framefilter) and simply passes them downstream (output framefilter). Executes a periodic task (every 2 secs). Demonstrates intercommunication between thread front- and backend.

Public Functions

void pingCall()

Frontend method that calls backend method ExampleThread::pingCall__

void pingCall2(int param)

Frontend method that calls backend method ExampleThread::pingCall2__

class GLXPresenterThread : public Limef::thread::PresenterThread
#include <glxpresenterthread.h>

GLX/OpenGL video presenter: renders decoded frames on screen via GLX.

Subclass of PresenterThread that creates an X11 window with a GLX context and renders each decoded video frame using OpenGL. Supports three frame paths without any extra configuration:

  • CPU frames (SW decode, YUV420P / NV12): uploaded via glTexSubImage2D.

  • VAAPI frames (Intel/AMD GPU): CPU fallback via materializeToCPU(). (DMA-buf zero-copy requires EGL; use EGLPresenterThread for that path.)

  • CUDA frames (NVDEC, NV12 on GPU): zero-copy via cudaGraphicsGLRegisterImage

    • cudaMemcpy2DToArray (compiled only when LIMEF_CUDA is defined). This is the principal advantage of GLX over EGL on X11: NVIDIA’s CUDA GL interop queries glXGetCurrentDisplay() internally and only works with a current GLX context. Requirement: the GLX context and the CUDA device must be on the same physical GPU. On hybrid (PRIME/optimus) systems the default GLX context is on the Intel/Mesa GPU; cudaGraphicsGLRegisterImage will fail and fall back to CPU upload. Force the NVIDIA GPU with: __NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia and set PresenterContext::bypass_compositor = true so KWin does not try to re-composite the NVIDIA-rendered window through its Mesa compositor. Alternatively, use sudo prime-select nvidia to make NVIDIA the system default (see tools/nvidia/check_display.bash).

Public Functions

GLXPresenterThread(std::string name, const Limef::FrameFifoContext &ctx = Limef::FrameFifoContext(true, 20, 40), const PresenterContext &pctx = {})
Parameters:
  • name – Thread name (used for logger and window title)

  • ctx – FrameFifo configuration (default: leaky, 20 frames stack, 40-frame fifo — appropriate for live streaming)

  • pctx – Window / timing options (see PresenterContext)

struct LiveStreamContext
#include <livestreamcontext.h>

Configuration context for live stream reader.

Public Members

const std::string url = {""}

Stream URL (e.g., “rtsp://camera.example.com/stream”)

const Slot slot = {1}

Slot identifying this stream.

int timeout_sec = {15}

Read timeout in seconds (av_read_frame streaming phase) - if no packets in this many secs during streaming, then reconnect.

int timeout_connect_sec = {20}

Connection timeout in seconds (avformat_open_input setup phase) - if RTSP DESCRIBE/SETUP/PLAY handshake is not completed within this many seconds, reconnect.

std::string rtsp_transport = {"tcp"}

RTSP transport (tcp/udp) for RTSP sources.

int max_delay_ms = {500}

Maximum allowed network delay for RTSP sources.

int reopen_retry_max = {-1}

Maximum number of reopen attempts: -1: infinite, 0: none, etc.

int timeout_start_sec = {5}

Start value for retry timeout - try to re-establish connection after this many seconds.

int timeout_max_sec = {60}

Max value for retry timeout - try to re-establish connection after this many seconds.

int factor = {2}

Factor to increase retry timeouts.

int probe_duration_sec = {15}

How long avformat_find_stream_info is allowed to probe for codec parameters, in seconds. On a lightly loaded system packets arrive quickly and the probe completes in well under a second. On a heavily loaded system (many parallel streams, valgrind, slow hardware) the server may be slow to deliver the first keyframe and the default FFmpeg probe window (~5 s) expires before width/height can be determined, causing a spurious retry loop. Increase this for production deployments with many concurrent streams or slow cameras.

The wall-clock interrupt deadline is set to 1.2× this value, giving FFmpeg time to hit its own internal limit before the hard abort fires.

Default: 15 s (3× the FFmpeg internal default).

bool use_ntp = {false}

Use NTP wallclock from RTCP Sender Reports as the absolute timestamp.

When true, absolute timestamps are taken from the camera’s NTP clock (delivered via RTCP Sender Reports). This enables wall-clock-aligned multi-stream synchronisation, but relies on the camera having a correctly configured NTP clock. A camera with a wrong clock (wrong year, large drift) will produce garbage absolute timestamps that break presentation scheduling — symptoms include a frozen first frame, pipeline stalls, or frames that never appear.

Before the first RTCP SR arrives (typically 1–5 s after stream open), the t0+PTS_delta fallback is used regardless of this setting, so early packets are always timestamped consistently.

Default: false (t0+PTS_delta, safe for all cameras). Set to true only when you know the camera’s NTP is reliable.

int ntp_timeout_sec = {10}

Warn if no NTP timestamp received within this many seconds after stream open.

int reconnect_interval_sec = {0}

Mandatory reconnection interval in seconds. When non-zero, the stream is forcibly dropped and re-opened after this many seconds of continuous streaming. Useful for cameras (notably some Chinese IP cameras) whose streams start lagging or corrupting after long sessions. The reconnect follows the normal backoff path (onLost emitted, then onConnected once the new session is established). Default: 0 = never force-reconnect.

class LiveStreamThread : public Limef::thread::Thread<Limef::frame::NullFrame>
#include <livestream.h>

Thread for reading live media streams using FFmpeg.

Handles live media sources like RTSP cameras using FFmpeg’s interrupt callback system for proper timeout handling. Sends CodecFrame on startup followed by PacketFrames containing media data.

Example protocols:

  • RTSP (rtsp://)

  • HTTP Live Streaming (http://)

  • UDP/RTP streams (udp://)

Public Functions

LiveStreamThread(std::string name, const LiveStreamContext &stream_ctx)

Construct a new Live Stream Reader Thread.

Parameters:
  • name – Thread name for identification

  • stream_ctx – LiveStreamContext defining the live stream

Throws:

std::runtime_error – if stream cannot be opened or initialized

Public Members

Limef::comm::Caller<int> onConnected

Emitted when stream opens successfully (first time or reconnect). Arg: slot number.

Limef::comm::Caller<int> onLost

Emitted when stream is lost (error, timeout, or EOF). Arg: slot number.

struct MediaFileContext
#include <mediafile0.h>

Public Members

const std::string filename = {""}

Path to media file.

const Slot slot = {1}

Slot identifying this stream.

int fps = {0}

Target fps for feeding frames. 0 = feed frames at infinite speed. -1 = feed frames at play speed.

int loop = {-1}

Loop the file from start at EOF. -1 = no looping, otherwise, the pause in milliseconds before looping.

class MediaFileSignal : public Limef::signal::Signal
#include <mediafile0.h>

Specific signals to MediaFileThread0.

class MediaFileThread : public Limef::thread::ComposeThread
#include <mediafile.h>

Media playback thread with DTS-ordered buffering.

Creates a chain of:

  1. MediaFileThread0 for reading files and sending packets as-is

  2. OrderedPacketBufferThread for DTS ordering and buffering

NOTE: thread starting order will be (2) -> (1)

                thread border
MediaFileThread0 ->| OrderedPacketBufferThread

class MediaFileThread0 : public Limef::thread::ProducerThread
#include <mediafile0.h>

Thread for reading media files using FFmpeg.

Reads packets from a media file and sends them downstream:

  1. On startup, sends CodecFrame with stream information

  2. Continuously sends PacketFrames with media data

Uses ProducerThread’s timing system to control packet output rate

Dumps media downstream as-is - no internal conversions

Public Functions

MediaFileThread0(std::string name, const MediaFileContext &ctx)

Construct a new Media File Reader Thread.

Parameters:
  • name – Thread name for identification

  • ctx – MediaFileContext identifying the stream

Throws:

std::runtime_error – if file cannot be opened or stream info cannot be read

virtual void handleSignalFrame(const Limef::frame::SignalFrame *signalFrame) override

Handles custom signals as per MediaFileSignal

void resendCodecFrame()

frontend-method: tell thread to send CodecFrame again downstream

class OrderedPacketBufferThread : public Limef::thread::PacketBufferThread
#include <orderedpacketbuffer.h>

Thread for buffering PacketFrames with DTS ordering.

Extends PacketBufferThread to use OrderedFrameFifo, which maintains video packets in DTS order. Otherwise methods identical to PacketBufferThread.

class PacketBufferThread : public Limef::thread::Thread<Limef::frame::PacketFrame>
#include <packetbuffer.h>

Thread for buffering PacketFrames.

This thread immediately terminates the filter chain for PacketFrames by:

  1. Making a copy of incoming PacketFrames using framefifo’s stack

  2. Placing the copy into framefifo’s queue

  3. Processing frames from the queue in its own thread context

Subclassed by Limef::thread::OrderedPacketBufferThread

Public Functions

PacketBufferThread(std::string name, const Limef::FrameFifoContext &ctx)

Construct a new Packet Buffer Thread.

Parameters:
  • name – Thread name for identification

  • ctx – FrameFifoContext defining the framefifo parameters

struct PerSocketData
#include <websocket.h>
template<typename T>
class PollThread : public Limef::thread::Thread<T>
#include <pollthread.h>

Example thread demonstrating PollFrameFifo usage.

This thread uses PollFrameFifo instead of the regular FrameFifo, allowing the main loop to multiplex frame reading with other I/O operations (sockets, pipes, etc.) using poll().

Key differences from regular Thread:

  • Overrides createFrameFifo() to create PollFrameFifo

  • Overrides mainLoop() to use poll() instead of blocking read()

  • Provides getFifoFd() for subclasses to include in their poll set

Usage pattern for subclasses (e.g., RTSPServerThread):

void MyServerThread::mainLoop() {
    preRun();
    sendSignal__(BasicSignal(BasicSignal::Operation::started));

    std::vector<pollfd> fds;
    fds.push_back({listen_fd_, POLLIN, 0});
    fds.push_back({getFifoFd(), POLLIN, 0});

    while (!stop_requested_) {
        int timeout_ms = computeTaskTimeout();
        poll(fds.data(), fds.size(), timeout_ms);

        // Handle incoming frames
        if (fds[1].revents & POLLIN) {
            while (auto* frame = pollFrameFifo()->tryRead()) {
                frameTask(frame);
            }
        }

        // Handle socket I/O
        if (fds[0].revents & POLLIN) {
            acceptClient();
        }

        task();
    }
    postRun();
}

struct PresenterContext
#include <presenterthread.h>

Configuration for X11 presenter threads (EGLPresenterThread, GLXPresenterThread).

Collects all window and timing parameters in one place so the thread constructors stay concise as new options are added.

Example:

PresenterContext pctx;
pctx.width              = 1920;
pctx.height             = 1080;
pctx.bypass_compositor  = true;   // needed on PRIME/KWin for GLX
GLXPresenterThread glx("glx", FrameFifoContext(false, 20, 40), pctx);

Public Members

int width = 1280

Initial window width in pixels.

int height = 720

Initial window height in pixels.

bool borderless = false

Create window without WM decorations.

bool bypass_compositor = false

Set _NET_WM_BYPASS_COMPOSITOR (needed on KWin + PRIME/GLX)

std::chrono::microseconds max_age = {0}

Drop frames older than this (0 = disabled)

std::chrono::microseconds max_future_age = {0}

Drop frames newer than now+this (0 = disabled). Set this for live streaming to guard against cameras that send wrong NTP timestamps: a frame with ABS_TS far in the future would otherwise fill pending_frames_ indefinitely and block the entire upstream pipeline. A value of 5–10 s is a safe default for IP cameras.

class PresenterThread : public Limef::thread::Thread<Limef::frame::DecodedFrame>
#include <presenterthread.h>

Base class for threads that present media at the correct wall-clock time.

PresenterThread receives DecodedFrames from upstream and holds them in an internal queue. Instead of processing each frame immediately on arrival, it inspects Frame::absolute_timestamp_ and presents frames only when their timestamp is “due” (i.e. wall-clock time >= frame timestamp).

Subclassed by Limef::thread::EGLPresenterThread, Limef::thread::GLXPresenterThread, Limef::thread::SDLVideoPresenterThread

Public Functions

PresenterThread(std::string name, const Limef::FrameFifoContext &ctx, std::chrono::microseconds max_age = std::chrono::microseconds(0), std::chrono::microseconds max_future_age = std::chrono::microseconds(0))
Parameters:
  • name – Thread name.

  • ctx – FrameFifo configuration. For live streaming, set ctx.leaky = true so that writeCopy() drops frames instead of blocking when the stack is full.

  • max_age – Drop frames whose timestamp is older than this. Zero (default) disables: all due frames are presented regardless of how late they are.

  • max_future_age – Drop frames whose timestamp is more than this far ahead of now. Zero (default) disables. Set to 5–10 s for live streaming to guard against cameras that send wrong NTP wallclock in their RTCP SR.

class ProducerThread : public Limef::thread::Thread<Limef::frame::NullFrame>
#include <producer.h>

A prototype frame producing thread (aka source)

An example and base class for Threads that produce frames, i.e. for frame sources. This example implementation produces and sends NullFrames to it’s output framefilter.

Subclassed by Limef::thread::MediaFileThread0, Limef::thread::USBCameraThread

class SDLVideoPresenterThread : public Limef::thread::PresenterThread
#include <sdlvideopresenterthread.h>

SDL2-based video presenter: renders decoded video frames to a window.

Subclass of PresenterThread that opens an SDL2 window and blits each decoded video frame via SDL2’s texture update API. Supports both CPU-resident and GPU-resident frames:

  • CPU frames (SW decode): YUV420P / YUVJ420P — uses SDL_PIXELFORMAT_IYUV and SDL_UpdateYUVTexture.

  • GPU frames (VAAPI / CUDA): calls DecodedFrame::materializeToCPU() (i.e. av_hwframe_transfer_data) which downloads to NV12 in system memory, then uses SDL_PIXELFORMAT_NV12 and SDL_UpdateNVTexture.

The SDL texture is created lazily on the first frame so the pixel format is always correct without needing to be specified at construction time. If the format or resolution changes mid-stream the texture is recreated.

All SDL calls happen on the PresenterThread backend so no cross-thread synchronisation is needed. Window close (SDL_QUIT) sets stop_requested_; resize (SDL_WINDOWEVENT_RESIZED) recreates the texture.

Example usage:

SDLVideoPresenterThread presenter("sdl", FrameFifoContext(false, 20, 40),
                                  1280, 720);
mediafile.getOutput().cc(decoding_ff).cc(presenter.getInput());
presenter.start();
// ... wait ...
presenter.stop();

Public Functions

SDLVideoPresenterThread(std::string name, const Limef::FrameFifoContext &ctx = Limef::FrameFifoContext(true, 20, 40), int width = 1280, int height = 720, bool borderless = false, std::chrono::microseconds max_age = std::chrono::microseconds(0), std::chrono::microseconds max_future_age = std::chrono::microseconds(0))
Parameters:
  • name – Thread name (used for logger)

  • ctx – FrameFifo configuration (default: leaky, 20 frames stack, 40-frame fifo — appropriate for live streaming)

  • width – Initial window / texture width in pixels

  • height – Initial window / texture height in pixels

  • borderless – If true the window is created without decorations

  • max_age – Drop frames older than this (0 = disabled, default)

  • max_future_age – Drop frames newer than now+this (0 = disabled). Set to 5–10 s for live streaming.

class TensorThread : public Limef::thread::Thread<Limef::frame::TensorFrame>
#include <tensorthread.h>

A pass-through thread for TensorFrame streams.

Receives TensorFrames, copies them through its internal TensorFrameFifo (breaking the synchronous filterchain), and forwards them unchanged downstream via output_ff.

This is the building block for the CPUBlock and GPUBlock pipeline nodes. It establishes the thread boundary — i.e. the point at which frames are copied into a pre-allocated pool and ownership transfers to this thread — without performing any computation. Subclass and override processFrame() to add per-frame work.

The TensorFrameFifo honours the gpu_target field of the context:

  • HWAccel::SW (default) — keep frames on CPU

  • HWAccel::CUDA — upload incoming CPU frames to GPU in one H2D copy

Non-TensorFrame frames (SignalFrame, StreamFrame, etc.) are dispatched by the base class and pass through unchanged.

FrameFifoContext ctx;
TensorThread tr("worker", ctx);
upstream.cc(tr.getInput());
tr.getOutput().cc(downstream);
tr.start();
template<typename T>
class Thread : public Limef::thread::ThreadBase
#include <thread.h>

A multithreading base class.

Thread class includes:

  • thread “frontend” methods: you are supposed to call these from the main thread.

  • thread “backend” methods: these are used internally by the thread after it has been spawned.

  • a single, unified fifo for handling incoming Frames and commands, the FrameFifo.

Subclassed by Limef::thread::PollThread< Limef::frame::RTPFrame >, Limef::thread::PollThread< Limef::frame::PacketFrame >, Limef::thread::PollThread< T >

Public Functions

Thread(std::string name, const Limef::FrameFifoContext &ctx)

Default ctor

Parameters:
  • name – a unique name identifying this thread

  • ctx – a FrameFifoContext defining the framefifo

virtual void start() override

sets up thread and starts mainLoop

inline virtual bool isStarted() const override

Check if start has been called or not.

inline virtual bool isRunning() const override

has the thread been started or not?

inline uint64_t getTaskCallCount() const

true while mainLoop() is executing

virtual void requestStop() override

request thread termination

virtual void waitStop() override

wait for thread termination

virtual void stop() override

combined requestStop() and waitStop()

virtual void setAffinity(int core_id) override

Binds the thread to a certain CPU.

std::unique_ptr<Limef::signal::Signal> read(std::chrono::microseconds timeout = 0us)

read a signal at the frontend. 0 means wait forever -> uses fifo_mutex_ & fifo_condition_

Read a signal at the thread frontend (main python thread) sent by the thread backend through an internal fifo. Example:

auto signal2 = read();
if (auto* basicSignal = signal2->as<SomeSignalClass>()) {
}

inline virtual Limef::ff::FrameFilter &getInput() override

returns thread’s input FrameFilter

inline virtual Limef::ff::FrameFilter &getOutput() override

returns thread’s output FrameFilter

virtual void setLogLevel(spdlog::level::level_enum level) override

Sets thread logger’s loglevel.

virtual void setLogFormat(const std::string &format) override

Sets thread logger’s format.

virtual void shortLogFormat() override

Shortcut method for setting a nice minimal format for thread’s logger.

virtual spdlog::level::level_enum getLogLevel() const override

Get thread logger’s current log level.

class ThreadBase
#include <threadbase.h>

Subclassed by Limef::thread::Thread< Limef::frame::RTPFrame >, Limef::thread::Thread< Limef::frame::PacketFrame >, Limef::thread::Thread< Limef::frame::DecodedFrame >, Limef::thread::Thread< Limef::frame::NullFrame >, Limef::thread::Thread< Limef::frame::TensorFrame >, Limef::thread::Thread< Limef::frame::RawFrame >, Limef::thread::ComposeThread, Limef::thread::Thread< T >

Public Functions

virtual void start() = 0

Start the thread.

Initializes internal structures and starts the thread’s main loop. Thread subclasses may perform additional initialization.

virtual bool isStarted() const = 0

Check if start has been called or not.

virtual bool isRunning() const = 0

Check if the thread backend is currently running (mainLoop is executing)

Returns true between start() and natural/requested stop, false before start() and after the thread has fully exited mainLoop(). Unlike isStarted(), this becomes false once the thread stops — either from stop() or from setting stop_requested_ itself (e.g. on EOF with no looping).

virtual void requestStop() = 0

Request thread termination.

Sends termination signal to the thread. Does not wait for completion.

virtual void waitStop() = 0

Wait for thread termination.

Blocks until the thread has completely stopped.

virtual void stop() = 0

Stop the thread.

Combines requestStop() and waitStop() for convenience.

virtual void setAffinity(int core_id) = 0

Bind thread to specific CPU core.

Parameters:

core_id – CPU core number to bind to

virtual void setLogLevel(spdlog::level::level_enum level) = 0

Set thread’s log level.

virtual void setLogFormat(const std::string &format) = 0

Set thread’s log format.

virtual void shortLogFormat() = 0

Set a nice minimal format for thread’s logger.

virtual spdlog::level::level_enum getLogLevel() const = 0

Get thread’s current log level.

virtual Limef::ff::FrameFilter &getInput() = 0

Get thread’s input framefilter.

Returns:

Reference to input framefilter

virtual Limef::ff::FrameFilter &getOutput() = 0

Get thread’s output framefilter.

Returns:

Reference to output framefilter

struct USBCameraContext
#include <usbcamera.h>

Configuration for USB camera capture.

Public Members

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

V4L2 device path.

Slot slot = {1}

Slot identifying this stream.

int width = {640}

Requested capture width.

int height = {480}

Requested capture height.

int fps = {30}

Requested frame rate.

AVPixelFormat capture_format = {AV_PIX_FMT_YUYV422}

Format to request from camera via VIDIOC_S_FMT.

int reinit_timeout_ms = {10000}

milliseconds of no successful readFrame() before an automatic reinit is triggered

int reinit_retry_ms = {5000}

ms between reinit attempts while device is down, before backoff kicks in

int reinit_backoff_after = {5}

consecutive failed reinit attempts before switching to the slower cadence

int reinit_backoff_ms = {30000}

ms between reinit attempts once backed off

int eagain_retry_divisor = {2}

EAGAIN retry interval = frame_interval / this divisor (default: half a frame period)

int eagain_retry_max_ms = {50}

upper bound on the EAGAIN retry interval (frame_interval / divisor), regardless of requested fps

class USBCameraSignal : public Limef::signal::Signal
#include <usbcamera.h>

A signal for USBCameraThread

A custom signal class for the USBCameraThread thread class, used to trigger a device reinit (close+reopen) on demand — mainly useful for testing the automatic stall-detection/reinit path without waiting for real hardware to misbehave.

class USBCameraThread : public Limef::thread::ProducerThread
#include <usbcamera.h>

Thread for capturing frames from USB cameras.

Reads raw frames from a V4L2 device, converts them to the target pixel format using SwScale, and sends them downstream as DecodedFrames.

On startup, sends a StreamFrame with video stream information. Then continuously sends DecodedFrames with pixel data.

Public Functions

USBCameraThread(std::string name, const USBCameraContext &ctx)

Construct USB camera capture thread.

Parameters:
  • name – Thread name for logging/identification

  • ctx – Camera configuration (device, resolution, format)

Throws:

std::runtime_error – if device cannot be opened

void reinit()

Frontend: trigger a device close+reopen. Same effect as an automatic stall-triggered reinit — mainly useful for testing.

class WebSocketBroadcastServer
#include <websocket_broadcast.h>

Public Functions

bool startServer(int port, std::chrono::seconds timeout = std::chrono::seconds(10))

Start listening on port. Blocks (up to timeout) until the server is actually listening or has failed to start.

Returns:

false on failure or timeout. Calling this while already running also fails immediately (returns false, does not restart).

void stopServer()

Stop the server and join its background thread. Blocks until fully stopped. Safe to call even if the server was never started or has already been stopped (no-op in that case). Called automatically from the destructor if still running.

size_t getClientCount() const

Number of currently connected clients.

void broadcastText(std::string message)

Broadcast a text message to every currently connected client. Safe to call from any thread. A no-op if the server isn’t running (before startServer() or after stopServer()).

struct Impl
class WebSocketServerSignal : public Limef::signal::Signal
#include <websocket.h>

Single signal class for WebSocketServerThread with signal type enum

class WebSocketServerThread : public Limef::thread::Thread<Limef::frame::RawFrame>
#include <websocket.h>

Ultra-fast WebSocket server for streaming frag-MP4 video

Accepts RawFrame(s), i.e. muxed raw media stream: just bytes.

Features:

  • Zero-copy streaming where possible

  • Lockfree hot path for frame handling

  • Automatic initialization segment caching (FTYP + MOOV)

  • Keyframe-synchronized client onboarding

  • Token-based stream access control

  • Multiple clients per stream

  • Automatic cleanup of dead connections

All incoming ftyp and moov packets per slot are cached

Complete walkthrough:

 media_thread:
  class: MediaFileThread
  note: sends CodecFrame only once at thread startup
  fork:
    fmp4:
      class: FMP4FrameFilter
      internal:
        gate:
          class: GateFrameFilter
          note: | 
            although initially closed, is always listening and caching
            CodecFrame(s).  When gate is opened, passes immediately CodecFrame downstream
        transcode:
          class: AudioTranscodeFrameFilter
          note: transcodes to AAC and sends modified CodecFrame downstream
        muxer:
          class: MuxerFrameFilter
          note: | 
            requires CodecFrame to start muxing
            for fmp4, CodecFrame is necessary so that ftyp and moov get emitted
        partitioner:
          class: MP4PartitionFrameFilter
      fork:
        websocket:
          class: WebSocketServerThread
 
Suppose gate first closed.  Once it is opened, sends CodecFrame immediately downstream,
muxer is initialized, ftyp and moov are sent correctly downstream

 *

Public Functions

bool startServer(int port = 8080)

Start WebSocket server on specified port

bool setSlotUUID(Slot slot, const std::string &uuid)

Register UUID <-> Slot mapping Called when camera/stream is added to system

bool addStreamToken(const std::string &token, const std::vector<std::string> &allowed_uuids, int64_t expires_timestamp = 0)

Add streaming token with allowed UUIDs

Parameters:
  • token – Access token string

  • allowed_uuids – List of stream UUIDs this token can access

  • expires_timestamp – Unix timestamp when token expires (0 = never)

inline bool isServerRunning() const

Get server status (lockfree)

class WebSocketStreamBuffer
#include <websocket.h>

Helper class for per-stream data structures Handles initialization segment caching and client management