官方文档

https://ffmpeg.org/ffmpeg-filters.html#drawtext-1
在这里插入图片描述

参考strftime() 方法相关参数;https://www.runoob.com/python/att-time-strftime.html
在这里插入图片描述

drawtext过滤器
本质是:使用libfreetype库从视频顶部的指定文件中绘制文本字符串或文本。
使用前提:要启用此过滤器的那么在编译ffmpeg的时候需要使用——enable-libfreetype配置FFmpeg。
如果要启用默认字体回退和字体选项,那您需要使用——enable-libfontconfig配置FFmpeg。
如果要启用text_shaping选项,需要使用——enable-libfribidi配置FFmpeg。
参数
box
用背景色在文本周围画一个方框。取值为1(启用)或0(禁用)。box的默认值为0。
boxborderw
使用框色设置框周围边框的宽度。boxborderw的默认值是0。
boxcolor
用于在文本周围绘制框的颜色。boxcolor默认值为“white”。
line_spacing
使用“方框”设置要在方框周围绘制的边框的像素线间距。line_spacing的默认值是0。
borderw
使用边框颜色设置要围绕文本绘制的边框的宽度。borderw的默认值为0。
bordercolor
设置用于在文本周围绘制边框的颜色。bordercolor的默认值为“black”。
expansion
选择文本的展开方式。可以是none、strftime(已弃用)或normal(默认)。详细信息请参阅下面的文本扩展部分。
basetime
设置计数的开始时间。取值单位为微秒。仅适用于已弃用的strftime扩展模式。要在普通扩展模式下进行模拟,使用pts函数,提供开始时间(以秒为单位)作为第二个参数。
fix_bounds
如果为真,检查并修复文本协调以避免剪切。
fontcolor
用于绘制字体的颜色。fontcolor 的默认值为“black”。
fontcolor_expr
字符串,以与文本相同的方式展开,以获得动态fontcolor值。默认情况下,该选项的值为空,不进行处理。当设置此选项时,它将覆盖fontcolor选项。
font
用于绘制文本的字体系列。在默认情况下没有。如STSONG.TTF字体类型,可以从 C:\Windows\Fonts 拷贝一个有效的字体文件
fontfile
用于绘制文本的字体文件。必须包括路径。当fontconfig支持被禁用时,此参数为必选参数。
alpha
绘制文本应用alpha混合。这个值可以是一个介于0.0和1.0之间的数字。表达式也接受相同的变量x, y。默认值为1。请参阅fontcolor_expr。
fontsize
用于绘制文本的字体大小。fontsize 默认值为16。
text_shaping
如果设置为1,则在绘制文本之前尝试对其进行整形(例如,颠倒文本从右到左的顺序并连接阿拉伯字符)。否则,就完全按照给定的方式绘制文本。默认为1(如果支持)。
ft_load_flags
用于加载字体的标志。flags映射了libfreetype支持的相应标志,并且是以下值的组合:默认值为“Default”。
default
no_scale
no_hinting
render
no_bitmap
vertical_layout
force_autohint
crop_bitmap
pedantic
ignore_global_advance_width
no_recurse
ignore_transform
monochrome
linear_design
no_autohint
shadowcolor
用于在绘制的文本后面绘制阴影的颜色。对于此选项的语法,请检查(ffmpeg-utils)ffmpeg-utils手册中的“颜色”部分。shadowcolor的默认值是“black”。
shadowx、shadowy
文本阴影位置相对于文本位置的x和y偏移量。它们可以是正的,也可以是负的。两者的默认值都是“0”。
start_number
n/frame_num变量的起始帧号。默认值为“0”。
tabsize
用于呈现选项卡的空格数的大小。默认值为4。
timecode
设置初始时间码表示格式为“hh:mm:ss[:;”。ff”格式。它可以带或不带文本参数使用。timeecode_rate选项必须指定。
timecode_rate, rate, r
设置时间码帧速率(仅限时间码)。值将四舍五入为最接近的整数。最小值为1。支持帧速率为30和60的拖帧时间码。
tc24hmax
如果设置为1,时间码选项的输出将环绕24小时。默认为0(禁用)。
text
要绘制的文本字符串。文本必须是UTF-8编码字符序列。如果没有指定textfile参数,则此参数为必选项。
textfile
包含要绘制的文本的文本文件。文本必须是UTF-8编码字符序列。如果没有指定文本字符串,则此参数为必选参数。如果同时指定了text和textfile,则抛出错误。
text_source
如果要在侧数据的检测框中使用文本数据,则文本源应该设置为side_data_detection_bboxes。
如果设置了text source, text和textfile将被忽略,在侧数据的检测框中仍然使用文本数据。因此,如果您不确定文本源,请不要使用此参数。
reload
如果设置为1,文本文件将在每一帧之前重新加载。一定要原子地更新它,否则它可能被部分读取,甚至失败。
x、y
指定在视频帧内绘制文本的偏移量的表达式。它们相对于输出图像的上/左边界。x和y的默认值为“0”。

文本扩展
如果将expansion设置为strftime,则过滤器将识别提供文本中的strftime()序列,并相应地展开它们。就是%s,%y这些格式。
如果expand设置为none,则会逐字打印文本。
如果“expansion”设置为“normal”(默认),则使用如下扩展机制。
反斜杠字符’ \ ‘后面跟着任何字符,总是扩展到第二个字符。
形式为%{…}是扩大。大括号之间的文本是一个函数名,后面可能跟以’:‘分隔的参数。如果参数包含特殊字符或分隔符(’:‘或’}’),则应转义。
注意,它们可能还必须转义为filter参数字符串中的text选项的值和filter图描述中的filter参数,也可能是shell的转义,这构成了四层转义;使用文本文件可以避免这些问题。
系统提供以下功能:
expr, e 表达式的计算结果。
它必须接受一个参数来指定要计算的表达式,该参数接受与x和y值相同的常量和函数。注意,不是所有的常量都应该被使用,例如,当计算表达式时,文本大小是未知的,所以常量text_w和text_h将有一个未定义的值。
expr_int_format, eif计算表达式的值并将其输出为格式化的整数。
它必须接受一个参数来指定要计算的表达式,该参数接受与x和y值相同的常量和函数。注意,不是所有的常量都应该被使用,例如,当计算表达式时,文本大小是未知的,所以常量text_w和text_h将有一个未定义的值。第一个参数是要计算的表达式,就像expr函数一样。第二个参数指定输出格式。允许的值是’ x ', ’ x ', ’ d ‘和’ u '。它们与printf函数中的处理方法完全相同。第三个参数是可选的,用于设置输出的位置数。它可以用来添加从左侧为零的填充。
gmtime
过滤器运行的时间,以UTC表示。它可以接受一个参数:strftime()格式字符串。
本地时间
过滤器运行的时间,以当地时区表示。它可以接受一个参数:strftime()格式字符串。
pts
当前帧的时间戳。它最多可以有三个参数。
第一个参数是时间戳的格式;它默认使用FLT表示秒,作为微秒精度的十进制数;hms表示格式化的[-]HH:MM:SS。毫秒精度的MMM时间戳。gmtime表示UTC时间格式的帧的时间戳;Localtime表示格式化为本地时区时间的帧的时间戳。
第二个参数是添加到时间戳的偏移量。
如果格式设置为hms,则可以提供第三个参数24HH,以24h格式(00-23)表示格式化时间戳的小时部分。
如果格式设置为localtime或gmtime,则可以提供第三个参数:strftime()格式字符串。默认使用YYYY-MM-DD HH:MM:SS格式。

