实现对取到的摄像头帧加时间水印数据,随系统时间变化。ffmpeg编译时必须加上./configure --enable-libfreetype,否则会提示找不到filter.
//frame_in:需要加水印的输入帧
//frame_out:完成加水印后取到的帧,执行完函数并完成相关逻辑后需要av_frame_unref(frame_out);
int waterMark(AVFrame *frame_in,AVFrame *frame_out){
AVFilterContext *buffersink_ctx = NULL;
AVFilterContext *buffersrc_ctx = NULL;
AVFilterGraph *filter_graph = NULL; //最关键的过滤器结构体
AVFilterContext* filter_ctx;//上下文
AVFilterInOut *outputs ;
AVFilterInOut *inputs;
AVBufferSinkParams *buffersink_params;
/*********************************************初始化结构体****************************************/
int ret;
const AVFilter *buffersrc = avfilter_get_by_name("buffer"); //输入,原始数据输入处
const AVFilter *buffersink = avfilter_get_by_name("buffersink"); //输出,处理后的数据输出
outputs = avfilter_inout_alloc();
inputs = avfilter_inout_alloc();
filter_graph = avfilter_graph_alloc();
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE }; //摄像头的像素格式
char args[256];
snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1280, 720, AV_PIX_FMT_YUVJ420P,1, 30, 1, 1); //输入过滤器参数配置:1280*720 j420p 帧率30
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph); //初始化并创建输入过滤器参数,通过参数指向具体的过滤器
if (ret < 0)
{
return -1;
}
buffersink_params = av_buffersink_params_alloc();
buffersink_params->pixel_fmts = pix_fmts; //设置输出的像素格式
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",NULL, buffersink_params, filter_graph); //创建输出过滤器
av_free(buffersink_params);
if (ret < 0)
{
return -2;
}
//参考和总结其他人的参数配置,实现水印格式添加
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
//将一串通过字符串描述的Graph添加到FilterGraph中
char filter_descr[128];
memset(filter_descr,0,sizeof(filter_descr));
sprintf(filter_descr,"drawtext=fontfile =verdanaz.ttf:x =w-tw:fontcolor=white:fontsize=20:text="":x=5:y=5");
if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_descr,&inputs, &outputs, NULL)) < 0)
return ret;
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
return ret;
int parsed_drawtext_0_index = -1;
for (int i = 0; i < filter_graph->nb_filters; i++)
{
AVFilterContext* filter_ctxn = filter_graph->filters[i];
fprintf(stdout, "[%s](%d) filter_ctxn->name=%s\n",__func__,__LINE__,filter_ctxn->name);
if(!strcmp(filter_ctxn->name,"Parsed_drawtext_0"))
parsed_drawtext_0_index = i;
}
if(parsed_drawtext_0_index == -1)
fprintf(stderr, "[%s](%d) no Parsed_drawtext_0\n",__func__,__LINE__);
filter_ctx = filter_graph->filters[parsed_drawtext_0_index];
/*****************************************************初始化完成*********************************************/
/**************************************************给图像添加水印*********************************************/
char sys_time[64];
time_t ltime;
time(<ime);
struct tm* today = localtime(<ime);
strftime(sys_time, sizeof(sys_time), "%Y-%m-%d %a %H:%M:%S", today); //24小时制
av_opt_set(filter_ctx->priv, "text", sys_time, 0 ); //设置text到过滤器
// 往源滤波器buffer中输入待处理的数据
if (av_buffersrc_add_frame(buffersrc_ctx, frame_in) < 0)
{
return -3;
}
// 从目的滤波器buffersink中输出处理完的数据
ret = av_buffersink_get_frame(buffersink_ctx, frame_out);
if (ret < 0)
return ret;
avfilter_inout_free(&outputs);
avfilter_inout_free(&inputs);
avfilter_graph_free(&filter_graph);
return 0;
}
效果如图:
接下来会对处理后的水印图片做格式转换,AV_PIX_FMT_YUVJ420P转AV_PIX_FMT_NV12。