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