视频水印是保护版权、标识视频来源的重要技术。本文将详细介绍如何使用C#和FFmpeg为视频添加水印,并提供多种实现方式。
准备工作
环境依赖
- .NET Framework 4.7.2 或更高版本
- FFmpeg(需要下载并配置系统环境变量)
- NuGet包:Xabe.FFmpeg
安装NuGet包
使用Package Manager Console安装:
Install-Package Xabe.FFmpeg
基本水印实现
文字水印
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xabe.FFmpeg;
namespace App08
{
public class VideoWatermarker
{
/// <summary>
/// 为视频添加文字水印
/// </summary>
/// <param name="inputVideo">输入视频路径</param>
/// <param name="outputVideo">输出视频路径</param>
/// <param name="watermarkText">水印文字内容</param>
public async Task AddTextWatermarkAsync(
string inputVideo,
string outputVideo,
string watermarkText)
{
try
{
// 确保已设置 FFmpeg 执行文件路径
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
// 创建转换
IMediaInfo mediaInfo = await FFmpeg.GetMediaInfo(inputVideo);
// 配置转换参数
var conversion = FFmpeg.Conversions.New()
.AddStream(mediaInfo.VideoStreams)
.AddStream(mediaInfo.AudioStreams)
.AddParameter($"-vf \"drawtext=fontfile=msyh.ttc:" +
$"text='{watermarkText}':" +
"fontcolor=white:" +
"fontsize=24:" +
"box=1:" +
"boxcolor=black@0.5:" +
"boxborderw=5:" +
"x=(w-text_w)/2:" +
"y=(h-text_h)/2\"")
.SetOutput(outputVideo);
// 执行转换
await conversion.Start();
}
catch (Exception ex)
{
Console.WriteLine($"水印添加失败:{ex.Message}");
throw;
}
}
}
}
static async Task Main(string[] args)
{
VideoWatermarker watermarker = new VideoWatermarker();
await watermarker.AddTextWatermarkAsync("D:\\Video\\1.mp4", "d:\\output.mp4", "IDIOSOFT");
}
图片水印
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xabe.FFmpeg;
namespace App08
{
public class ImageWatermarker
{
public async Task AddImageWatermarkAsync(
string inputVideo,
string outputVideo,
string watermarkImage)
{
try
{
// 设置 FFmpeg 路径
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
// 创建转换配置
IConversion conversion = FFmpeg.Conversions.New()
.AddParameter($"-i \"{inputVideo}\" -i \"{watermarkImage}\" " +
$"-filter_complex \"[0:v][1:v] overlay=W-w-10:10\" " +
$"-c:a copy")
.SetOutput(outputVideo);
// 添加进度报告
conversion.OnProgress += (sender, args) =>
{
var percent = args.Percent;
Console.WriteLine($"处理进度: {percent:F1}%");
};
// 添加完成处理程序
conversion.OnDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
{
Console.WriteLine($"FFmpeg输出: {args.Data}");
}
};
// 执行转换
await conversion.Start();
Console.WriteLine("水印添加成功!");
}
catch (Exception ex)
{
Console.WriteLine($"图片水印添加失败:{ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"内部错误:{ex.InnerException.Message}");
}
throw;
}
}
}
}
如果需要调整水印位置,可以修改overlay参数:
- 右上角:overlay=W-w-10:10
- 左下角:overlay=10:H-h-10
- 右下角:overlay=W-w-10:H-h-10
- 居中:overlay=(W-w)/2:(H-h)/2
其中:
- W: 视频宽度
- H: 视频高度
- w: 水印宽度
- h: 水印高度
高级水印技巧
动态水印位置
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xabe.FFmpeg;
namespace App08
{
public class ImageWatermarker
{
public async Task AddImageWatermarkAsync(
string inputVideo,
string outputVideo,
string watermarkImage)
{
try
{
// 设置 FFmpeg 路径
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
// 创建转换配置
IConversion conversion = FFmpeg.Conversions.New()
.AddParameter($"-i \"{inputVideo}\" -i \"{watermarkImage}\" " + // Added input video parameter
"-filter_complex \"" +
"[0:v][1:v]overlay='if(gte(t,2),main_w-overlay_w-10,10):" +
"if(gte(t,2),main_h-overlay_h-10,10)'" +
"\" -codec:a copy")
.SetOutput(outputVideo);
// 添加进度报告
conversion.OnProgress += (sender, args) =>
{
var percent = args.Percent;
Console.WriteLine($"处理进度: {percent:F1}%");
};
// 添加完成处理程序
conversion.OnDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
{
Console.WriteLine($"FFmpeg输出: {args.Data}");
}
};
// 执行转换
await conversion.Start();
Console.WriteLine("水印添加成功!");
}
catch (Exception ex)
{
Console.WriteLine($"图片水印添加失败:{ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"内部错误:{ex.InnerException.Message}");
}
throw;
}
}
}
}
图片
// 创建转换配置
IConversion conversion = FFmpeg.Conversions.New()
.AddParameter($"-i \"{inputVideo}\" -i \"{watermarkImage}\" " +
"-filter_complex \"" +
"[0:v][1:v]overlay=" +
"'if(lt(mod(t,8),2),10," + // 0-2秒:左上角
"if(lt(mod(t,8),4),main_w-overlay_w-10," + // 2-4秒:右上角
"if(lt(mod(t,8),6),10," + // 4-6秒:左下角
"main_w-overlay_w-10))):" + // 6-8秒:右下角
"if(lt(mod(t,8),2),10," + // 0-2秒:左上角
"if(lt(mod(t,8),4),10," + // 2-4秒:右上角
"if(lt(mod(t,8),6),main_h-overlay_h-10," + // 4-6秒:左下角
"main_h-overlay_h-10)))'" + // 6-8秒:右下角
"\" -codec:a copy")
.SetOutput(outputVideo);
参数说明:
水印位置循环逻辑:
使用mod(t,8)将时间分成8秒一个循环,然后在这8秒内分配四个不同的位置
透明度控制
// 创建转换配置
IConversion conversion = FFmpeg.Conversions.New()
.AddParameter($"-i \"{inputVideo}\" -i {watermarkImage} " +
"-filter_complex \"" +
"[1:v]format=rgba,colorchannelmixer=aa=0.5[watermark];" +
"[0:v][watermark]overlay=10:10" +
"\" -codec:a copy")
.SetOutput(outputVideo);
注意事项
- 确保FFmpeg正确安装
- 处理大视频文件时注意内存占用
- 水印不应过度遮挡视频内容
结论
通过C#和FFmpeg,我们可以灵活地为视频添加各种类型的水印,保护内容并增加版权标识。