测试案例

drawtext=“fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text=‘Test Text’:
x=100: y=50: fontsize=24: fontcolor=yellow@0.2: box=1: boxcolor=red@0.2”
在x=100和y=50的位置(从屏幕的左上角开始计算),用字体FreeSerif绘制大小为24的“测试文本”,文本是黄色的,周围有一个红色框。文本和框的不透明度均为20%。

ffmpeg -t 5 -i recodeFile.mp4 -vf drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Test Text':\x=100: y=50: fontsize=60: fontcolor=yellow@0.2: box=1: boxcolor=red@0.2" -c:v libx264 -an -f mp4 output.mp4 -y

在这里插入图片描述

相关命令实现;

参考;https://blog.csdn.net/ternence_hsu/article/details/102540626

ffmpeg -t 5 -i recodeFile.mp4 -vf "drawtext=fontsize=60:text='%{localtime\:%Y-%M-%d %H.%m.%S}'" -c:v libx264 -an -f mp4 output.mp4 -y

在这里插入图片描述

ffmpeg -t 5 -i recodeFile.mp4 -vf "drawtext=fontfile=STSONG.TTF:fontcolor=red:fontsize=100:x=0:y=0:text='%{localtime\:%Y-%M-%d %H.%m.%S}'" -c:v libx264 -an -f mp4 output.mp4 -y
还可以增加属性
fontfile=STSONG.TTF字体类型,可以从 C:\Windows\Fonts 拷贝一个有效的字体文件放到当前目录。
fontcolor=red颜色
fontsize=100大小
x=0:y=0坐标
text='%{localtime\:%Y-%M-%d %H.%m.%S}'具体的值

