Build FFmpeg Filtergraph with avfilter_graph_parse_ptr
This guide demonstrates how to programmatically construct an
audio/video processing pipeline using the
avfilter_graph_parse_ptr function from the FFmpeg C API
(libavfilter). You will learn the role of
AVFilterInOut linked lists, how to bridge raw frame
producers and consumers using buffer and
buffersink filters, and the precise sequence of API calls
needed to parse complex filter strings, configure the graph, and manage
memory safely.
Understanding
avfilter_graph_parse_ptr
The function avfilter_graph_parse_ptr allows you to
define complex filtering pipelines via a standard FFmpeg filtergraph
string (e.g., "scale=1280:720,fps=30") while explicitly
mapping the graph's open inputs and outputs to programmatic filters
using linked lists of AVFilterInOut structures.
The signature is:
int avfilter_graph_parse_ptr(AVFilterGraph *graph,
const char *filters,
AVFilterInOut **inputs,
AVFilterInOut **outputs,
void *log_ctx);inputs: Refers to where the filter string takes its input. These correspond to the output pads of your input filters (e.g.,buffer).outputs: Refers to where the filter string sends its output. These correspond to the input pads of your output filters (e.g.,buffersink).
Step-by-Step Implementation
- Allocate the Graph: Create an empty
AVFilterGraph. - Create Endpoint Filters: Instantiate and initialize
the
buffer(source) andbuffersink(destination) filter contexts. - Configure
AVFilterInOutChains: Set up labels mapping to thebufferandbuffersinkfilters. - Parse the Pipeline: Call
avfilter_graph_parse_ptr. - Validate and Finalize: Execute
avfilter_graph_config. - Free Temporary Resources: Free the
AVFilterInOutstructures.
Complete Code Example
The following example builds a video scaling pipeline converting frames to \(1280 \times 720\):
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <stdio.h>
int init_filtergraph(AVFilterGraph **graph_out,
AVFilterContext **src_ctx_out,
AVFilterContext **sink_ctx_out)
{
int ret = 0;
AVFilterGraph *graph = avfilter_graph_alloc();
if (!graph) return AVERROR(ENOMEM);
const AVFilter *buffer_src = avfilter_get_by_name("buffer");
const AVFilter *buffer_sink = avfilter_get_by_name("buffersink");
AVFilterContext *src_ctx = NULL;
AVFilterContext *sink_ctx = NULL;
AVFilterInOut *inputs = avfilter_inout_alloc();
AVFilterInOut *outputs = avfilter_inout_alloc();
if (!inputs || !outputs) {
ret = AVERROR(ENOMEM);
goto cleanup;
}
// 1. Configure source parameters (e.g., 1920x1080 YUV420P)
char args[512];
snprintf(args, sizeof(args),
"video_size=1920x1080:pix_fmt=%d:time_base=1/25:pixel_aspect=1/1",
AV_PIX_FMT_YUV420P);
ret = avfilter_graph_create_filter(&src_ctx, buffer_src, "in",
args, NULL, graph);
if (ret < 0) goto cleanup;
// 2. Configure sink filter
ret = avfilter_graph_create_filter(&sink_ctx, buffer_sink, "out",
NULL, NULL, graph);
if (ret < 0) goto cleanup;
// 3. Set accepted pixel formats for sink
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
ret = av_opt_set_int_list(sink_ctx, "pix_fmts", pix_fmts,
AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
if (ret < 0) goto cleanup;
// 4. Map the inputs and outputs
// The filter string's input connects to src_ctx's output
outputs->name = av_strdup("in");
outputs->filter_ctx = src_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
// The filter string's output connects to sink_ctx's input
inputs->name = av_strdup("out");
inputs->filter_ctx = sink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
// 5. Parse the filter string
const char *filter_desc = "scale=1280:720";
ret = avfilter_graph_parse_ptr(graph, filter_desc, &inputs, &outputs, NULL);
if (ret < 0) goto cleanup;
// 6. Finalize graph configuration
ret = avfilter_graph_config(graph, NULL);
if (ret < 0) goto cleanup;
*graph_out = graph;
*src_ctx_out = src_ctx;
*sink_ctx_out = sink_ctx;
cleanup:
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
if (ret < 0 && graph) {
avfilter_graph_free(&graph);
}
return ret;
}Key Considerations
- Naming Direction: In the
AVFilterInOutmapping, the pointer labeledoutputsconnects the graph's origin (src_ctx) to the string's entry point, whereasinputsconnects the string's termination point to the graph's destination (sink_ctx). - Memory Management:
avfilter_graph_parse_ptrcan modify theinputsandoutputslists during parsing. Always pass their addresses and callavfilter_inout_freeafterwards to prevent leaks. - Frame Exchange: Once
avfilter_graph_configreturns0, push raw frames into the graph viaav_buffersrc_add_frame_flags(src_ctx, frame, flags)and pull processed frames viaav_buffersink_get_frame(sink_ctx, frame).