FrameFifos

A FrameFifo manages a pool of pre-allocated frames (stack) and a queue (fifo) for inter-thread communication. All FrameFifo variants live in the Limef namespace.

template<typename T>
class FrameFifo

FrameFifo: a stack and a fifo.

FrameFifo establishes

  • (1) A stack of reserved frames, implemented using a circular buffer

  • (2) A fifo, implemented with std::queue

Both (1) and (2) hold pointers of type Frame*. See class Frame for more details.

Inserting a new frame (a) into framefifo is done with FrameFifo::writeCopy:

  • it takes a frame (b) from the stack (1)

  • copies contents of (a) into (b)

  • places (b) into the fifo (2)

After that, the copied stack frame (b) is typically sent downstream. Once downstream operations have been completed, FrameFifo::recycle is called on frame (b), returning the frame (b) into the stack (1)

FrameFifo is typically used by a thread.

For Frame types that have lots of allocated memory, memory is not (re)allocated, but copied instead into pre-allocated membufs of pre-reserved Frames. These pre-reserved Frames are kept in FrameFifo’s internal stack.

All Frame* (and dowcasted) pointers lifetimes are managed by FrameFifo, i.e. Frame* pointers are always returned to the Fifo with the recycle method that knows what to do with them once they’re used. NOT using unique_ptr here is intentional.

All frames that are of the template T use the pre-reserved Frame and stack scheme.

All other frames are passed and placed into the Fifo after just cloning them.

Subclassed by Limef::PollFrameFifo< T >

Public Functions

FrameFifo(std::string name, const FrameFifoContext &ctx)

name : a unique name identifying this framefifo

ctx : a defining this framefifo

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

Set logger instance for this FrameFifo

void close()

Stop waiting for all condition variables asap

virtual bool writeCopy(const Limef::frame::Frame *f)

Copies or clones a frame and places it into the internal fifo

For frames of the template type T:

f : incoming frame

  • takes frame (b) from the stack

  • copies contents of (f) into (b)

  • places (b) into the fifo

For all other frame types just clones the frame, using the Limef::frame::Frame class clone method, and places it into the fifo

Limef::frame::Frame *read(std::chrono::microseconds timeout)

Returns next frame available in the internal fifo

If timeout takes place, returns nullptr

timeout : operation timeout in microseconds

void recycle(Limef::frame::Frame *frame)

Returns the frame and places it back into the internal stack for Frames of type T, all other frame types are simply deleted

The only place where this should be called is Limef::thread::Thread’s frameTask method: the frameTask initializes the filterchain by calling the first filter in the chain. Once the filterchain is finished, recycle should be called.

class OrderedFrameFifo : public Limef::FrameFifo<Limef::frame::PacketFrame>

A FrameFifo that maintains PacketFrames in DTS order.

Extends FrameFifo to provide automatic sorting of PacketFrames based on their DTS (Decoding Time Stamp). Sorting is triggered only when a DTS discontinuity is detected between consecutive packets, making it efficient for mostly-ordered streams.

Non-PacketFrames pass through normally without affecting the ordering.

class DecodedFrameFifo : public Limef::FrameFifo<frame::DecodedFrame>

FrameFifo for DecodedFrame with GPU buffer pool support.

Extends FrameFifo<DecodedFrame> to manage a dedicated GPU buffer pool (hw_frames_ctx) for stack frames. Handles multiple scenarios:

When ctx.gpu_target == SW (default):

  • CPU frames: CPU→CPU copy (standard behavior)

  • GPU frames: GPU→GPU copy into owned pool (prevents buffer reuse issues)

When ctx.gpu_target == CUDA/VAAPI:

  • CPU frames: CPU→GPU upload to target device

  • GPU frames on target device: GPU→GPU copy

  • GPU frames on different device: GPU→CPU→GPU transfer (with warning)

Pool creation is lazy - happens on first frame with matching dimensions. Resolution changes trigger pool recreation.

Public Functions

virtual bool writeCopy(const frame::Frame *f) override

Copy frame into fifo with GPU pool management.

Handles CPU→GPU upload, GPU→GPU copy, and cross-device transfers based on ctx.gpu_target setting.

class TensorFrameFifo : public Limef::FrameFifo<frame::TensorFrame>

Public Functions

TensorFrameFifo(std::string name, const FrameFifoContext &ctx)
Parameters:
  • name – Unique name for this fifo

  • ctx – FrameFifoContext — gpu_target/gpu_device respected for CUDA upload

virtual bool writeCopy(const frame::Frame *f) override

Copy frame into fifo, with optional CPU↔GPU transfer at the boundary.

  • SW target + GPU source: downloads each plane D2H into a CPU stack frame.

  • CUDA target + CPU source: uploads each plane H2D into a GPU stack frame.

  • All other combinations delegate to the base class (memcpy or D2D).

  • Non-TensorFrames always use the base class clone path.

template<typename T>
class PollFrameFifo : public Limef::FrameFifo<T>

FrameFifo that can be multiplexed with poll/select.

Extends FrameFifo with an EventFd that is signaled whenever a frame is written. This allows the fifo to be multiplexed with socket I/O using poll() or select().

Usage:

PollFrameFifo<PacketFrame> fifo("fifo", ctx);

// In your poll loop:
struct pollfd fds[2];
fds[0] = {socket_fd, POLLIN, 0};
fds[1] = {fifo.getFd(), POLLIN, 0};

poll(fds, 2, timeout_ms);

if (fds[1].revents & POLLIN) {
    while (auto* frame = fifo.tryRead()) {
        processFrame(frame);
        fifo.recycle(frame);
    }
}

Public Functions

inline int getFd() const

Get the file descriptor for use with poll/select.

Add this fd to your poll set with POLLIN. When signaled, call tryRead() to get available frames.

inline virtual bool writeCopy(const Limef::frame::Frame *f) override

Write a copy of the frame and signal the eventfd.

Overrides FrameFifo::writeCopy to also signal the eventfd, waking up any poll() waiting on getFd().

inline Limef::frame::Frame *tryRead()

Non-blocking read for use after poll signals.

Call this in a loop after poll() indicates getFd() is readable. Returns nullptr when no more frames are available.

Returns:

Frame pointer or nullptr if fifo is empty