Framefilters¶
Framefilters are the building blocks of pipelines.
The base class Limef::ff::FrameFilter defines the go() / cc() / pass() interface.
Use Limef::ff::SimpleFrameFilter for one-to-one filters and
Limef::ff::SplitFrameFilter for one-to-many forks.
-
namespace ff¶
Framefilters.
Typedefs
-
using json = nlohmann::json¶
Enums
Functions
-
static size_t serialize_frame_wrapper(uint8_t *buffer, size_t buffer_size, Frame *frame)¶
-
class AnnexBFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <annexb.h>
FrameFilter that converts H.264/H.265 video from AVCC to Annex B format.
Activates the
h264_mp4toannexb/hevc_mp4toannexbBSF when the incoming stream is in AVCC (length-prefixed) format, i.e.extradata[0] != 0x00. Typical sources: demuxed MP4 files, RTSP streams from hardware cameras.NVENC always outputs Annex B natively, regardless of
AV_CODEC_FLAG_GLOBAL_HEADER, so this filter is a no-op for NVENC-encoded streams.Public Functions
-
struct AudioTranscodeContext¶
- #include <audiotranscode.h>
A Context variable that defines the audio codecs and their specific requirements.
NOTE: Only supports planar audio channel formats.
Public Functions
-
inline AudioTranscodeContext(AVCodecID codec, int bitrate, AVSampleFormat sample_format, int sample_size, const std::vector<int> &flags, const std::map<std::string, std::string> &opts = {})¶
Constructor with options.
- Parameters:
codec – Audio codec ID
bitrate – Target bitrate
sample_format – Target sample format (AVSampleFormat). NOTE: must be a planar format.
calc – Sample calculation method
flags – Codec flags
opts – Dictionary options for encoder
Public Members
-
AVCodecID codec_id = {AV_CODEC_ID_AAC}¶
AV_CODEC_ID of the audio codec. Use to define the target codec.
-
int bit_rate = {44100}¶
Default / good bitrate for the codec. Feel free to change.
-
AVSampleFormat sample_format = {AV_SAMPLE_FMT_FLTP}¶
The default planar format for AAC.
-
int sample_size = {1024}¶
Sample size for the encoder.
-
const std::vector<int> codec_flags¶
Just store raw FFmpeg flags.
-
std::map<std::string, std::string> options¶
New field: dictionary options for the encoder.
Public Static Functions
-
static inline AudioTranscodeContext AAC()¶
Advanced Audio Codec (AAC)
-
static inline AudioTranscodeContext AAC(const std::map<std::string, std::string> &opts)¶
AAC with custom options.
- Parameters:
opts – Dictionary options to override defaults
- Returns:
AudioTranscodeContext
-
inline AudioTranscodeContext(AVCodecID codec, int bitrate, AVSampleFormat sample_format, int sample_size, const std::vector<int> &flags, const std::map<std::string, std::string> &opts = {})¶
-
class AudioTranscodeFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <audiotranscode.h>
FrameFilter that transcodes audio to a different codec.
Takes a CodecFrame first to get stream information, then accepts audio PacketFrames, transcodes them and outputs new PacketFrames with the desired audio codec (target codec)
If the incoming codec matches the target codec, then passthrough is enabled and audio packets are passed downstream as-is
- Param name:
Name for this framefilter
- Param ctx:
A Context that defines the audio codec and it’s requirements
- Param next:
(optional) next framefilter in the chain
Public Functions
-
class CodecAssertFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <codecassert.h>
FrameFilter that asserts the incoming stream matches an allowed codec pair.
On the first CodecFrame it inspects the video and audio codec IDs and checks them against a caller-supplied list of CodecPair values. If no pair matches the filter logs a fatal error and inutilizes itself: all subsequent frames (including the non-matching CodecFrame) are silently dropped.
When a pair matches, the CodecFrame and all following frames are forwarded downstream normally.
-
class CodecCacheFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <codec_cache.h>
FrameFilter that caches and can resend CodecFrames.
Acts as a passthrough filter for all frames, but when it encounters a CodecFrame, it makes an internal copy that can be resent later. This is useful when a new client/component needs to receive codec parameters mid-stream without waiting for a new CodecFrame to arrive naturally.
Thread-safe: can be called from multiple threads.
Example usage:
// In setup code CodecCacheFrameFilter codec_cache("codec_cache"); source.getOutput().cc(codec_cache).cc(next_filter); // ... later when a new component joins codec_cache.reSend(); // Resends cached CodecFrame to next_filter
Public Functions
-
inline explicit CodecCacheFrameFilter(std::string name = "CodecCacheFrameFilter")¶
Construct a new Codec Cache Frame Filter.
- Parameters:
name – Unique name for this filter
next – Optional pointer to the next filter in chain
-
~CodecCacheFrameFilter() override = default¶
Destroy the Codec Cache Frame Filter.
Cleans up any cached codec frame.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Process incoming frame.
Passes all frames downstream. For CodecFrames, also maintains an internal copy.
- Parameters:
frame – The frame to process
-
inline bool reSend()¶
Resend the cached CodecFrame downstream.
If a CodecFrame has been cached, sends a copy downstream. Thread-safe: can be called from any thread.
- Returns:
true if a CodecFrame was sent
- Returns:
false if no CodecFrame is available to send
-
inline void reset()¶
Reset the filter state.
Clears any cached CodecFrame. After calling this method, hasCodecFrame() will return false and reSend() will not send anything until a new CodecFrame is received.
Thread-safe: can be called from any thread.
-
inline bool hasCodecFrame() const¶
Check if a CodecFrame has been cached.
Thread-safe method to check if a CodecFrame is available.
- Returns:
true if a CodecFrame has been cached
- Returns:
false if no CodecFrame is cached
-
inline explicit CodecCacheFrameFilter(std::string name = "CodecCacheFrameFilter")¶
-
class CodecMessageFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <codec_message.h>
FrameFilter that sends a JSON message through a pipe when it encounters a CodecFrame.
Passes all frames through to the next filter unchanged, but when it encounters a CodecFrame, it sends a JSON message through the provided pipe for external monitoring.
Thread-safe: can be used from multiple threads.
Example usage:
// Create a pipe for receiving messages auto [sender_pipe, receiver_pipe] = Limef::comm::Pipe::create(); // Create filter CodecMessageFrameFilter message_filter("codec_monitor", &sender_pipe); // Connect to pipeline source.getOutput().cc(message_filter).cc(next_filter); // In another thread or context, monitor for codec messages std::string json_str; if (receiver_pipe.recv(json_str)) { auto msg = json::parse(json_str); std::cout << "New codec: video=" << msg["has_video"] << ", audio=" << msg["has_audio"] << std::endl; }
Public Functions
-
inline explicit CodecMessageFrameFilter(std::string name = "CodecMessageFrameFilter", Limef::comm::Pipe *pipe = nullptr)¶
Construct a new Codec Message Frame Filter.
- Parameters:
name – Unique name for this filter
pipe – Pipe to send codec messages through
next – Optional pointer to the next filter in chain
-
inline void setPipe(Limef::comm::Pipe *pipe)¶
Set the pipe to send messages through.
- Parameters:
pipe – Pipe for sending messages
-
inline explicit CodecMessageFrameFilter(std::string name = "CodecMessageFrameFilter", Limef::comm::Pipe *pipe = nullptr)¶
-
struct CodecPair¶
- #include <codecassert.h>
A (video, audio) codec pair used by CodecAssertFrameFilter.
Use AV_CODEC_ID_NONE for either field to mean “don’t check this track type”. If the source has no stream of that type the field is treated as AV_CODEC_ID_NONE.
Examples:
CodecPair{AV_CODEC_ID_H264, AV_CODEC_ID_AAC} // H264 video + AAC audio CodecPair{AV_CODEC_ID_H264, AV_CODEC_ID_NONE} // H264 video, any/no audio CodecPair{AV_CODEC_ID_NONE, AV_CODEC_ID_OPUS} // any/no video, Opus audio
-
class ComposeFrameFilter : public Limef::ff::FrameFilter¶
- #include <compose.h>
Base class for composite framechain.
Allows creating complex framefilters by composing simpler ones. Subclasses should create and chain their specific filters in their constructor, for example:
class FMP4FrameFilter : public ComposeFrameFilter { public: FMP4FrameFilter(const AudioParams& params) : ComposeFrameFilter("FMP4") { // Chain them together this.chain = { new AudioDecoder(params), new Muxer() }; } };
NOTE: ComposeFrameFilter will delete the framefilters you have created in-place in the vector initialization at dtor time, so no need to worry about them.
Subclassed by Limef::ff::FMP4FrameFilter, Limef::ff::RTSPMuxerFrameFilter, Limef::ff::WebMFrameFilter, Limef::ff::WebRTCMuxerFrameFilter
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Go is called by the upstream framefilter.
In this case, simply forward to first internal framefilter
-
inline virtual FrameFilter &cc(FrameFilter &next_) override¶
In this case, chain internal last filter to the next_
-
inline virtual void clear() override¶
Call clear() of the internal last framefilter
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class CountDecodedFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <count.h>
Count DecodedFrames and report count + fps on demand.
All frames are passed downstream unchanged. Only
DecodedFrames (FrameClass::Decoded) are counted. Timing starts on the first DecodedFrame seen.report()andgetCount()are safe to call from any thread.Example:
CountDecodedFrameFilter counter("counter"); camera.getOutput().cc(counter); // ... run for a while ... counter.report(); // logs: "counter: 150 frames in 10.0s → 15.0 fps"
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline void report() const¶
Log frame count and mean fps since the first DecodedFrame.
-
inline long getCount() const¶
Return number of DecodedFrames received so far.
-
inline long sinceLastFrame() const¶
Milliseconds since the last DecodedFrame; -1 if none has arrived yet.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class CountTensorFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <count.h>
Count TensorFrames and report count + fps on demand.
All frames are passed downstream unchanged. Only
TensorFrames (FrameClass::Tensor) are counted. Timing starts on the first TensorFrame seen.report()andgetCount()are safe to call from any thread.Example:
CountTensorFrameFilter counter("counter"); camera.getOutput().cc(counter); // ... run for a while ... counter.report(); // logs: "counter: 150 frames in 10.0s → 15.0 fps"
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline void report() const¶
Log frame count and mean fps since the first TensorFrame.
-
inline long getCount() const¶
Return number of TensorFrames received so far.
-
inline long sinceLastFrame() const¶
Milliseconds since the last TensorFrame; -1 if none has arrived yet.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class CpuSwScaleConverter : public Limef::ff::DecodedToTensorConverter¶
- #include <decoded_to_tensor_cpu.h>
Converts any CPU DecodedFrame → TensorFrame (c, h, w) UInt8 via libswscale.
Colour input → GBRP intermediate → CHW(3, H, W) via permuted dst[] pointers (zero extra copy). Greyscale input → GRAY8 → CHW(1, H, W) directly.
ChannelOrder::RGB→ channels [R, G, B] in slots [0, 1, 2].ChannelOrder::BGR→ channels [B, G, R] in slots [0, 1, 2].Public Functions
-
inline virtual bool accepts(const frame::DecodedFrame &df) const override¶
Return true if this converter handles
df(may inspect format and location).
-
virtual bool convert(const frame::DecodedFrame &src, frame::TensorFrame &dst, ChannelOrder order) override¶
Convert
srcintodst.dstis the filter’s internal TensorFrame (grow-only, reused across calls). After a successful call,dst.planes[0]has shape(c, h, w), dtype UInt8.- Parameters:
src – Incoming video DecodedFrame (isVideo() guaranteed by caller).
dst – Output TensorFrame to fill (grow-only).
order – Desired output channel order.
- Returns:
true on success; false to signal a conversion error (frame is dropped).
-
inline virtual const char *converterName() const override¶
Short name used in log messages.
-
inline virtual bool accepts(const frame::DecodedFrame &df) const override¶
-
class CUDAScaleFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <cuda_scale_frame.h>
Scales NV12 CUDA DecodedFrames to a target resolution on the GPU.
Uses bilinear interpolation. Y and UV planes are scaled independently, preserving the NV12 semi-planar layout (interleaved UV).
Output is always BufferLocation::CUDA (plain cudaMalloc, no hw_frames_ctx), regardless of whether the input was CUDA or CUDA_FFMPEG.
Public Functions
-
struct CUDAScaleParams¶
- #include <cuda_scale_frame.h>
Configuration for CUDAScaleFrameFilter.
Public Members
-
int dst_width = {0}¶
Target width in pixels; 0 = keep source width.
-
int dst_height = {0}¶
Target height in pixels; 0 = keep source height
-
AVPixelFormat output_format = {AV_PIX_FMT_NV12}¶
Output pixel format. AV_PIX_FMT_NV12 (default) preserves NV12 layout. AV_PIX_FMT_YUV420P scales AND de-interleaves the UV plane in one GPU pass, producing a CUDA frame with planar U/V ready for DecodedDownloadFrameFilter + VP8.
-
int dst_width = {0}¶
-
class CudaToFFmpegFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <cuda_to_ffmpeg.h>
Converts BufferLocation::CUDA frames to BufferLocation::CUDA_FFMPEG.
Allocates an AVHWFramesContext (AV_HWDEVICE_TYPE_CUDA, NV12, pooled) on the first incoming CUDA frame and copies each frame into the pool via D2D cudaMemcpy2D. The output frame has hw_frames_ctx set and can be consumed directly by h264_nvenc / hevc_nvenc / av1_nvenc without an upload step.
Public Functions
-
class DecodedDownloadFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <decoded_transfer.h>
Downloads CUDA/CUDA_FFMPEG DecodedFrames to CPU memory (BufferLocation::CPU, NV12).
Grow-only output buffer: reallocated only when a larger frame arrives. Non-CUDA video frames and audio frames are passed through unchanged.
For TensorFrame transfers see tensor_transfer.cpp.
Public Functions
-
class DecodedToTensorConverter¶
- #include <decoded_to_tensor.h>
Abstract base for pixel-format converters used by DecodedToTensorFrameFilter.
Each subclass handles one (or a small group of closely related) AVPixelFormats. Converters are owned by the filter and never exposed to users.
The
convert()call must be reentrant-safe for the same object (called once per frame, always from the filter’s driving thread).Subclassed by Limef::ff::CpuSwScaleConverter
Public Functions
-
virtual bool accepts(const frame::DecodedFrame &df) const = 0¶
Return true if this converter handles
df(may inspect format and location).
-
virtual bool convert(const frame::DecodedFrame &src, frame::TensorFrame &dst, ChannelOrder order) = 0¶
Convert
srcintodst.dstis the filter’s internal TensorFrame (grow-only, reused across calls). After a successful call,dst.planes[0]has shape(c, h, w), dtype UInt8.- Parameters:
src – Incoming video DecodedFrame (isVideo() guaranteed by caller).
dst – Output TensorFrame to fill (grow-only).
order – Desired output channel order.
- Returns:
true on success; false to signal a conversion error (frame is dropped).
-
virtual const char *converterName() const = 0¶
Short name used in log messages.
-
virtual bool accepts(const frame::DecodedFrame &df) const = 0¶
-
class DecodedToTensorFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <decoded_to_tensor.h>
FrameFilter that converts DecodedFrame → TensorFrame (c, h, w).
Usage:
DumpFrameFilter dump("dump"); DecodedToTensorFrameFilter d2t("d2t", ChannelOrder::RGB); d2t.cc(dump); // … drive with decoded frames …
Public Functions
-
explicit DecodedToTensorFrameFilter(std::string name = "DecodedToTensorFrameFilter", ChannelOrder out_order = ChannelOrder::RGB)¶
- Parameters:
name – Identifier used in log messages.
out_order – Desired output channel order (default: RGB).
-
explicit DecodedToTensorFrameFilter(std::string name = "DecodedToTensorFrameFilter", ChannelOrder out_order = ChannelOrder::RGB)¶
-
class DecodedUploadFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <decoded_transfer.h>
Uploads CPU DecodedFrames to plain CUDA memory (BufferLocation::CUDA).
Allocates cudaMalloc’d NV12 output buffers lazily on the first video frame. Grow-only: the buffer is reallocated only when a larger frame arrives. Non-video frames and frames already on GPU are passed through unchanged.
For TensorFrame transfers see tensor_transfer.cpp.
Public Functions
-
struct DecodedUploadParams¶
- #include <decoded_transfer.h>
Configuration for CPU→CUDA upload.
Only BufferLocation::CUDA is supported as target.
-
class DecodingFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <decoding.h>
A
FrameFilterthat decodes frames.Receives
Limef::frame::CodecFrames andLimef::frame::PacketFramesProduces
Limef::frame::DecodedFramesUses internally the
Limef::decode::Decoderclass
This framefilter uses both
Limef::frame::CodecFrames andLimef::frame::PacketFrames that pass through it: the former is used to set up decoders and the latter ones are passed on to the set’ted up decoders as-is.Output from this framefilter is a
Limef::frame::DecodedFrame.Always when this framefilter receives a new PacketFrame, it feeds it to the decoder and after that drains the decoder, i.e. calls the decoder until all decoded frames are fetched from the decoder and sent downstream.
Supports multiple decoder backends via the factory pattern:
// Default: FFmpeg software decoding DecodingFrameFilter decode; // Custom FFmpeg params (more threads, etc.) FFmpegDecoderParams params; params.thread_count = 4; DecodingFrameFilter decode("decode", params); // V4L2 hardware decoding (when available) V4L2NVDecoderParams v4l2_params; v4l2_params.device = "/dev/video0"; DecodingFrameFilter decode("decode", v4l2_params);
Note
For hardware frame lifetime details (when using VAAPI/CUDA decoding), see the “Hardware Frame Lifecycle” section in Limef::decode::Decoder.
Public Functions
-
explicit DecodingFrameFilter(std::string name = "DecodingFrameFilter", const Limef::decode::VideoDecoderParams ¶ms = Limef::decode::FFmpegDecoderParams{})¶
Construct a decoding framefilter.
- Parameters:
name – Identifier for logging
params – Decoder parameters (FFmpegDecoderParams, V4L2NVDecoderParams, etc.)
-
class DumpFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <dump.h>
Dump info about the
FrameUses
Frame’s dump method to print information about the frame to stdoutPublic Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class DumpPacketFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <dump_packet.h>
A
FrameFilterthat dumps information aboutPacketFrames.Public Functions
-
class EmptyFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <empty.h>
Dummy
FrameFilterA
FrameFilterthat does nothing.
A use case: some object’s internal framefilter that start a framefilter chain
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class EncodeCheckFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <encode_check.h>
Validates stream codec types and controls downstream frame flow.
Waits for initial CodecFrame and checks if its codecs match allowed lists. If match, passes all frames downstream. If no match, blocks further frames and sends warning InfoFrame.
Public Functions
-
EncodeCheckFrameFilter(std::string name = "EncodeCheckFilter", const std::vector<AVCodecID> &allowed_video_codecs = {}, const std::vector<AVCodecID> &allowed_audio_codecs = {}, std::string warning_message = "Unsupported codec detected")¶
Construct filter with allowed codec lists.
- Parameters:
name – Filter name
allowed_video_codecs – List of allowed video codec IDs
allowed_audio_codecs – List of allowed audio codec IDs
warning_message – Message for log and InfoFrame on codec mismatch
-
EncodeCheckFrameFilter(std::string name = "EncodeCheckFilter", const std::vector<AVCodecID> &allowed_video_codecs = {}, const std::vector<AVCodecID> &allowed_audio_codecs = {}, std::string warning_message = "Unsupported codec detected")¶
-
class EncodingFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <encoding.h>
A
FrameFilterthat encodes frames.Receives
Limef::frame::StreamFrames andLimef::frame::DecodedFramesProduces
Limef::frame::CodecFrame(once, after encoder init) andLimef::frame::PacketFramesUses internally the
Limef::encode::Encoderclass
This framefilter uses both
Limef::frame::StreamFrames andLimef::frame::DecodedFrames that pass through it: the former is used to configure encoder timing (fps, timebase) and the latter ones are encoded into packets.Output sequence:
When encoder initializes (after first DecodedFrame with dimensions):
Sends
CodecFramedownstream with encoder’s codec parametersThis allows downstream decoders to initialize
For each encoded packet:
Sends
PacketFramedownstream
Has separate encoders for video and audio - routes DecodedFrames to the correct encoder based on their MediaType.
Always when this framefilter receives a new DecodedFrame, it feeds it to the appropriate encoder and after that drains the encoder, i.e. calls the encoder until all encoded packets are fetched and sent downstream.
Type checking:
If a CodecFrame (encoded stream info) is received instead of StreamFrame, a warning is logged - this likely indicates misrouted frames.
Public Functions
-
explicit EncodingFrameFilter(std::string name = "EncodingFrameFilter", const Limef::encode::VideoEncoderParams &video_params = Limef::encode::FFmpegEncoderParams{}, const Limef::encode::VideoEncoderParams *audio_params = nullptr)¶
Construct an encoding framefilter.
Example:
// Using FFmpeg encoder (default) FFmpegEncoderParams ffmpeg_params; ffmpeg_params.codec_id = AV_CODEC_ID_H264; EncodingFrameFilter enc("encoder", ffmpeg_params); // Using V4L2 encoder (when available) V4L2EncoderParams v4l2_params; v4l2_params.device = "/dev/video2"; EncodingFrameFilter enc("encoder", v4l2_params);
- Parameters:
name – Filter name for logging
video_params – Encoding parameters for video (variant of FFmpegEncoderParams, V4L2EncoderParams)
audio_params – Encoding parameters for audio (optional, nullptr to disable)
-
virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
void requestKeyFrame()¶
Request a keyframe from the video encoder on its next output.
Rare exception to the “no public setters on framefilters” rule (see CLAUDE.md, “Thread Safety: FrameFilter Chains”): safe to call from any thread (e.g. a WebRTC PLI callback) because it’s mutex-protected against the driving thread’s own use of video_encoder_ in go()/ setupEncoders() (which may delete/recreate the encoder concurrently).
No-op if there is no video encoder yet (e.g. before the first StreamFrame/DecodedFrame arrives).
-
class FMP4FrameFilter : public Limef::ff::ComposeFrameFilter¶
- #include <fmp4.h>
Composite filter that muxes to fragmented MP4 for browser MediaSource Extensions.
Creates a chain of:
CodecAssertFrameFilter — rejects unsupported codec pairs (see table below)
GateFrameFilter — toggles the stream on/off; call open() to start
MuxerFrameFilter — muxes packets into fMP4 boxes
MP4PartitionFrameFilter — splits the muxed stream into ftyp/moov/moof/mdat RawFrames
Audio transcoding is not performed here — the upstream pipeline is responsible for providing the correct codec pair.
-
template<typename T>
class FrameFifoFrameFilter : public Limef::ff::SimpleFrameFilter¶ - #include <framefifo_.h>
Feeding
FrameFifoA
FrameFilterthat feeds a FrameFifo- Param FrameFifo:
: the
FrameFifothis framefilter is feeding
Public Functions
-
class FrameFilter¶
- #include <framefilter.h>
Subclassed by Limef::ff::ComposeFrameFilter, Limef::ff::SimpleFrameFilter, Limef::ff::SplitFrameFilter, Limef::ff::SwitchFrameFilter
Public Functions
-
virtual void clear() = 0¶
Removes framefilter downstream connection.
-
virtual FrameFilter &cc(FrameFilter &next) = 0¶
Register next framefilter in the chain.
This method does any necessary initialization. Framefilter is not fully functional until this method has been called. Should call init.
-
inline const std::string &getName() const¶
Initialize framefilter.
Get the name of this framefilter
-
virtual void clear() = 0¶
-
class GateFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <gate.h>
Frame filter that can Gate packet stream on/off with timestamp correction.
Handles CodecFrames and PacketFrames with special logic, passes all other frame types through:
Caches received CodecFrame(s) for later use whether the gate is open or closed (always listening for CodecFrames)
Doesn’t pass PacketFrames by default (closed state). All other packets are passed through.
When opened:
If has a cached CodecFrame: sends it downstream and starts passing PacketFrames if conditions are met (see below)
If no CodecFrame yet: waits for it, then sends it and starts passing packets if conditions are met (see below)
When video stream present:
Waits for keyframe before passing any packets
After keyframe, passes all packets
When only audio stream:
Passes packets immediately after opening (no keyframe concept)
When closed:
Stops passing packets
Maintains CodecFrame cache .. keeps listening/caching CodecFrame(s) and passing all other packets than PacketFrames downstream
Thread-safe: can be opened/closed from any thread.
Public Functions
-
explicit GateFrameFilter(std::string name = "GateFrameFilter")¶
Construct a new GateFrameFilter.
- Parameters:
name – Identifier for this filter
next – Next filter in chain
-
void cleanup()¶
Resets state.
-
virtual void go(const Limef::frame::Frame *frame) override¶
Process incoming frames.
For CodecFrame:
Cache for later use
For PacketFrame when open:
Adjust timestamps to start from zero
For video, wait for keyframe before passing
For audio, pass immediately
All other frame types pass through.
- Parameters:
frame – Input frame
-
void open()¶
Open the Gate and start passing packets.
If we have CodecFrame:
Send it downstream
Start passing PacketFrame(s) (after keyframe for video)
If no CodecFrame:
Wait for CodecFframe to appear before taking any other action
Meanwhile pass downstream all other than PacketFrame(s)
-
void close()¶
Close the Gate and stop passing packets.
Resets internal state:
Stops passing packets
Maintains CodecFrame cache
-
class H264StripParamSetsFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <h264_strip_param_sets.h>
Strips SPS (NAL type 7) and PPS (NAL type 8) from H.264 Annex B packets after the first occurrence, preventing NVDEC from firing repeated V4L2_EVENT_SOURCE_CHANGE events on every GOP boundary.
Public Functions
-
class InfoFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <info.h>
Captures InfoFrames and stores their messages.
Passes all other frames downstream but captures InfoFrames. Messages can be retrieved later using popMessage().
Public Functions
-
virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
bool hasMessage() const¶
Check if there are messages available.
- Returns:
true if messages in queue
-
std::string popMessage()¶
Get oldest message from queue.
- Returns:
Message string or empty string if none available
-
virtual void go(const Limef::frame::Frame *frame) override¶
-
class MP4PartitionFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <mp4part.h>
Repartitions fragmented MP4 stream into proper box-aligned chunks.
Input: Raw byte blobs from FFmpeg muxer that may contain:
Partial MP4 boxes
Multiple MP4 boxes
Parts of multiple MP4 boxes
Output: Clean-cut MP4 boxes as individual frames
Public Functions
-
class MP4ProbeFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <mp4_probe.h>
Analyzes and logs fragmented MP4 boxes as they pass through.
Outputs box information in format: <BOX_TYPE/size=N> for incomplete boxes <BOX_TYPE/size=N/complete> for complete boxes
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class MuteAudioFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <muteaudio.h>
Drops all audio from the stream.
CodecFrame: copies the frame but removes all audio streams before passing downstream. PacketFrame with audio media type: silently dropped. All other frame types: passed through unchanged.
Use this upstream of WebRTCMuxerFrameFilter when the file/RTSP source carries an audio codec that WebRTC does not accept (e.g. PCM S16LE).
Public Functions
-
class MuxerFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <muxer.h>
FrameFilter that muxes elementary streams into a container format.
This is a very general muxing framefilter that produces RawFrame(s) that are processed by downstream framefilters and threads as just muxed media stream: just raw bytestream
For more specifically muxed stream, feel free to implement more complementary framefilters, see for example RTPMuxerFrameFilter.
Takes a CodecFrame first to get stream information, then accepts elementary PacketFrames (H.264, AAC, etc.) as input and outputs RawFrames containing muxed data in specified container format.
The first output will contain format headers required for initializing downstream demuxers.
Internals:
AVFormatContext refers to AVIOContext AVIOContext refers to a custom writeCallback
walkthrough: go -> processPacket -> av_interleaved_write_frame -> returns immediately on some instances, when av_interleaved_write_frame is called, writeCallback is activated internally by ffmpeg -> pass
Public Functions
-
void close()¶
flush the muxer
-
virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
void setOption(const char *key, const char *value)¶
Set muxer options using FFmpeg AVDictionary key/value pairs
-
void close()¶
-
class MuxingContext¶
- #include <muxer.h>
Parameters for muxing streams into containers.
Public Functions
-
inline MuxingContext(const std::string &format, const std::map<std::string, std::string> &custom_options)¶
Create context with custom options
Public Members
-
const std::string format_name¶
FFmpeg format name (e.g. “mp4”, “flv”, etc.)
-
std::map<std::string, std::string> options¶
Custom muxer options (key-value pairs for AVDictionary)
Public Static Functions
-
static inline MuxingContext MKV()¶
Ready-made context for Matroska
-
static inline MuxingContext FMP4()¶
Ready-made context for fragmented MP4 A separate fragment for each frame: more balanced fragmentation
-
static inline MuxingContext FMP4_KEYFRAG()¶
Ready-made context for fragmented MP4 One fragment per each keyframe - all other frames are included in that same macrofragment
-
static inline MuxingContext WebM()¶
Ready-made context for streaming WebM (VP8 / VP9).
cluster_time_limit forces a new Cluster every N milliseconds, giving the browser regular segment boundaries without needing the muxer to seek back and fill in a Cluster size (which is impossible with custom IO). Clusters written this way carry unknown size (0x01FFFFFFFFFFFFFF), which WebMPartitionFrameFilter handles by detecting the next Cluster start.
Audio note: WebM uses Vorbis or Opus, not AAC. If the upstream source carries AAC audio, the muxer will reject it. For video-only VP8/VP9 sources (e.g. USBCameraThread with no audio) this is fine.
-
inline MuxingContext(const std::string &format, const std::map<std::string, std::string> &custom_options)¶
-
class PutInfoFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <putinfo.h>
Injects InfoFrames into the pipeline from an external thread.
All frames are passed downstream unchanged. Calling put() from any thread queues a message; the next go() call (on the driving thread) drains the queue and emits an InfoFrame per message before forwarding the regular frame.
Public Functions
-
virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
void put(const std::string &msg)¶
Queue a message for injection as an InfoFrame. Thread-safe — may be called from any thread.
-
virtual void go(const Limef::frame::Frame *frame) override¶
-
class RTPMuxerFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <rtpmuxer.h>
FrameFilter that muxes elementary streams into RTP packets.
Takes a CodecFrame first to get stream information and generate SDP, then accepts PacketFrames and outputs RTPFrames.
Flow:
CodecFrame → RTPMuxerFrameFilter ├── SDPFrame (once, downstream) └── (waits for packets) PacketFrame → RTPMuxerFrameFilter └── RTPFrame (per RTP/RTCP packet)Usage:
RTPMuxerFrameFilter rtp_muxer("rtp"); rtp_muxer.cc(downstream); // Send CodecFrame first - SDPFrame will be passed downstream rtp_muxer.go(&codec_frame); // Then send packets - RTPFrames will be passed downstream rtp_muxer.go(&packet_frame);
The RTP muxer uses FFmpeg’s RTP format. Each track gets its own AVFormatContext because RTP only supports one stream per context. SDP is generated from all tracks using av_sdp_create().
Incoming PacketFrames must already be in the correct bitstream format (e.g. Annex B for H.264/H.265). Use AnnexBFrameFilter upstream if needed.
Public Functions
-
explicit RTPMuxerFrameFilter(std::string name = "RTPMuxerFrameFilter", int packet_size = 1400)¶
- Parameters:
name – label for logging
packet_size – max size in bytes of each muxed RTP packet (default 1400, i.e. a plain-Ethernet path MTU of ~1500 minus IP/UDP headers). Lower this when the packets must additionally survive a tunnel/VPN hop (e.g. Tailscale, MTU 1280) between this muxer and the client, since nothing downstream fragments an oversized RTP/SRTP packet - see WebRTCMuxerFrameFilter.
-
explicit RTPMuxerFrameFilter(std::string name = "RTPMuxerFrameFilter", int packet_size = 1400)¶
-
struct RTPTrackContext¶
- #include <rtpmuxer.h>
Context for a single RTP track (video or audio)
Each track has its own FFmpeg muxer context because RTP format supports only one stream per context.
Public Members
-
AVFormatContext *fmt_ctx = {nullptr}¶
RTP muxer for this track.
-
int track_index = {0}¶
Track index (0=video, 1=audio, etc.)
-
AVRational input_time_base = {1, 1000}¶
Original input timebase for rescaling.
-
uint32_t ssrc = {0}¶
SSRC assigned by FFmpeg’s RTP muxer.
-
int64_t last_input_dts = {AV_NOPTS_VALUE}¶
Last input DTS before offset (for discontinuity detection)
-
int64_t max_output_dts = {AV_NOPTS_VALUE}¶
Maximum output DTS ever sent (for offset calculation)
-
int64_t dts_offset = {0}¶
Cumulative offset for loops.
-
AVFormatContext *fmt_ctx = {nullptr}¶
-
class RTSPMuxerFrameFilter : public Limef::ff::ComposeFrameFilter¶
- #include <rtspmuxer.h>
Composite filter that canonizes a stream for RTSP/RTP delivery.
Chains: CodecAssertFrameFilter → AnnexBFrameFilter → RTPMuxerFrameFilter
The codec assert rejects unsupported codec combinations with a fatal log and drops all subsequent frames. The Annex B filter converts H.264/H.265 from AVCC (length-prefixed) to Annex B (start-code) format as required by the RTP muxer. Non-H.264/H.265 streams pass through AnnexBFrameFilter unchanged.
-
class ShmemServerFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <shmemserver.h>
Server-side framefilter that serializes frames to shared memory.
Accepts DecodedFrames and RawFrames and serializes them directly to shared memory ring buffer. Other frame types are ignored.
This is a terminal framefilter: frame flow stops here, cannot be connected to downstream filters.
The shared memory ring buffer is initialized in the constructor and cleaned up in the destructor automatically.
Usage:
EventFd event_fd; Limef::shmem::ShmemRingbufferContext ctx("decoder_ring", 5, 8*1024*1024, 100, event_fd); ShmemServerFrameFilter server("shmem-server", ctx); // Chain in framefilter pipeline (terminal filter) decoder.cc(server);
Subclassed by ShmemServerFrameFilterPy
Public Functions
-
ShmemServerFrameFilter(const std::string &name, const Limef::shmem::ShmemRingbufferContext &ctx)¶
Construct server framefilter.
Automatically initializes the shared memory ring buffer.
- Parameters:
name – Name for logging and identification
ctx – Context defining shared memory parameters
next – Should be nullptr - this is a terminal filter
- Throws:
std::runtime_error – if shared memory setup fails
-
~ShmemServerFrameFilter() override¶
Destructor - automatically cleans up shared memory.
-
virtual void go(const Limef::frame::Frame *frame) override¶
Process incoming frames.
DecodedFrames and RawFrames are serialized to shared memory. All other frame types are ignored (logged and dropped).
After each successful write the ring buffer increments the eventfd counter (via setEventFd()), waking any client blocked in select/poll.
- Parameters:
frame – Incoming frame to process
-
inline const Limef::shmem::ShmemRingbufferContext &getContext() const¶
Get the context used by this server.
- Returns:
const Limef::shmem::ShmemRingbufferContext& Context reference
-
size_t getOverflowCount() const¶
Get number of overflow events detected.
Overflows occur when frames are too large for the ring buffer cells or when the ring buffer is full.
- Returns:
size_t Overflow count since creation or last reset
-
void resetOverflowCount()¶
Reset the overflow counter to zero.
-
bool isActive() const¶
Check if the server is currently active.
- Returns:
true if ring buffer is available for writing
Set the logger for this framefilter and its ring buffer.
This hides the base class implementation to also set the ring buffer’s logger.
- Parameters:
logger – Logger instance to use
-
ShmemServerFrameFilter(const std::string &name, const Limef::shmem::ShmemRingbufferContext &ctx)¶
-
class SimpleFrameFilter : public Limef::ff::FrameFilter¶
- #include <simple.h>
A base class for simple one-to-one framefilters.
A
FrameFilterof this class can be connected to only one framefilter in the framefilter chain, i.e.FrameFilter ff1(); FrameFilter ff2(); FrameFilter ff3(); FrameFilter ff4(); ff1.cc(ff2).cc(ff3).cc(ff4)
For subclasses, you should only implement the virtual method
Limef::ff::SimpleFrameFilter::goSubclassed by Limef::ff::FrameFifoFrameFilter< Limef::frame::DecodedFrame >, Limef::ff::FrameFifoFrameFilter< Limef::frame::TensorFrame >, Limef::ff::AnnexBFrameFilter, Limef::ff::AudioTranscodeFrameFilter, Limef::ff::CUDAScaleFrameFilter, Limef::ff::CodecAssertFrameFilter, Limef::ff::CodecCacheFrameFilter, Limef::ff::CodecMessageFrameFilter, Limef::ff::CountDecodedFrameFilter, Limef::ff::CountTensorFrameFilter, Limef::ff::CudaToFFmpegFrameFilter, Limef::ff::DecodedDownloadFrameFilter, Limef::ff::DecodedToTensorFrameFilter, Limef::ff::DecodedUploadFrameFilter, Limef::ff::DecodingFrameFilter, Limef::ff::DumpFrameFilter, Limef::ff::DumpPacketFrameFilter, Limef::ff::EmptyFrameFilter, Limef::ff::EncodeCheckFrameFilter, Limef::ff::EncodingFrameFilter, Limef::ff::FrameFifoFrameFilter< T >, Limef::ff::GateFrameFilter, Limef::ff::H264StripParamSetsFrameFilter, Limef::ff::InfoFrameFilter, Limef::ff::MP4PartitionFrameFilter, Limef::ff::MP4ProbeFrameFilter, Limef::ff::MuteAudioFrameFilter, Limef::ff::MuxerFrameFilter, Limef::ff::PutInfoFrameFilter, Limef::ff::RTPMuxerFrameFilter, Limef::ff::ShmemServerFrameFilter, Limef::ff::StreamGateFrameFilter, Limef::ff::SwScaleFrameFilter, Limef::ff::TensorToDecodedFrameFilter, Limef::ff::ThrottleFrameFilter, Limef::ff::WebMPartitionFrameFilter, Limef::ff::WritePNGFrameFilter
Public Functions
-
inline virtual void pass(const Limef::frame::Frame *frame) final¶
Define how frames are passed downstream.
Used by method
Limef::ff:FrameFilter::goCallsLimef::ff:FrameFilter::gomethod(s) of the downstream filter(s)
-
inline virtual FrameFilter &cc(FrameFilter &next_) override¶
Register next framefilter in the chain.
This method does any necessary initialization. Framefilter is not fully functional until this method has been called. Should call init.
-
inline virtual void clear() override¶
Removes framefilter downstream connection.
-
inline virtual void pass(const Limef::frame::Frame *frame) final¶
-
class SplitFrameFilter : public Limef::ff::FrameFilter¶
- #include <split.h>
A base class for one-to-many framefilters.
A
FrameFilterof this class can be connected to several downstream framefilters:Maintains an internal registry of connected framefiltersFrameFilter ff1(); FrameFilter ff2(); SplitFrameFilter ff3(); // connect many downstream framefilters: ff1.cc(ff2).cc(ff3).cm(ff41,ff42,ff43) // connect many downstream framefilters one-by-one ff3.cc(ff41) ff3.cc(ff42) // disconnect: ff3.dc(ff41); ff3.dc(ff42)
NOTE: this framefilter is thread safe, i.e. you can use methods cc, cm and dc after threads have been started on the filterchain
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline virtual void pass(const Limef::frame::Frame *frame) final¶
Define how frames are passed downstream.
Used by method
Limef::ff:FrameFilter::goCallsLimef::ff:FrameFilter::gomethod(s) of the downstream filter(s)
-
inline virtual FrameFilter &cc(FrameFilter &next) override¶
Register next framefilter in the chain.
This method does any necessary initialization. Framefilter is not fully functional until this method has been called. Should call init.
-
inline virtual void clear() override¶
Removes framefilter downstream connection.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
-
class StreamGateFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <streamgate.h>
Passes only source-originated StreamFrames; drops relay replays.
Acts as a gate on the
StreamFrame::from_sourceflag:from_source == true→ frame passes through unchanged.from_source == false→ frame is silently dropped.
All other frame types (PacketFrame, DecodedFrame, TensorFrame, SignalFrame, CodecFrame, …) pass through unconditionally.
Public Functions
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
class SwitchFrameFilter : public Limef::ff::FrameFilter¶
- #include <switch.h>
Routes incoming frames to exactly one of N output terminals.
Only the currently active terminal receives frames. Calling
toggle()at runtime changes which terminal is active. When a terminal is first activated, any cachedCodecFrameandStreamFramemetadata are replayed automatically before the next live frame is forwarded, so the new downstream has the codec/stream context it needs even if those one-time metadata frames have already passed.Caching rules:
CodecFrameandStreamFrameare cached keyed by their slot number.A newer frame for the same slot replaces the cached one.
All other frame types are never cached.
Public Functions
-
inline explicit SwitchFrameFilter(std::string name = "switchframefilter", int n = 1)¶
- Parameters:
name – Filter name (for logging)
n – Number of output terminals (must be >= 1)
-
inline FrameFilter &cc(int index, FrameFilter &next)¶
Connect output terminal
indextonext.- Parameters:
index – Terminal index in [0, n)
next – Downstream framefilter
- Returns:
Reference to
next(for chaining further downstream)
-
inline virtual FrameFilter &cc(FrameFilter &next) override¶
Connect terminal 0 to
next.Convenience override compatible with the standard
cc()chain API. Equivalent tocc(0, next).
-
inline void toggle(int index)¶
Activate output terminal
index.Pass
-1to deactivate all terminals (frames are silently dropped). When activating a terminal, a lazy replay of cached metadata is scheduled: the next call togo()will forward all cachedCodecFrame/StreamFrameentries before the live frame.- Parameters:
index – Terminal to activate, or -1 to deactivate all
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
inline virtual void clear() override¶
Removes framefilter downstream connection.
-
class SwScaleFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <swscale.h>
Converts bitmap frames to specified pixel format.
For DecodedVideoFrames:
If already in target format, passes downstream as-is
If different format, converts using swscale
For StreamFrames: makes a deep copy, updates the video stream’s pixel format to target_format, then passes the copy downstream. This keeps downstream consumers (encoders, shmem servers) informed of the actual output format.
All other frame types pass through unchanged.
Public Functions
-
class TensorToDecodedFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <tensor_to_decoded.h>
Converts TensorFrame (c, h, w) UInt8 → DecodedFrame.
CPU planes → GBRP or GRAY8 DecodedFrame (via memcpy). GPU planes → AV_PIX_FMT_CUDA / NV12 DecodedFrame (via CUDA kernel, LIMEF_CUDA only). Also emits a StreamFrame when the stream starts, dimensions change, or CPU/GPU mode changes.
Public Functions
-
explicit TensorToDecodedFrameFilter(std::string name = "TensorToDecodedFrameFilter", ChannelOrder in_order = ChannelOrder::RGB)¶
- Parameters:
name – Identifier used in log messages.
in_order – Channel order of the input tensor (default: RGB).
-
explicit TensorToDecodedFrameFilter(std::string name = "TensorToDecodedFrameFilter", ChannelOrder in_order = ChannelOrder::RGB)¶
-
class ThrottleFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <throttle.h>
Rate-limit payload frames by minimum inter-frame interval.
Forwards a payload frame (Packet, Decoded, Tensor) downstream only when at least
intervalmicroseconds have elapsed since the last forwarded payload frame, as measured by the frame’s absolute timestamp.Non-payload frames (Signal, Codec, Stream, SDP, RTP, Info, …) pass through unconditionally.
Payload frames with an invalid absolute timestamp pass through unconditionally.
The very first payload frame always passes through (no prior reference point).
Two orthogonal controls:
Rate-limiter (
setState/setInterval): drops frames that arrive too soon after the previous forwarded frame.Gate (
open/close): drops all payload frames when closed, regardless of timestamps or the rate-limiter state.
All control methods are mutex-protected and safe to call from any thread.
Public Functions
-
inline void setState(bool enabled)¶
Enable or disable the rate-limiter.
When enabled (default), payload frames are forwarded only when the inter-frame interval condition is met. When disabled, all payload frames pass through immediately with no timestamp check — equivalent to removing the filter from the chain. Non-payload frames are unaffected by this flag. Thread-safe.
-
inline bool getState() const¶
Return true if the rate-limiter is currently enabled. Thread-safe.
-
inline void setInterval(int interval_ms)¶
Change the minimum inter-frame interval.
Sets the minimum time (in milliseconds) that must elapse between two consecutively forwarded payload frames. Setting 0 ms passes every frame (since any delta ≥ 0), but still incurs the timestamp check overhead; prefer setState(false) for a true pass-through. Thread-safe; takes effect on the next go() call.
-
inline void close()¶
Close the gate — drop all payload frames until open() is called.
Acts independently of the rate-limiter (setState). When the gate is closed, no payload frames reach downstream regardless of timestamps or the enabled flag. Non-payload frames (Signal, Codec, Stream, Info, …) still pass through. Thread-safe.
-
inline void open()¶
Open the gate — resume forwarding payload frames.
Also resets the internal timestamp reference so the very next payload frame passes immediately (no waiting for the interval to elapse from the last frame before close() was called). Thread-safe.
-
inline bool isOpen() const¶
Return true if the gate is currently open. Thread-safe.
-
inline virtual void go(const Limef::frame::Frame *frame) override¶
Implementation of the framefilter action.
Uses
Limef::ff:FrameFilter::passto pass frames downstream.The framefilter ensures that the frame is not modified. If it needs a modified frame it has to take an internal copy of the frame first.
-
class WebMFrameFilter : public Limef::ff::ComposeFrameFilter¶
- #include <webm.h>
Composite filter that muxes a VP8/VP9/AV1 stream to WebM for browser MSE.
Creates the chain: CodecAssertFrameFilter → GateFrameFilter → MuxerFrameFilter(WebM) → WebMPartitionFrameFilter
Output: one RawFrame per MSE segment:
Init segment = EBML header + Segment header + Info + Tracks
Media segment = one WebM Cluster (contains video blocks, ~1 s each)
Intended downstream: WebSocketServerThread (same as FMP4FrameFilter).
-
class WebMPartitionFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <webmpart.h>
Repartitions a WebM/EBML byte stream into MSE-friendly segments.
Input: raw byte blobs from ffmpeg’s WebM muxer — arbitrary chunk sizes, not aligned to EBML element boundaries.
Output: one RawFrame per logical MSE segment:
Init segment = EBML header + Segment header + Info + Tracks (everything before the first Cluster element)
Media segment = one complete Cluster element
The WebM Cluster element is the MSE media-segment boundary, analogous to moof+mdat in fragmented MP4. The browser expects to receive the init segment first, then a stream of Clusters (each containing one or more video/audio blocks).
The parser walks the EBML tree at two depths:
DOC / SEGMENT level: 4-byte IDs (first byte 0x10–0x1F)
CLUSTER level: 1-byte IDs (first byte 0x80–0xFF)
Clusters from ffmpeg with custom IO have unknown size (streaming mode); the end of a Cluster is detected by the appearance of the next EBML element with a 4-byte ID (first byte 0x10–0x1F).
Assumption: Cluster children produced by ffmpeg’s webm muxer always carry known sizes (SimpleBlock, BlockGroup, Timecode). Unknown-size children are flagged as warnings and parsing stops until the next blob.
Public Functions
-
class WebRTCMuxerFrameFilter : public Limef::ff::ComposeFrameFilter¶
- #include <webrtcmuxer.h>
Composite filter that canonizes a stream for WebRTC delivery.
Chains: CodecAssertFrameFilter → RTPMuxerFrameFilter
Public Functions
-
inline explicit WebRTCMuxerFrameFilter(std::string name = "WebRTCMuxerFrameFilter", int mtu = 1200)¶
- Parameters:
name – label for logging
mtu – path MTU to the client in bytes (default 1200, matching WebRTCServerThread’s default). Nothing downstream fragments an oversized RTP/SRTP packet - libdatachannel’s own
mtuconfig only bounds its own SCTP/DTLS traffic, not media tracks - so the RTP muxer’s packet size must itself be kept at or belowmtu. Pass the same value given to WebRTCServerThread; lower both when routing over a VPN/tunnel such as Tailscale (MTU 1280) to avoid EMSGSIZE (“datagram is
too large”) errors.
-
inline explicit WebRTCMuxerFrameFilter(std::string name = "WebRTCMuxerFrameFilter", int mtu = 1200)¶
-
class WritePNGFrameFilter : public Limef::ff::SimpleFrameFilter¶
- #include <write_png.h>
Writes each decoded video frame to a PNG file in a directory.
Pass-through: every frame is forwarded downstream unchanged after being written to disk.
Filenames are
frame000001.png,frame000002.png, … (6-digit counter). The directory is created on construction.Only CPU-resident video frames are written. CUDA/GPU frames are passed through with a one-time warning — insert DecodedDownloadFrameFilter upstream to materialise GPU frames before reaching this filter.
The source pixel format is automatically converted to RGB24 via libswscale before PNG encoding, so any AVPixelFormat is accepted.
Public Functions
-
using json = nlohmann::json¶