【音视频】使用movie、drawtext过滤器实现图片、文字水印(6-3)

24 篇文章 9 订阅
24 篇文章 2 订阅

本来准备从六月份开始研究使用ffmpeg的movie filter实现图片水印、drawtext filter实现文字水印的能力,但一直没时间,临近中秋终于有空,于是研究了下ffmpeg命令行(这里不做展示,关注代码实现),从中转化为C++代码实现。

直接上代码,这里新增了视频水印类,以下是主要实现:

int VideoWaterMarker::init(const VIDEO_FILTER_CTX& outCtx, const VIDEO_FILTER_CTX* inCtx0, const VIDEO_FILTER_CTX* inCtx1)
{
	int err = ERROR_CODE_OK;

	if (m_inited) {
		return err;
	}

	if (inCtx0 == nullptr) {
		err = ERROR_CODE_PARAMS_ERROR;
		return err;
	}

	do {
		m_filterGraph = avfilter_graph_alloc();
		if (m_filterGraph == nullptr) {
			err = ERROR_CODE_FILTER_ALLOC_GRAPH_FAILED;
			break;
		}

		m_filterInCtxs = new VIDEO_FILTER_CTX;
		memcpy_s(&m_filterInCtxs[0], sizeof(VIDEO_FILTER_CTX), inCtx0, sizeof(VIDEO_FILTER_CTX));
		m_filterOutCtx = outCtx;

		m_filterInCtxs[0].filterInout = avfilter_inout_alloc();
		m_filterOutCtx.filterInout = avfilter_inout_alloc();

		char filterInArg[512] = { 0 };
		sprintf_s(filterInArg, sizeof(filterInArg), "video_size=%dx%d:pix_fmt=%d:frame_rate=%d:time_base=%d/%d:pixel_aspect=%d/%d",
			m_filterInCtxs[0].width, m_filterInCtxs[0].height, m_filterInCtxs[0].pixelFmt, m_filterInCtxs[0].framerate,
			m_filterInCtxs[0].timebase.num, m_filterInCtxs[0].timebase.den, m_filterInCtxs[0].pixelAspect.num, m_filterInCtxs[0].pixelAspect.den);

		int ret = avfilter_graph_create_filter(&m_filterInCtxs[0].filterCtx, avfilter_get_by_name("buffer"), "in", filterInArg, nullptr, m_filterGraph);
		if (ret < 0) {
			err = ERROR_CODE_FILTER_CREATE_FILTER_FAILED;
			break;
		}

		ret = avfilter_graph_create_filter(&m_filterOutCtx.filterCtx, avfilter_get_by_name("buffersink"), "out", nullptr, nullptr, m_filterGraph);
		if (ret < 0) {
			err = ERROR_CODE_FILTER_CREATE_FILTER_FAILED;
			break;
		}

		av_opt_set_bin(m_filterOutCtx.filterCtx, "pix_fmts", (uint8_t*)&m_filterOutCtx.pixelFmt, sizeof(m_filterOutCtx.pixelFmt), AV_OPT_SEARCH_CHILDREN);

		m_filterInCtxs[0].filterInout->name = av_strdup("in");
		m_filterInCtxs[0].filterInout->filter_ctx = m_filterInCtxs[0].filterCtx;
		m_filterInCtxs[0].filterInout->pad_idx = 0;
		m_filterInCtxs[0].filterInout->next = nullptr;

		m_filterOutCtx.filterInout->name = av_strdup("out");
		m_filterOutCtx.filterInout->filter_ctx = m_filterOutCtx.filterCtx;
		m_filterOutCtx.filterInout->pad_idx = 0;
		m_filterOutCtx.filterInout->next = nullptr;

		std::string filterDesc;
		/* 1、图片水印 */
		filterDesc = "movie=11.png[wm];[in][wm]overlay=W-w:H-h[out]";
		/* 2、文字水印 */
		std::wstring tempText = L"Hello, 世界!";
		std::string strText = HELPER::StringConverter::convertUnicodeToUtf8(tempText);
		filterDesc = "drawtext=fontfile=\'C\\:/Windows/Fonts/simsun.ttc\':fontsize=72:fontcolor=white:box=1:boxcolor=blue@0.5:x=w-text_w:y=h-text_h:text=\'" + strText + "\'";
		/* 3、时间水印 */
		filterDesc = "drawtext=fontfile=\'C\\:/Windows/Fonts/Arial.ttf\':text=\'%{localtime\\:%Y-%m-%d %H.%M.%S}\':fontsize=36:fontcolor=white:box=1:boxcolor=blue:x=100:y=50";
		ret = avfilter_graph_parse_ptr(m_filterGraph, filterDesc.c_str(), &m_filterOutCtx.filterInout, &m_filterInCtxs[0].filterInout, nullptr);
		if (ret < 0) {
			err = ERROR_CODE_FILTER_PARSE_PTR_FAILED;
			break;
		}

		ret = avfilter_graph_config(m_filterGraph, nullptr);
		if (ret < 0) {
			err = ERROR_CODE_FILTER_CONFIG_FAILED;
			break;
		}

		m_inited = true;
	} while (0);

	if (err != ERROR_CODE_OK) {
		LOGGER::Logger::log(LOGGER::LOG_TYPE_ERROR, "[%s] init mixer, error: %s", __FUNCTION__, HCMDR_GET_ERROR_DESC(err));
		cleanup();
	}

	return err;
}

1、对于图片的水印,使用movie filter将图片作为一个输入源[wm]跟另外一个视频输入源[in](摄像头或桌面采集)输出新的[out]视频源。“movie=11.png[wm];[in][wm]overlay=W-w:H-h[out]”,其中W、H是[in]的大小,w、h是[wm]的大小,将[wm]overlay在[in]上面,且显示在右下角。
2、对于文字水印,使用drawtext filter,首先要指定绝对路径的文字文件,例如fontfile=‘C\:/Windows/Fonts/simsun.ttc’,在windows下一定要这样写,要不然找不到指定的文字文件而使用默认的文字文件,其次文字输入如果包含中文则需要将其转化为UTF8格式作为text的值传入。一般文字大小从8磅到72磅,这里指定文字大小为72磅,颜色为白色,box=1表示开启文字背景色,指定背景色为蓝色且透明度为50%(文字也可以像这样单独指定透明度;如果要同时指定文字和背景色透明度,可以使用命令alpha=0.5),这里x、y将文字位置至于右下角。
3、对于时间水印,同样需要指定绝对路径fontfile,其次text需要指定例如text=‘%{localtime\:%Y-%m-%d %H.%M.%S}’,Y表示年,m表示月份,d表示天,H表示小时,M表示分钟,S表示秒,Arial字体的时间样式:
在这里插入图片描述

PS:因为视频水印也是线程驱动的,剩下的一些实现如开始线程start()、停止线程stop()、喂帧addFrame()、清空cleanup()和线程函数mixProcess()跟《【音视频】视频混流-avfilter(2-2)》类似,可以跳转参考。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值