1.前言
使用ffmpeg添加和去除水印是常见的功能,两者的参数都跟在-vf选项后,本文主要介绍水印去除功能。
2.水印去除功能简介
常见的ffmpeg水印去除功能的命令行如下
ffmpeg -i xxx.mp4 -vf "delogo=x=1:y=1:w=800:h=100" -c:a copy delogo.mp4意思是从左上角开始去除水印,水印的范围是长度为800,宽度为100的矩形。一个720P(1280x720)的视频,去除水印的效果如下

但是这样将水印坐标固定的写法会导致一些问题,比如当视频的分辨率更低时,很容易出现去除水印区域的长度非法的问题。
比如我们调整去除水印区域的长度超过视频画面的长度,比如1800对于1080P(1920x1080)的视频是合法的,但是对于720P(1280x720)的视频,就不合法了。
ffmpeg -i xxx.mp4 -vf "delogo=x=1:y=1:w=1800:h=100" -c:a copy delogo.mp4
所以我们很自然的会想到参考添加水印时采用的方式,使用相对长度和位置,以保证不会使水印去除区域过大。添加水印时,视频画面的长度记为W,视频画面的宽度为H,如下所示
ffmpeg -i xxx.mp4 -vf "drawtext=text='asdf':fontcolor=white:fontfile=jdsongti.ttf:fontsize=48:x=72:y=H-th-72" -c:a copy logo.mp4但是如果我们直接套用到去除水印的功能里的话,就会出错
ffmpeg -i xxx.mp4 -vf "delogo=x=1:y=1:w=W/2:h=H/10" -c:a copy delogo.mp4
那么,这个问题应该如何解决呢?如果要修改ffmpeg,应该如何修改呢?
3.修改ffmpeg代码
由于添加水印的部分已经具备了相对长度,所以我们可以参考水印添加的代码,位于
libavfilter/vf_drawtext.c,而我们需要修改的代码位于libavfilter/vf_delogo.c,改动如下:首先增加变量名称
main_h和main_w来匹配ffmpeg命令行参数中的字符(如x=main_h/2)
static const char * const var_names[] = { "main_h", ///< height of the input video "main_w", ///< width of the input video "x", "y", "w", "h", "n", ///< number of frame "t", ///< timestamp expressed in seconds NULL};其次添加变量
VAR_MAIN_H和VAR_MAIN_W来记录视频的高和宽
enum var_name { VAR_MAIN_H, VAR_MAIN_W, VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_T, VAR_VARS_NB};最后在
config_input处理每一帧时,计算出水印去除区域的坐标。config_input保存了视频的长和宽,并解析表达式(如x=main_h/2),得到计算后的值。
static int config_input(AVFilterLink *inlink){ DelogoContext *s = inlink->dst->priv; s->var_values[VAR_MAIN_W] = inlink->w; s->var_values[VAR_MAIN_H] = inlink->h; s->x = av_expr_eval(s->x_pexpr, s->var_values, s); s->y = av_expr_eval(s->y_pexpr, s->var_values, s); s->w = av_expr_eval(s->w_pexpr, s->var_values, s); s->h = av_expr_eval(s->h_pexpr, s->var_values, s);// printf("s->x:%d s->y:%d s->w:%d s->h:%d s->band:%d \n", s->x, s->y, s->w, s->y, s->band); /* Check whether the logo area fits in the frame */ if (s->x + (s->band - 1) < 0 || s->x + s->w - (s->band*2 - 2) > inlink->w || s->y + (s->band - 1) < 0 || s->y + s->h - (s->band*2 - 2) > inlink->h) { av_log(s, AV_LOG_ERROR, "Logo area is outside of the frame.\n"); return AVERROR(EINVAL); } return 0;}4.效果
重新编译修改后的ffmpeg,新生成的ffmpeg可以使用以下参数进行水印去除。并且随着视频分辨率的变化,去除水印的位置也会相对发生变化,做到了自适应。
ffmpeg -i xxx.mp4 -vf "delogo=x=1:y=1:w=main_w/2:h=main_h/10" -c:a copy delogo.mp4
可以看到水印去除的区域,就位于整个视频画面长度的一半。
5.总结
ffmpeg源码里有很多值得学习的地方,新功能可以基于已有的功能进行移植和裁剪来实现。