ffmpeg 非movie滤镜添加图片水印

该博客介绍了如何利用ffmpeg命令行将jpg图片转换为yuv420格式,并在C++代码中实现将转换后的yuv图片叠加到视频上,省去了movie滤镜的使用。作者详细展示了从图片转换到视频处理的步骤,包括读取yuv文件、构建AVFrame、进行图片叠加等操作。

本人在ffmpeg movie滤镜添加图片水印博客中用命令行以及代码的方式,利用movie滤镜将jpg图片叠加到视频上。

其实,我们也可以将jpg直接转成yuv420,然后叠加到视频上,此时就不需要movie滤镜。
首先,将jpg转换成yuv420,可以用ffmpeg命令行,命令行如下:
ffmpeg -i flower.jpg -s 480x320 -pix_fmt yuv420p flower.yuv
这里定义了规格,480x320,其实原来的flower.jpg的规格是499x333,我为了linesize的对齐方便,将规格改成了480x320,图片如下所示:
请添加图片描述
合成效果如下:
在这里插入图片描述

main函数如下:

int main()
{
   
   
	CDrawMyMovie cVideoDrawMovie;
	const char *pFileA = "E:\\learn\\ffmpeg\\FfmpegFilterTest\\x64\\Release\\in-computer.mp4";

	const char *pFileOut = "E:\\learn\\ffmpeg\\FfmpegFilterTest\\x64\\Release\\in-computer_drawmymovie.mp4";

	std::string strMovieFile = "E:\\learn\\ffmpeg\\convert\\flower.yuv";
	//std::string strMovieFile = "flower.jpg";
	cVideoDrawMovie.StartDrawMyMovie(pFileA, pFileOut, 100, 300, strMovieFile, 480, 320);
	cVideoDrawMovie.WaitFinish();
	return 0;
}

这里面,100,300代表叠加的位置坐标。

y,u,v分量的读取很简单,因为它们在文件是依次存储的,读取方式如下所示:

int CDrawMyMovie::ReadMovieFile(const char *pFileMovie, int iWidth, int iHeight)
{
   
   
	m_iMovieWidth = iWidth;
	m_iMovieHeight = iHeight;

	int ret = -1;
	do 
	{
   
   
		FILE *fp = fopen(pFileMovie, "rb");
		if (NULL == fp)
		{
   
   
			break;
		}
		m_pMovieY = new uint8_t[iWidth * iHeight];
		m_pMovieU = new uint8_t[iWidth * iHeight / 4];
		m_pMovieV = new uint8_t[iWidth * iHeight / 4];

		int iread = fread(m_pMovieY, 1, iWidth * iHeight, fp);
		iread = fread(m_pMovieU, 1, iWidth * iHeight / 4, fp);
		iread = fread(m_pMovieV, 1, iWidth * iHeight / 4, fp);

		ret = 0;
	} while (0);
	

	return ret;
}

下面我们可以根据宽,高,yuv分量值构建水印图片的AVFrame

int iYuv420MovieFrameSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, m_iMovieWidth, m_iMovieHeight, 1);
AVFrame *pFrameVideoMovie = av_frame_alloc();
uint8_t *videoMovie_buffer_yuv420 = (uint8_t *)av_malloc(iYuv420MovieFrameSize);
av_image_fill_arrays(pFrameVideoMovie->data, pFrameVideoMovie->linesize, videoMovie_buffer_yuv420, AV_PIX_FMT_YUV420P, m_iMovieWidth, m_iMovieHeight, 1);

pFrameVideoMovie->width = m_iMovieWidth;
pFrameVideoMovie->height = m_iMovieHeight;
pFrameVideoMovie->format = AV_PIX_FMT_YUV420P;

memcpy(pFrameVideoMovie->data[0], m_pMovieY, m_iMovieWidth * m_iMovieHeight);
memcpy(pFrameVideoMovie->data[1], m_pMovieU, m_iMovieWidth * m_iMovieHeight / 4);
memcpy(pFrameVideoMovie->data[2], m_pMovieV, m_iMovieWidth * m_iMovieHeight / 4);

然后根据下面的代码进行两张图片的叠加

ret = av_buffersrc_add_frame(m_pFilterCtxSrcVideoA, pFrameVideoA);
if (ret < 0)
{
   
   
	break;
}

ret = av_buffersrc_add_frame(m_pFilterCtxSrcVideoMovie, pFrameVideoMovie);
if (ret < 0)
{
   
   
	break;
}

ret = av_buffersink_get_frame(m_pFilterCtxSink, pFrame_out);
if (ret < 0)
{
   
   
	//printf("Mixer: failed to call av_buffersink_get_frame_flags\n");
	break;
}

代码结构如下:
在这里插入图片描述

其中FfmpegMyMovieTest.cpp的内容如下:

#include <iostream>
#include "DrawMyMovie.h"
#include <vector>

#ifdef	__cplusplus
extern "C"
{
   
   
#endif

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")


#ifdef __cplusplus
};
#endif



std::string Unicode_to_Utf8(const std::string & str)
{
   
   
	int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
	wchar_t * pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴 
	ZeroMemory(pwBuf, nwLen * 2 + 2);
	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
	char * pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);
	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
	std::string retStr(pBuf);
	delete[]pwBuf;
	delete[]pBuf;
	pwBuf = NULL;
	pBuf = NULL;
	return retStr;
}


int main()
{
   
   
	CDrawMyMovie cVideoDrawMovie;
	const char *pFileA = "E:\\learn\\ffmpeg\\FfmpegFilterTest\\x64\\Release\\in-computer.mp4";

	const char *pFileOut = "E:\\learn\\ffmpeg\\FfmpegFilterTest\\x64\\Release\\in-computer_drawmymovie.mp4";

	std::string strMovieFile = "E:\\learn\\ffmpeg\\convert\\flower.yuv";
	//std::string strMovieFile = "flower.jpg";
	cVideoDrawMovie.StartDrawMyMovie(pFileA
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值