在这里插入图片描述

API实现

参考;https://blog.csdn.net/dancing_night/article/details/80536510

int InitAvFilter(AVFilterGraph *&filter_graph, AVFilterContext * &bufferSrc_ctx, AVFilterContext* &bufferSink_ctx, const char *args)
{
	int ret = 0;

	avfilter_register_all();

	filter_graph = avfilter_graph_alloc();
	if (!filter_graph)
	{
		cout << "create filter graph Fial" << endl;
		return -1;
	}

	//创建一个buffer源过滤器并创建对应的过滤器实列并加入过滤器图中,之后就需要将图里面的不同过滤器链接到一起即可
	AVFilter* bufferSrc = avfilter_get_by_name("buffer");
	ret = avfilter_graph_create_filter(&bufferSrc_ctx, bufferSrc ,"in", args, NULL, filter_graph);
	if (ret < 0) {
		printf("Fail to create filter\n");
		return -1;
	}

	//创建buffersink目的过滤器
	//bufferSink需要设置参数 允许的像素格式列表,以AV_PIX_FMT_NONE结束
	AVBufferSinkParams *bufferSink_params = NULL;
	enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
	bufferSink_params = av_buffersink_params_alloc();
	bufferSink_params->pixel_fmts = pix_fmts;
	AVFilter* bufferSink = avfilter_get_by_name("buffersink"); //ffbuffersink带缓冲的buffersink
	ret = avfilter_graph_create_filter(&bufferSink_ctx, bufferSink, "out", NULL, bufferSink_params, filter_graph);
	if (ret < 0) {
		printf("Fail to create filter sink filter\n");
		return -1;
	}
	AVFilterInOut *outputs = avfilter_inout_alloc();
	AVFilterInOut *inputs = avfilter_inout_alloc();
	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;

	time_t now = time(0);
	string strTime = "";
	char ch[100] = { 0 };
	tm *ltm = localtime(&now);
	// 输出 tm 结构的各个组成部分
	itoa(ltm->tm_sec, ch, 10);
	strTime = ch;
	string m_filters_descr = "drawtext=fontfile=STSONG.TTF:fontcolor=red:fontsize=50:x=0:y=0:text=";
	m_filters_descr += "\'%{localtime\\:%Y-%m-%d %H.%M.%S}\'";
	//string m_filters_descr = "settb=AVTB,setpts='trunc(PTS/1K)*1K+st(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K)',drawtext=fontsize=100:fontcolor=white:text='%{localtime}.%{eif\:1M*t-1K*trunc(t*1K)\:d}'";
	if ((ret = avfilter_graph_parse_ptr(filter_graph, m_filters_descr.c_str(),
		&inputs, &outputs, NULL)) < 0)
		return -1;

	if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
		return -1;
	return ret;

}


//读写帧的时候调用
//向缓冲区源添加一个帧。
if (av_buffersrc_add_frame(bufferSrc_ctx, pFrame) < 0) {
	printf("Error while add frame.\n");
	break;
}

