avfilter_graph_create_filter()
/** * Create and add a filter instance into an existing graph. * The filter instance is created from the filter filt and inited * with the parameters args and opaque. * * In case of success put in *filt_ctx the pointer to the created * filter instance, otherwise set *filt_ctx to NULL. * * @param name the instance name to give to the created filter instance * @param graph_ctx the filter graph * @return a negative AVERROR error code in case of failure, a non * negative value otherwise */ int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx);avfilter_graph_parse_ptr()
/** * Add a graph described by a string to a graph. * * In the graph filters description, if the input label of the first * filter is not specified, "in" is assumed; if the output label of * the last filter is not specified, "out" is assumed. * * @param graph the filter graph where to link the parsed graph context * @param filters string to be parsed * @param inputs pointer to a linked list to the inputs of the graph, may be NULL. * If non-NULL, *inputs is updated to contain the list of open inputs * after the parsing, should be freed with avfilter_inout_free(). * @param outputs pointer to a linked list to the outputs of the graph, may be NULL. * If non-NULL, *outputs is updated to contain the list of open outputs * after the parsing, should be freed with avfilter_inout_free(). * @return non negative on success, a negative AVERROR code on error */ int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx);avfilter_graph_config()
/** * Check validity and configure all the links and formats in the graph. * * @param graphctx the filter graph * @param log_ctx context used for logging * @return >= 0 in case of success, a negative AVERROR code otherwise */ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx);av_buffersrc_add_frame_flags()
/** * Add a frame to the buffer source. * * By default, if the frame is reference-counted, this function will take * ownership of the reference(s) and reset the frame. This can be controlled * using the flags. * * If this function returns an error, the input frame is not touched. * * @param buffer_src pointer to a buffer source context * @param frame a frame, or NULL to mark EOF * @param flags a combination of AV_BUFFERSRC_FLAG_* * @return >= 0 in case of success, a negative AVERROR code * in case of failure */ av_warn_unused_result int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src, AVFrame *frame, int flags);av_buffersink_get_frame()
/** * Get a frame with filtered data from sink and put it in frame. * * @param ctx pointer to a context of a buffersink or abuffersink AVFilter. * @param frame pointer to an allocated frame that will be filled with data. * The data must be freed using av_frame_unref() / av_frame_free() * * @return * - >= 0 if a frame was successfully returned. * - AVERROR(EAGAIN) if no frames are available at this point; more * input frames must be added to the filtergraph to get more output. * - AVERROR_EOF if there will be no more output frames on this sink. * - A different negative AVERROR code in other failure cases. */ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame); 3. 滤镜API使用方法在代码中使用滤镜,主要分为两个步骤:
[1]. 滤镜的初始化配置:根据滤镜参数,配置生成滤镜图,此滤镜图供下一步骤使用
[2]. 使用滤镜处理原始音视频帧:向滤镜图提供输入帧(AVFrame),从滤镜图取出经处理后的输出帧(AVFrame)
本节节选的代码示例选自:
https://github.com/leichn/exercises/blob/master/source/ffmpeg/ffmpeg_vfilter/video_filter.c
在代码中,滤镜配置比滤镜使用复杂,滤镜配置代码如下:
// 功能:创建配置一个滤镜图,在后续滤镜处理中,可以往此滤镜图输入数据并从滤镜图获得输出数据 // filters_descr:输入参数,形如“transpose=cclock,pad=iw+80:ih:40” // @vfmt:输入参数,描述提供给待生成滤镜图的视频帧和格式 // @fctx:输出参数,返回生成滤镜图的信息,供调用者使用 int init_filters(const char *filters_descr, const input_vfmt_t *vfmt, filter_ctx_t *fctx) { int ret = 0; // 1. 配置滤镜图输入端和输出端 fctx->filter_graph = avfilter_graph_alloc(); if (!fctx->filter_graph) { ret = AVERROR(ENOMEM); goto end; } char args[512]; char *p_args = NULL; if (vfmt != NULL) { /* buffer video source: the decoded frames from the decoder will be inserted here. */ // args是buffersrc滤镜的参数 snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", vfmt->width, vfmt->height, vfmt->pix_fmt, vfmt->time_base.num, vfmt->time_base.den, vfmt->sar.num, vfmt->sar.den); p_args = args; } ret = avfilter_graph_create_filter(&fctx->bufsrc_ctx, bufsrc, "in", p_args, NULL, fctx->filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); goto end; } const AVFilter *bufsink = avfilter_get_by_name("buffersink"); ret = avfilter_graph_create_filter(&fctx->bufsink_ctx, bufsink, "out", NULL, NULL, fctx->filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); goto end; } #if 0 // 因为后面显示视频帧时有sws_scale()进行图像格式转换,故此处不设置滤镜输出格式也可 enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE }; // 设置输出像素格式为pix_fmts[]中指定的格式(如果要用SDL显示,则这些格式应是SDL支持格式) 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 end; } #endif // 1. end // 2. 将filters_descr描述的滤镜图添加到filter_graph滤镜图中 AVFilterInOut *outputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); outputs->filter_ctx = fctx->bufsrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; AVFilterInOut *inputs = avfilter_inout_alloc(); inputs->name = av_strdup("out"); inputs->filter_ctx = fctx->bufsink_ctx; inputs->pad_idx = 0; inputs->next = NULL; ret = avfilter_graph_parse_ptr(fctx->filter_graph, filters_descr, &inputs, &outputs, NULL); if (ret < 0) { goto end; } // 2. end // 3. 配置filtergraph滤镜图,建立滤镜间的连接 ret = avfilter_graph_config(fctx->filter_graph, NULL); if (ret < 0) { goto end; } // 3. end end: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; }函数参数说明: