I am looking for an example how to use the latest FFmpeg libavfilter functions to add a bitmap overlay image to a video. I only find more than ten years old examples which are based on an old versions of libavfilter.
What I am trying to do:
On Windows with latest libav (full build) an C++ app reads YUV420P frames from a frame grabber card. I want to draw a Windows bitmap BGR24 overlay image (from file) on every frame via libavfilter. First I convert the BGR24 overlay image via format filter to YUV420P. Then I feed the YUV420P frame from frame grabber and the YUV420P overlay into the overlay filter. Everything seems to be fine but when I try to get the frame out of the filter graph I always get an “Resource is temporary not available” (EAGAIN) error, independent on how many frames I put into the graph.
My current initialization code looks like below. It does not report any errors or warnings but when I try to get the filtered frame out of the graph via av_buffersink_get_frame
I always get an EAGAIN
return code.
Here is my current initialization code:
int init_overlay_filter(AVFilterGraph** graph, AVFilterContext** src_ctx, AVFilterContext** overlay_src_ctx,
AVFilterContext** sink_ctx)
{
AVFilterGraph* filter_graph;
AVFilterContext* buffersrc_ctx;
AVFilterContext* overlay_buffersrc_ctx;
AVFilterContext* buffersink_ctx;
AVFilterContext* overlay_ctx;
AVFilterContext* format_ctx;
const AVFilter *buffersrc, *buffersink, *overlay_buffersrc, *overlay_filter, *format_filter;
int ret;
// Create the filter graph
filter_graph = avfilter_graph_alloc();
if (!filter_graph)
{
fprintf(stderr, "Unable to create filter graph.n");
return AVERROR(ENOMEM);
}
// Create buffer source filter for main video
buffersrc = avfilter_get_by_name("buffer");
if (!buffersrc)
{
fprintf(stderr, "Unable to find buffer filter.n");
return AVERROR_FILTER_NOT_FOUND;
}
// Create buffer source filter for overlay image
overlay_buffersrc = avfilter_get_by_name("buffer");
if (!overlay_buffersrc)
{
fprintf(stderr, "Unable to find buffer filter.n");
return AVERROR_FILTER_NOT_FOUND;
}
// Create buffer sink filter
buffersink = avfilter_get_by_name("buffersink");
if (!buffersink)
{
fprintf(stderr, "Unable to find buffersink filter.n");
return AVERROR_FILTER_NOT_FOUND;
}
// Create overlay filter
overlay_filter = avfilter_get_by_name("overlay");
if (!overlay_filter)
{
fprintf(stderr, "Unable to find overlay filter.n");
return AVERROR_FILTER_NOT_FOUND;
}
// Create format filter
format_filter = avfilter_get_by_name("format");
if (!format_filter)
{
fprintf(stderr, "Unable to find format filter.n");
return AVERROR_FILTER_NOT_FOUND;
}
// Initialize the main video buffer source
char args[512];
snprintf(args, sizeof(args),
"video_size=1920x1080:pix_fmt=yuv420p:time_base=1/25:pixel_aspect=1/1");
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph);
if (ret < 0)
{
fprintf(stderr, "Unable to create buffer source filter for main video.n");
return ret;
}
// Initialize the overlay buffer source
snprintf(args, sizeof(args),
"video_size=165x165:pix_fmt=bgr24:time_base=1/25:pixel_aspect=1/1");
ret = avfilter_graph_create_filter(&overlay_buffersrc_ctx, overlay_buffersrc, "overlay_in", args, NULL,
filter_graph);
if (ret < 0)
{
fprintf(stderr, "Unable to create buffer source filter for overlay.n");
return ret;
}
// Initialize the format filter to convert overlay image to yuv420p
snprintf(args, sizeof(args), "pix_fmts=yuv420p");
ret = avfilter_graph_create_filter(&format_ctx, format_filter, "format", args, NULL, filter_graph);
if (ret < 0)
{
fprintf(stderr, "Unable to create format filter.n");
return ret;
}
// Initialize the buffer sink
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph);
if (ret < 0)
{
fprintf(stderr, "Unable to create buffer sink filter.n");
return ret;
}
// Initialize the overlay filter
ret = avfilter_graph_create_filter(&overlay_ctx, overlay_filter, "overlay", "W-w:H-h:enable='between(t,0,20)':format=yuv420", NULL, filter_graph);
if (ret < 0)
{
fprintf(stderr, "Unable to create overlay filter.n");
return ret;
}
// Connect the filters
ret = avfilter_link(overlay_buffersrc_ctx, 0, format_ctx, 0);
if (ret >= 0)
{
ret = avfilter_link(buffersrc_ctx, 0, overlay_ctx, 0);
}
else
{
fprintf(stderr, "Unable to configure filter graph.n");
return ret;
}
if (ret >= 0)
{
ret = avfilter_link(format_ctx, 0, overlay_ctx, 1);
}
else
{
fprintf(stderr, "Unable to configure filter graph.n");
return ret;
}
if (ret >= 0)
{
if ((ret = avfilter_link(overlay_ctx, 0, buffersink_ctx, 0)) < 0)
{
fprintf(stderr, "Unable to link filter graph.n");
return ret;
}
}
else
{
fprintf(stderr, "Unable to configure filter graph.n");
return ret;
}
// Configure the filter graph
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
{
fprintf(stderr, "Unable to configure filter graph.n");
return ret;
}
*graph = filter_graph;
*src_ctx = buffersrc_ctx;
*overlay_src_ctx = overlay_buffersrc_ctx;
*sink_ctx = buffersink_ctx;
return 0;
}