//从接收器获得一个过滤后的数据帧,并将其放入帧中。
/* pull filtered pictures from the filtergraph */
ret = av_buffersink_get_frame(bufferSink_ctx, frame_out);
if (ret < 0)
	break;

补充多处水印添加

命令

ffmpeg -t 5 -i recodeFile.mp4 -vf "drawtext=fontfile=STSONG.TTF:fontcolor=red:x=0:y=0:fontsize=60:text='123'[a];[a]drawtext=fontfile=STSONG.TTF:fontcolor=red:x=0:y=100:fontsize = 60 : text='123'	" -c:v libx264 -an -f mp4 output.mp4 -y

在这里插入图片描述

API

string m_filters_descr = "drawtext=fontfile=textfont.ttf:fontcolor=red:fontsize=50:x=0:y=0:text=";
m_filters_descr += "\'%{localtime\\:%Y-%m-%d %H.%M.%S}\'";
m_filters_descr += "[a]";
m_filters_descr += ";";
m_filters_descr += "[a]";
m_filters_descr += "drawtext=fontfile=textfont.ttf:fontcolor=red:fontsize=50:x=300:y=300:text=\'H5RTC111 \'";
//string  m_filters_descr = "drawtext=fontcolor=red:fontsize=50:x=0:y=0:text=\'sfadfdsf\'";
//string m_filters_descr = "settb=AVTB,setpts='trunc(PTS/1K)*1K+st(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K)',drawtext=fontsize=100:fontcolor=white:text='%{localtime}.%{eif\:1M*t-1K*trunc(t*1K)\:d}'";
if ((ret = my_avfilter_graph_parse_ptr(filter_graph, (const char *)m_filters_descr.c_str(), &inputs, &outputs, NULL)) < 0)
{
	char buf[1024] = { 0 };
	av_strerror(ret, buf, sizeof(buf));//ffmpeg中打印错误信息
	return -1;
}

参考博客
https://blog.csdn.net/m0_37684310/article/details/78257779

项目代码
git仓库

drawtext中文水印显示问题

drawtext中文显示不出来,
1、首先确保编码是UTF-8
采用转换来保证是否是UTF-8;vs编码器默认GB2312编码调试可以看到中文字
char s[1000];
char *s1 = s;
s1 = U2G(m_strbusinessType.c_str());
string sss = G2U(s1);

//UTF-8到GB2312的转换
char* U2G(const char* utf8)
{
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
if (wstr) delete[] wstr;
return str;
}

//GB2312到UTF-8的转换
char* G2U(const char* gb2312)
{
int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
if (wstr) delete[] wstr;
return str;
}

2、如果还是提示一个框框的,则可以替换字体库查看英文字体是否变化,我这的原因是字体没有找到,使用默认的则不支持中文

fontfile
The font file to be used for drawing text. The path must be
included. This parameter is mandatory if the fontconfig support is disabled.
用于绘制文本的字体文件。必须包括路径。当fontconfig支持被禁用时,此参数为必选参数。
ffmpeg官网有说必须包含路径的,主要是验证的时候用命令行不需要都可以直接指定路径替换过来导致一直怀疑编码而没有怀疑是字体库没有找到

 ffmpeg -t 15 -i recodeFile.mp4 -vf "drawtext=fontfile=msyhbd.ttc:fontsize=160:fontcolor=red:fontsize=100:x=0:y=0:text="你好啊"" -c:v libx264 -an -f mp4 output.mp4 -y

3、如何使用绝对路径指定,相对路径指定
注意绝对目录因为使用了:则需要用\\\,在命令行里面只要\\个就行了。

strWaterFilter += "drawtext=fontfile=D\\\\\\://STSONG.TTF:fontcolor=red:fontsize=25";

注意相对目录在调试的时候当前目录是工程cvproject所在目录,而在实践运行的时候是生成exe所在目录

strWaterFilter += "drawtext=fontfile=.//STSONG.TTF:fontcolor=red:fontsize=50"; 

在这里插入图片描述

参考博客
https://www.cnblogs.com/wanggang123/p/6707985.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