How to Use avfilter_graph_parse_ptr in FFmpeg
This article demonstrates how to programmatically construct and
configure an FFmpeg filtergraph using the
avfilter_graph_parse_ptr function in C. You will learn how
to initialize the filtergraph, set up the input (source) and output
(sink) filters, map them using AVFilterInOut structures,
parse a custom filter string, and finalize the graph configuration.
Overview of the Implementation Process
To use avfilter_graph_parse_ptr, you must establish a
bridge between your application’s data source/destination and the filter
chain described by your filter string (e.g.,
"scale=1280:720,unsharp"). This is achieved by: 1.
Allocating an AVFilterGraph. 2. Creating a source filter
(abuffer or buffer) and a sink filter
(abuffersink or buffersink). 3. Configuring
AVFilterInOut pointers to map the open inputs and outputs
of your parsed filter string to your source and sink filters. 4. Calling
avfilter_graph_parse_ptr to parse the string and link the
filters. 5. Configuring the graph with
avfilter_graph_config.
Step-by-Step Code Example
Below is a complete, straight-to-the-point C implementation
demonstrating how to build a video filtergraph using
avfilter_graph_parse_ptr.
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
int build_filter_graph(const char *filter_descr, AVCodecContext *dec_ctx,
AVFilterGraph **out_graph, AVFilterContext **out_src, AVFilterContext **out_sink) {
int ret = 0;
AVFilterGraph *graph = avfilter_graph_alloc();
if (!graph) {
return AVERROR(ENOMEM);
}
// 1. Create the buffer source filter (input to the graph)
const AVFilter *buffersrc = avfilter_get_by_name("buffer");
AVFilterContext *buffersrc_ctx = NULL;
char args[512];
snprintf(args, sizeof(args),
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
dec_ctx->time_base.num, dec_ctx->time_base.den,
dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
args, NULL, graph);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
goto fail;
}
// 2. Create the buffer sink filter (output from the graph)
const AVFilter *buffersink = avfilter_get_by_name("buffersink");
AVFilterContext *buffersink_ctx = NULL;
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
NULL, NULL, graph);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
goto fail;
}
// Set output pixel formats for the sink
enum AVPixelFormat pix_fmts[] = { dec_ctx->pix_fmt, AV_PIX_FMT_NONE };
ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
goto fail;
}
// 3. Configure the inputs and outputs for avfilter_graph_parse_ptr.
// "outputs" represents the outputs of our source context (feeding into the filtergraph input).
AVFilterInOut *outputs = avfilter_inout_alloc();
// "inputs" represents the inputs of our sink context (fed by the filtergraph output).
AVFilterInOut *inputs = avfilter_inout_alloc();
if (!outputs || !inputs) {
ret = AVERROR(ENOMEM);
avfilter_inout_free(&outputs);
avfilter_inout_free(&inputs);
goto fail;
}
// Link the source output to the parsed graph's input named "in"
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
// Link the sink input to the parsed graph's output named "out"
inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
// 4. Parse the filter string.
// This function takes ownership of the inputs and outputs lists and frees them.
ret = avfilter_graph_parse_ptr(graph, filter_descr, &inputs, &outputs, NULL);
if (ret < 0) {
goto fail;
}
// 5. Finalize and validate the graph configuration
ret = avfilter_graph_config(graph, NULL);
if (ret < 0) {
goto fail;
}
*out_graph = graph;
*out_src = buffersrc_ctx;
*out_sink = buffersink_ctx;
return 0;
fail:
avfilter_graph_free(&graph);
return ret;
}Key Considerations
- Ownership of AVFilterInOut: The
avfilter_graph_parse_ptrfunction automatically deallocates and frees theAVFilterInOutlists passed to it on both success and failure. You do not need to manually callavfilter_inout_freeforinputsandoutputsifavfilter_graph_parse_ptris called. - Input and Output Naming Conventions: The names
assigned to
outputs->nameandinputs->name(e.g.,"in"and"out") must correspond to the open pads in your filter string. If your filter string contains custom pads, like[in] scale [scaled]; [scaled] hflip [out], the strings must match those bracketed labels. - Thread Safety: Ensure you initialize the graph
using
avfilter_graph_configonly after parsing is completely finished and all filters are linked.