ffmpeg 添加视频加文字水印--drawtext 滤镜详解

使用ffmpeg 命令行给视频添加文字水印,利用drawtext滤镜,如果是代码上api调用,也是一样的用法,创建好滤镜图, 在滤镜图描述字符串中,把这里命令行的参数拷贝过去替换就行,改动非常方便。
给视频添加文字,简单地添加一个helloworld 很方便,在《FFMPEG 从入门到精通》-刘歧 书第6.2章 有讲解,不过讲的非常浅显,不解其中参数的意义,总是期望哪里有一份官方说明使用手册来告诉我们这些参数的意义,遗憾并没有找到,这本书虽然是ffmpeg官网推荐的却也非常浅显,基本没有涉及源码,索性从源码里去寻找答案,这才是最完整的第一手资料。这里结合源代码,来分析分析这个滤镜用法。 源码vf_drawtext.c


添加文字我们关心的几个问题
1.0 文字内容。 固定的内容最简单,能否每一帧都添加不同的内容?能否添加程序自动计算出来的一些信息?
2.0 文字位置。固定位置也最简单,能否每一帧都添加在不同的位置?用一个公式去动态自己确定位置?
3.0 字体,颜色,背景色,逐渐变换的颜色。
一条典型的命令
叠加上每一帧的序号,解码成 raw yuv420p格式

ffmpeg -i native.mp4 -t 10 -vf "drawtext=fontsize=100:x=n*5:y=100:fontcolor=red:box=1:text='%{n}'" -pix_fmt yuv420p 1280x720_yuv420p_test.yuv

# -t 10    取前10s ,默认开始时间是0,也可以用参数:-ss 00:00:00 指定时间点
# -vf ""  这里就开始指定滤镜
#fontsize=100 字体大小 还有fontfile='xx'  指定使用的字体文件,我这里wind上执行的使用的系统缺省字体
#x=n*5  y=100   可以直接写固定数值,这里写了个表达式,n*5  n指的是帧序号,所以x坐标是在变化的。
#fontcolor=red   颜色, freetype字库接口支持的
#box=1   box是指字体背景“盒子”, 默认的话是背景透明的,即box=0 . 现在box=1是绘制背景的,box默认颜色白色,也可以通过 boxcolor 修改 
#text='%{n}'  这个就有意思了,原本可以直接通过text='hello world' 设置固定的文字,这里是以%{xx}格式,表示扩展功能,当前用的这个扩展功能会将文字设置为每一帧的序号。
#文字还可以从文件加载,通过设置textfile=test_file  设置文件。

 上面的输出如下,添加的文字信息是每一帧自己的序号 ,从0开始, 坐标因为设置了 x=n*5,也是和帧序号相关。



 

一:查看help信息

 ffmpeg 命令行查看某一个滤镜的参数:
#ffmpeg --help filter=drawtext

 这些help信息,都是直接在源码中可以查看到的,在源码vf_drawtext.c 的 AVOption结构体中,上面的输出就是从该结构体中取出的字符串,每一个滤镜都有这么一个选项结构体

二:文字内容的几种来源


     1.0 固定输入: 选项 -text='hello world'
      2.0 从文件导入  -textfile='xxx'
      3.0 %{xx} 扩展功能  文字内容从这个扩展函数里面生成
           3.1  每一帧的pts 时间戳信息
                  text='%{pts}'
           3.2  当前系统 时间 
                   text='%{localtime}'
                   text='%{gmtime}'  //gmtime和localtime的区别,就不啰嗦了
            3.3 每一帧的序号
                   text='%{frame_num}'  或者简写成 text='%{n}'
            3.4 添加mete 媒体信息
                  text='%{metadata\:width}'       这个功能必须携带一个参数,不给参数会报警,这里给的是width,源数据用的mp4,结果发现根本就么有mete信息. 
在源码中://下面printf个人添加的,因为使用mp4文件的时候怎么添加mete都没有,结果发现这里 av_dict_count() 为0, 根本没有添加过meta信息,  这个dict, 词典, 存储着键值对信息。。实验失败,没啥用

static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
                         char *fct, unsigned argc, char **argv, int tag)
{

    DrawTextContext *s = ctx->priv;
    AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
   //下面printf个人添加的,因为使用mp4文件的时候怎么添加mete都没有,结果发现这里 av_dict_count() 为0, 根本没有添加过meta信息,  这个dict, 词典, 存储着键值对信息。
    printf("[%s%d]argv[0] :%s metacount:%d  \n",__FUNCTION__,__LINE__,argv[0],av_dict_count(s->metadata));

    if (e && e->value)
        av_bprintf(bp, "%s", e->value);
    else if (argc >= 2)
        av_bprintf(bp, "%s", argv[1]);
    return 0;
}

       3.5 显示帧类型
               text='%{pict_type}'
              如下图,drawtext了两次同时加上序号和帧类型。

 要注意,这里的帧类型,P帧,I帧,B帧, 指的是解码前 h264数据的类型,如果在命令操作的时候保存的是再编码的数据,再编码出来的数据可就和这里的帧类型无关了,滤镜都是在解码后,重编码前作的对raw数据做的像素级别的操作。
所以用命令行:
#ffmpeg -i native.mp4 -t 10 -vf "drawtext=fontsize=100:x=0:y=0:fontcolor=red:box=1:text='%{pict_type}'" -vcodec libx264 -bf 0 test_pict_type.h264 输出的重编码的  test_pict_type.h264 画面显示的 log 帧类型,是指 输入文件native.mp4 的帧类型,重编码后的 test_pict_type.h264 帧类型是不一样的。

         3.6 扩展表达式。
              { "expr_int_format", 2, 3, 0, func_eval_expr_int_format },
             { "eif",       2, 3, 0,   func_eval_expr_int_format },
            这个就比较厉害了,ffmpeg命令行的参数都支持 表达式类型,比如条件判断,啥都都行,比较复杂,这里就不在此深究了。
源码中可以看到支持的扩展函数功能:

需要以%{} 格式输入:
源码中相关的函数

static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
{
    int ret;

    av_bprint_clear(bp);
    while (*text) {
        if (*text == '\\' && text[1]) {
            av_bprint_chars(bp, text[1], 1);
            text += 2;
        } else if (*text == '%') {
            text++;
            if ((ret = expand_function(ctx, bp, &text)) < 0)
                return ret;
        } else {
            av_bprint_chars(bp, *text, 1);
            text++;
        }
    }
    if (!av_bprint_is_complete(bp))
        return AVERROR(ENOMEM);
    return 0;
}

三:坐标的控制

可以支持表达式扩展 ffmpeg命令行的参数都支持 表达式类型,比如条件判断,啥都都行,比较复杂,这里就不在此深究了。

四:使能,显示时机的控制。

      enable=xxx 
      这个参数并不是本滤镜所特有的,是滤镜控制的一个公共的参数,上面 help信息中就有说明:
This filter has support for timeline through the 'enable' option.
同样这个参数可以支持表达式形式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值