using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace StHH
{
public class VideoHelper
{
//引用示例
//VideoHelper.Install.ExecuteVideo(
// ffmpegPath: @"D:\app\ffmpeg\bin\ffmpeg.exe",
// originalVideo: @"D:\AreYouOk\AA.mp4",
// newVideo: @"D:\AreYouOk\newFile.mp4",
// waterWord:"少年强",
// fontSize: 18);
public static readonly VideoHelper Install = new VideoHelper();
/// <summary>
/// 执行一条command命令
/// </summary>
/// <param name="command">需要执行的Command</param>
/// <param name="output">输出</param>
/// <param name="error">错误</param>
private void ExecuteCommand(string command, out string output, out string error)
{
try
{
//创建一个进程
Process pc = new Process();
pc.StartInfo.FileName = command;
pc.StartInfo.UseShellExecute = false;
pc.StartInfo.RedirectStandardOutput = true;
pc.StartInfo.RedirectStandardError = true;
pc.StartInfo.CreateNoWindow = true;
//启动进程
pc.Start();
//准备读出输出流和错误流
string outputData = string.Empty;
string errorData = string.Empty;
pc.BeginOutputReadLine();
pc.BeginErrorReadLine();
pc.OutputDataReceived += (ss, ee) =>
{
outputData += ee.Data;
};
pc.ErrorDataReceived += (ss, ee) =>
{
errorData += ee.Data;
};
//等待退出
pc.WaitForExit();
//关闭进程
pc.Close();
//返回流结果
output = outputData;
error = errorData;
}
catch (Exception)
{
output = null;
error = null;
}
}
/// <summary>
/// 获取视频的帧宽度和帧高度
/// </summary>
/// <param name="videoFilePath">mov文件的路径</param>
/// <returns>null表示获取宽度或高度失败</returns>
private void GetVideoSize(string videoFilePath, out int? width, out int? height)
{
try
{
//判断文件是否存在
if (!File.Exists(videoFilePath))
{
width = null;
height = null;
}
string ffmpegPath = FFmpegPath;
string output;
string error;
ExecuteCommand("\"" + ffmpegPath + "\"" + " -i " + "\"" + videoFilePath + "\"", out output, out error);
if (string.IsNullOrEmpty(error))
{
width = null;
height = null;
}
//通过正则表达式获取信息里面的宽度信息
Regex regex = new Regex("(\\d{2,4})x(\\d{2,4})", RegexOptions.Compiled);
Match m = regex.Match(error);
if (m.Success)
{
width = int.Parse(m.Groups[1].Value);
height = int.Parse(m.Groups[2].Value);
}
else
{
width = null;
height = null;
}
}
catch (Exception)
{
width = null;
height = null;
}
}
/// <summary>
/// 生成文字水印的图片
/// </summary>
/// <param name="text"></param>
/// <param name="isBold"></param>
/// <param name="fontSize"></param>
private Image CreateWaterImage(string text, int fontSize, double w, double h)
{
Font font = new Font("宋体", fontSize, FontStyle.Regular);
//绘笔颜色
SolidBrush brush = new SolidBrush(Color.FromArgb(255, 255, 255, 255));
StringFormat format = new StringFormat(StringFormatFlags.NoClip);
Bitmap image = new Bitmap(Convert.ToInt32(w), Convert.ToInt32(h));
Graphics g = Graphics.FromImage(image);
SizeF sizef = g.MeasureString(text, font, PointF.Empty, format);//得到文本的宽高
int width = (int)(sizef.Width + 1);
int height = (int)(sizef.Height + 1);
int s_w = 1, s_h = 1;
if (w > 100)
{
s_w = Convert.ToInt32(w / 100);
}
if (h > 100)
{
s_h = Convert.ToInt32(h / 100);
}
for (int x = 0; x < 1000; x++)
{
for (int y = 0; y < 1000; y++)
{
float i_x = (float)(x * (width + w / s_w));
float i_y = (float)(y * (height + h / s_h));
if (i_x > w) continue;
if (i_y > h) continue;
RectangleF rect = new RectangleF(i_x, i_y, width, height);
//绘制图片
g.DrawString(text, font, brush, rect);
}
}
//g.Clear(Color.Transparent);
//g.Flush();
//释放对象
g.Dispose();
return image;
}
/// <summary>
/// 生成文字水印视频
/// </summary>
/// <param name="ffmpegPath">ffmpeg.exe路径</param>
/// <param name="originalVideo">原始视频</param>
/// <param name="newVideo">目标视频</param>
/// <param name="waterWord">水印文字</param>
/// <param name="fontSize">水印文字字体大小</param>
/// <returns></returns>
public VideoResult ExecuteVideo(string ffmpegPath, string originalVideo, string newVideo, string waterWord, int fontSize = 18)
{
FFmpegPath = ffmpegPath;
VideoResult result = new VideoResult()
{
IsSuccess = false
};
if (string.IsNullOrEmpty(ffmpegPath))
{
result.Msg = "FFmpeg路径为空";
return result;
}
if (string.IsNullOrEmpty(originalVideo))
{
result.Msg = "原始视频为空";
return result;
}
if (File.Exists(originalVideo) == false)
{
result.Msg = "原始视频不存在";
return result;
}
if (string.IsNullOrEmpty(newVideo))
{
result.Msg = "目标视频为空";
return result;
}
if (string.IsNullOrEmpty(waterWord))
{
result.Msg = "水印文字为空";
return result;
}
try
{
int? s_w, s_h;
GetVideoSize(originalVideo, out s_w, out s_h);
if (s_w.HasValue == false)
{
result.Msg = "无法读取视频宽度";
return result;
}
if (s_h.HasValue == false)
{
result.Msg = "无法读取视频高度";
return result;
}
if (s_w.Value <= 0)
{
result.Msg = "无法识别视频宽度";
return result;
}
if (s_h.Value <= 0)
{
result.Msg = "无法识别视频高度";
return result;
}
var i_w = Math.Sqrt(Math.Pow(s_w.Value, 2) + Math.Pow(s_h.Value, 2));
var i_h = s_w.Value * s_h.Value * 2 / i_w;
if (s_h.Value > s_w.Value)
{
i_h = Math.Sqrt(Math.Pow(s_w.Value, 2) + Math.Pow(s_h.Value, 2));
i_w = s_w.Value * s_h.Value * 2 / i_h;
}
i_w = i_w * 1.2;
i_h = i_h * 1.2;
var v_x = (s_w - i_w) / 2;
var v_y = (s_h - i_h) / 2;
string watermarkImage = Path.Combine(System.Environment.CurrentDirectory, DateTime.Now.ToString("HHmmssfff") + ".png");
Image img = CreateWaterImage(text: waterWord, fontSize: fontSize, i_w, i_h);
img.Save(watermarkImage);
img.Dispose();
watermarkImage = watermarkImage.Substring(0, 1) + @"\\" + watermarkImage.Substring(1).Replace("\\", "/");
//lut=a=val*0.15 调水印图片的透明度
string arguments = "-i " + originalVideo + " -vf \"movie=" + watermarkImage + ",scale=w=" + i_w + ":h=" + i_h + ",rotate=a=-PI*30/180, lut=a=val*0.15[watermark];[in][watermark] overlay=x=" + v_x + ":y=" + v_y + "\" " + newVideo;
using (var process = new Process())
{
process.StartInfo.FileName = FFmpegPath;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
}
result.IsSuccess = true;
return result;
}
catch (Exception ex)
{
result.Msg = "生成水印视频失败," + ex.Message;
result.Ex = ex;
return result;
}
}
/// <summary>
/// ffmpeg.exe路径
/// </summary>
private string FFmpegPath { get; set; }
}
public class VideoResult
{
public bool IsSuccess { get; set; } = false;
public string Msg { get; set; } = "";
public Exception Ex { get; set; }
}
}
C#满屏倾斜文字水印的视频