Feed Frames to FFmpeg Filtergraph Using Buffer Source
In the FFmpeg C API, feeding raw decoded audio or video data into a
filtergraph requires using the buffer (for video) or
abuffer (for audio) source filter. This article provides a
direct guide on initializing these buffer sources, passing
AVFrame instances into the filter pipeline using
av_buffersrc_add_frame_flags(), flushing the graph at
stream termination, and pulling the filtered output from the sink.
1. Filtergraph Architecture
An FFmpeg filtergraph requires an entry point and an exit point:
- Source:
buffer(video) orabuffer(audio) receivesAVFrameobjects from your application. - Sink:
buffersink(video) orabuffersink(audio) outputs processedAVFrameobjects.
[ Your App: AVFrame ]
│
▼
[ buffer / abuffer ] ──► [ Filter Chain ] ──► [ buffersink / abuffersink ]
│
▼
[ Filtered AVFrame ]
2. Initializing the Buffer Source
The buffer source must be initialized with parameters matching the input frames (such as dimensions, pixel format, time base, or audio sample rate).
Video (buffer)
Configuration
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
#include <libavutil/opt.h>
AVFilterGraph *filter_graph = avfilter_graph_alloc();
const AVFilter *buffersrc = avfilter_get_by_name("buffer");
const AVFilter *buffersink = avfilter_get_by_name("buffersink");
AVFilterContext *buffersrc_ctx;
AVFilterContext *buffersink_ctx;
char args[512];
snprintf(args, sizeof(args),
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
width, height, pix_fmt,
time_base_num, time_base_den,
aspect_num, aspect_den);
int ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
args, NULL, filter_graph);
if (ret < 0) {
// Handle error
}Audio (abuffer)
Configuration
const AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
AVFilterContext *abuffersrc_ctx;
char ch_layout_str[64];
av_channel_layout_describe(&channel_layout, ch_layout_str, sizeof(ch_layout_str));
char args[512];
snprintf(args, sizeof(args),
"sample_rate=%d:sample_fmt=%s:channel_layout=%s:time_base=%d/%d",
sample_rate, av_get_sample_fmt_name(sample_fmt),
ch_layout_str, time_base_num, time_base_den);
ret = avfilter_graph_create_filter(&abuffersrc_ctx, abuffersrc, "in",
args, NULL, filter_graph);3. Linking the Graph and Finalizing
Create your sink filter, connect your inputs to outputs (either
directly or via a filter string parsed by
avfilter_graph_parse_ptr()), and configure the graph.
// Create sink
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
NULL, NULL, filter_graph);
// Link source directly to sink (or place intermediate filters in between)
ret = avfilter_link(buffersrc_ctx, 0, buffersink_ctx, 0);
// Validate and configure the graph
ret = avfilter_graph_config(filter_graph, NULL);4. Pushing Frames into the Buffer Source
To feed frames into the initialized filtergraph, call
av_buffersrc_add_frame_flags().
// Push a decoded frame into the filtergraph
int ret = av_buffersrc_add_frame_flags(buffersrc_ctx, input_frame, AV_BUFFERSRC_FLAG_KEEP_REF);
if (ret < 0) {
// Handle buffer source feed error
}AV_BUFFERSRC_FLAG_KEEP_REF: Keeps the reference toinput_frameintact in your code by taking a new reference internally. If omitted, the filtergraph takes ownership ofinput_frameand unreferences it.Flushing: When the input stream ends, send
NULLas the frame pointer to signal End Of File (EOF):av_buffersrc_add_frame_flags(buffersrc_ctx, NULL, 0);
5. Pulling Processed Frames from the Sink
After feeding a frame, retrieve all available filtered frames in a
loop until AVERROR(EAGAIN) or AVERROR_EOF is
returned:
AVFrame *filtered_frame = av_frame_alloc();
while (1) {
int ret = av_buffersink_get_frame(buffersink_ctx, filtered_frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break; // Need more input frames or EOF reached
}
if (ret < 0) {
// Handle filter processing error
break;
}
// Process the filtered frame (e.g., encode or display)
av_frame_unref(filtered_frame);
}
av_frame_free(&filtered_frame);6. Cleanup
Free the entire graph and its associated filter contexts when processing is complete:
avfilter_graph_free(&filter_graph);