C#实现为视频添加水印
作者:Csharp小记 发布时间:2022-02-16 05:30:07
标签:C#,视频,水印
文章描述
以下主要还是使用到了ffmpeg命令,分别实现了给视频添加图片水印以及文字水印。
开发环境
.NET Framework版本:4.5
开发工具
Visual Studio 2013
实现代码
public static void Run(string cmd)
{
try
{
string ffmpeg = AppDomain.CurrentDomain.BaseDirectory + "ffmpeg.exe";
ProcessStartInfo startInfo = new ProcessStartInfo(ffmpeg);
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = cmd;
Process process = Process.Start(startInfo);
process.WaitForExit(3000);
process.Kill();
}
catch { }
}
/// <summary>
/// 按时间获取某帧图片
/// </summary>
/// <param name="videoPath">视频路径</param>
/// <param name="outPath">输出路径</param>
/// <param name="frameTime">时间(格式:00:00:01)</param>
public static void GetFrame(string videoPath, string outPath, string frameTime)
{
Run(string.Format("-ss 00:00:01 -i {1} {2}", frameTime, videoPath, outPath));
}
/// <summary>
/// 批量添加图片水印
/// </summary>
/// <param name="videoPath"></param>
/// <param name="outPath"></param>
/// <param name="listImg"></param>
public static void AddImageMark(string videoPath, string outPath, List<ImgMark> listImg)
{
string imgs = "", postions = "";
foreach (ImgMark mark in listImg)
{
imgs += " -i " + mark.ImgPath;
postions += "overlay=" + mark.Postion.X + ":" + mark.Postion.Y+",";
}
postions = postions.Remove(postions.Length - 1);
Run(string.Format("-i {0}{1} -filter_complex \"{2}\" {3}", videoPath, imgs, postions, outPath));
}
/// <summary>
/// 添加文字水印
/// </summary>
/// <param name="videoPath">视频路径</param>
/// <param name="outPath">输出路径</param>
/// <param name="textMark">水印属性</param>
public static void AddTextMark(string videoPath, string outPath, TextMark textMark)
{
Run(string.Format(" -i {0} -vf \"drawtext=fontfile={1}: text='{2}':x={3}:y={4}:fontsize={5}:fontcolor={6}\" {7}", videoPath, textMark.FontFile, textMark.Text, textMark.X, textMark.Y, textMark.FontSize, textMark.FontColor.Name.ToLower(), outPath));
//@"%{localtime\:%Y\-%m\-%d %H-%M-%S}"
}
private void btn_select_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "视频|*.mp4;*.avi";
ofd.Title = "请选择视频文件";
ofd.InitialDirectory = Application.StartupPath;
if (ofd.ShowDialog() == DialogResult.OK)
{
axWindowsMediaPlayer1.URL = ofd.FileName;
}
}
private void btn_text_Click(object sender, EventArgs e)
{
if (!File.Exists(axWindowsMediaPlayer1.URL))
{
MessageBox.Show("未选择视频");
return;
}
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "视频|*.mp4";
sfd.AddExtension = true;
if (sfd.ShowDialog() == DialogResult.OK)
{
TextMark mark = new TextMark
{
Text = "这里是水印",
FontColor = Color.Red,
FontFile = "simsun.ttc",
FontSize = 100,
X = 80,
Y = 60
};
FFmpegUtil.AddTextMark(axWindowsMediaPlayer1.URL, sfd.FileName, mark);
axWindowsMediaPlayer2.URL = sfd.FileName;
}
}
private void btn_img_Click(object sender, EventArgs e)
{
if (!File.Exists(axWindowsMediaPlayer1.URL))
{
MessageBox.Show("未选择视频");
return;
}
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "视频|*.mp4";
sfd.AddExtension = true;
if (sfd.ShowDialog() == DialogResult.OK)
{
FFmpegUtil.AddImageMark(axWindowsMediaPlayer1.URL, sfd.FileName, new List<ImgMark>{
new ImgMark {
ImgPath=@"C:\Users\Zero\Desktop\a\\1.png", Postion=new Point(60,60)},
new ImgMark {ImgPath=@"C:\Users\Zero\Desktop\a\\1.png", Postion=new Point(60,200)}});
axWindowsMediaPlayer2.URL = sfd.FileName;
}
}
实现效果
代码解析:着重介绍下添加文字水印的,由于很多时候我们需要添加的是中文,所以需要将字体包先放入到ffmepg的同级目录,然后指定该字体。
来源:https://mp.weixin.qq.com/s/g6Rx7mnIK4rhJxmZS3gX5A
0
投稿
猜你喜欢
- 由于最近想要阅读下JDK1.8 中HashMap的具体实现,但是由于HashMap的实现中用到了红黑树,所以我觉得有必要先复习下红黑树的相关
- 概述Selenium是一款免费的分布式的自动化测试工具,支持多种开发语言,无论是C、 java、ruby、python、或是C# ,你都可以
- 前言:顺序表的问题及思考1. 顺序表中间/头部的插入删除,时间复杂度为O(N)2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗
- 1 异常异常的体系• ThrowableError通常出现重大问题如:运行的类不存在或者内存溢出等。不编写针对代码对其处理Exception
- 1.概述在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。很多项目都会封装规定好本身项目的接口规范,所以大多数需要
- 前言JAVA中在运用数组进行排序功能时,一般有四种方法:快速排序法、冒泡法、选择排序法、插入排序法。本文就给大家介绍了关于最简单易懂的jav
- SpringBoot入门Demo,一次深夜踩坑记录。springboot小项目开启后,访问端口无反应。首先看我的项目目录:项目的pom文件内
- 字节流和字符流对于文件必然有读和写的操作,读和写就对应了输入和输出流,流又分成字节和字符流。1.从对文件的操作来讲,有读和写的操作——也就是
- 一、pom.xml<dependency> <groupId>net.sf.ehcache
- 场景在任何一个Form表单的操作页面或者数据台账的查询页面,基本都会看到一个清除的按钮,其功能就是用来清除我们需要抛弃的已经写入到控件内的数
- 1. 引言在 Java 应用程序中,异常类对于正确捕获和处理错误至关重要。我们常常在编写异常处理的重复代码上花费时间,而不是关注应用程序的其
- IP地址与整数之间的转换1、IP地址转换为整数原理:IP地址每段可以看成是8位无符号整数即0-255,把每段拆分成一个二进制形式组合起来,然
- 今天一起学习下如何在Spring中进行异步编程。我们都知道,web服务器处理请求 request 的线程是从线程池中获取的,这也不难解释,因
- 上一节是把大概的流程给过了一遍,但是还有很多地方没有说到,后续的慢慢会涉及到,敬请期待!这次我们说说垃圾收集器,又名gc,顾名思义,就是收集
- List查询JAVA中从数据库中取数据,根据MyBits返回结果主要有两种类型的List,一种是List<Entity>,还一种
- 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还
- 一、链表的介绍什么是链表链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结
- 1、AOP基本总结连接点(JoinPoint):连接点是程序运行的某个阶段点,如方法调用、异常抛出等切入点(Pointcut):切入点是Jo
- 2017年一直以来在公司负责爬虫项目相关工程,主要业务有预定、库存、在开发中也遇到很多问题,随手记录一下,后续会持续更新。chrome、fi
- GUI编程实现贪吃蛇小游戏,供大家参考,具体内容如下1、编写主方法实现启动类2、准备好素材图片,编写数据类3、代码主体部分:在panel面板