在C#开发中,处理视频转码、裁剪、提取音频、添加水印等需求时,直接调用FFmpeg是成本较低且效果稳定的方案。FFmpeg是跨平台的音视频处理工具,支持几乎所有主流音视频格式的转换与处理,C#可以通过进程调用或封装库的方式使用它的能力。
环境准备
首先需要下载FFmpeg的可执行文件,前往FFmpeg官方渠道获取对应系统的版本,解压后得到ffmpeg.exe(Windows系统)或者ffmpeg(Linux/Mac系统)文件,将文件放在项目可访问的路径下,后续调用时需要指定该文件的路径。
方法一:通过Process类直接调用
这是最基础也最常用的调用方式,C#的System.Diagnostics命名空间下的Process类可以启动外部进程,执行FFmpeg的命令行指令,适合大多数简单的视频处理场景。
基础调用示例:视频转码
以下代码实现将MP4格式视频转码为AVI格式,同时捕获FFmpeg的输出信息:
using System;
using System.Diagnostics;
namespace FFmpegDemo
{
class Program
{
static void Main(string[] args)
{
// FFmpeg可执行文件路径
string ffmpegPath = @"D:ffmpegbinffmpeg.exe";
// 输入视频路径
string inputVideo = @"D:inputtest.mp4";
// 输出视频路径
string outputVideo = @"D:outputtest.avi";
// 构建FFmpeg命令行参数
// -i 指定输入文件,-y 覆盖已有输出文件
string arguments = $"-i "{inputVideo}" -y "{outputVideo}"";
// 创建进程对象
Process process = new Process();
process.StartInfo.FileName = ffmpegPath;
process.StartInfo.Arguments = arguments;
// 不显示命令行窗口
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
// 重定向输出信息,方便捕获处理进度或错误
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
// 绑定输出事件
process.OutputDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
Console.WriteLine("输出信息:" + e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
Console.WriteLine("错误信息:" + e.Data);
}
};
// 启动进程
process.Start();
// 开始异步读取输出
process.BeginOutputReadLine();
process.BeginErrorReadLine();
// 等待进程执行完成
process.WaitForExit();
process.Close();
Console.WriteLine("视频转码完成");
}
}
}
常用视频处理参数说明
FFmpeg的命令行参数非常丰富,以下是C#调用时常用的参数:
- -i:指定输入文件路径,支持本地路径和远程URL
- -y:覆盖已存在的输出文件,无需手动确认
- -ss:指定开始时间,格式为HH:MM:SS或者秒数,例如
-ss 00:00:10表示从第10秒开始处理 - -t:指定处理时长,例如
-t 00:00:30表示处理30秒的内容 - -c:v:指定视频编码器,例如
-c:v libx264使用H.264编码 - -c:a:指定音频编码器,例如
-c:a aac使用AAC编码 - -s:指定输出视频分辨率,格式为宽x高,例如
-s 1280x720 - -vn:只处理音频,不处理视频,用于提取音频
- -an:只处理视频,不处理音频
示例:提取视频中的音频
以下代码实现从MP4视频中提取MP3音频:
string ffmpegPath = @"D:ffmpegbinffmpeg.exe";
string inputVideo = @"D:inputtest.mp4";
string outputAudio = @"D:outputtest.mp3";
// -vn 表示不处理视频,只提取音频,使用libmp3lame编码为MP3格式
string arguments = $"-i "{inputVideo}" -vn -c:a libmp3lame -y "{outputAudio}"";
Process process = new Process();
process.StartInfo.FileName = ffmpegPath;
process.StartInfo.Arguments = arguments;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.ErrorDataReceived += (s, e) =>
{
if (!string.IsNullOrEmpty(e.Data)) Console.WriteLine(e.Data);
};
process.Start();
process.BeginErrorReadLine();
process.WaitForExit();
process.Close();
方法二:使用第三方封装库
如果不想直接处理命令行参数,也可以使用社区封装好的C#调用FFmpeg的库,例如FFmpeg.AutoGen,它是FFmpeg原生API的C#绑定,可以直接调用FFmpeg的底层函数,适合需要更精细控制处理流程的场景。
使用FFmpeg.AutoGen需要先在NuGet中安装对应包,然后引入命名空间,以下是简单的初始化示例:
using FFmpeg.AutoGen;
// 注册FFmpeg的所有组件
ffmpeg.av_register_all();
// 获取FFmpeg版本信息
string version = ffmpeg.av_version_info();
Console.WriteLine("FFmpeg版本:" + version);
不过这种方式的学习成本较高,需要了解FFmpeg的底层API结构,普通业务场景更推荐使用第一种Process类调用的方式。
注意事项
- 调用前需要校验FFmpeg可执行文件是否存在,避免路径错误导致进程启动失败
- 处理大视频文件时,进程执行时间可能较长,建议不要在主线程中调用,避免界面卡死,可以放在后台线程或使用异步方式执行
- 捕获FFmpeg的Error输出非常重要,很多执行错误不会抛出异常,而是输出到Error流中,需要针对性处理
- 如果处理的视频路径包含中文,需要确保命令行参数中的路径用双引号包裹,避免被截断
- Linux或Mac系统调用时,需要给ffmpeg文件添加执行权限,命令为
chmod +x ffmpeg
常见问题处理
问题1:调用时提示找不到ffmpeg.exe?
检查ffmpegPath的路径是否正确,建议先使用绝对路径测试,确认文件确实存在,也可以将ffmpeg.exe放在项目输出目录下,使用相对路径调用。
问题2:转码后视频没有声音?
检查是否误加了-an参数,或者音频编码器设置不正确,确保音频编码参数符合输出格式的要求。
问题3:处理进度如何获取?
FFmpeg的Error输出中会包含时间进度信息,例如time=00:00:15.00,可以解析这部分内容计算处理进度,实现进度条展示。