使用C#封裝FFmpeg實現視頻格式轉換,你學會了嗎?
作者:iamrick
FFmpeg是一個功能強大的開源多媒體框架,可以用于視頻和音頻的編碼、解碼、轉碼等操作。本文將介紹如何使用C#封裝FFmpeg,實現一個簡單但功能完整的視頻格式轉換工具。
1. 簡介
FFmpeg是一個功能強大的開源多媒體框架,可以用于視頻和音頻的編碼、解碼、轉碼等操作。本文將介紹如何使用C#封裝FFmpeg,實現一個簡單但功能完整的視頻格式轉換工具。
2. 環境準備
- Visual Studio 2022
- .NET 6.0或更高版本
- FFmpeg可執行文件 (ffmpeg.exe) 可以從官網下載:https://ffmpeg.org/download.html
3. 項目實現
3.1 創建FFmpeg包裝類
首先,我們創建一個FFmpegWrapper類來封裝FFmpeg的核心功能:
using System.Diagnostics;
public class FFmpegWrapper
{
private readonly string _ffmpegPath;
// FFmpeg進程執行的事件委托
public delegate void OnProgressHandler(double percentage);
public event OnProgressHandler OnProgress;
// 構造函數
public FFmpegWrapper(string ffmpegPath)
{
_ffmpegPath = ffmpegPath;
if (!File.Exists(_ffmpegPath))
{
throw new FileNotFoundException("FFmpeg executable not found!", _ffmpegPath);
}
}
/// <summary>
/// 獲取視頻信息
/// </summary>
public async Task<VideoInfo> GetVideoInfoAsync(string inputPath)
{
if (!File.Exists(inputPath))
{
throw new FileNotFoundException("Input video file not found!", inputPath);
}
var startInfo = new ProcessStartInfo
{
FileName = _ffmpegPath,
Arguments = $"-i \"{inputPath}\"",
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = startInfo };
process.Start();
string output = await process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
// 解析視頻信息
return ParseVideoInfo(output);
}
/// <summary>
/// 轉換視頻格式
/// </summary>
public async Task ConvertVideoAsync(string inputPath, string outputPath, VideoConversionOptions options)
{
if (!File.Exists(inputPath))
{
throw new FileNotFoundException("Input video file not found!", inputPath);
}
// 構建FFmpeg命令
string arguments = BuildFFmpegArguments(inputPath, outputPath, options);
var startInfo = new ProcessStartInfo
{
FileName = _ffmpegPath,
Arguments = arguments,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = startInfo };
// 添加輸出數據接收處理
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null)
{
UpdateProgress(e.Data);
}
};
process.Start();
process.BeginErrorReadLine();
await process.WaitForExitAsync();
if (process.ExitCode != 0)
{
throw new Exception($"FFmpeg process exited with code {process.ExitCode}");
}
}
/// <summary>
/// 構建FFmpeg命令參數
/// </summary>
private string BuildFFmpegArguments(string inputPath, string outputPath, VideoConversionOptions options)
{
var args = new List<string>
{
"-i", $"\"{inputPath}\"",
"-y" // 覆蓋輸出文件
};
// 添加視頻編碼器
if (!string.IsNullOrEmpty(options.VideoCodec))
{
args.Add("-c:v");
args.Add(options.VideoCodec);
}
// 添加音頻編碼器
if (!string.IsNullOrEmpty(options.AudioCodec))
{
args.Add("-c:a");
args.Add(options.AudioCodec);
}
// 設置視頻比特率
if (options.VideoBitrate > 0)
{
args.Add("-b:v");
args.Add($"{options.VideoBitrate}k");
}
// 設置音頻比特率
if (options.AudioBitrate > 0)
{
args.Add("-b:a");
args.Add($"{options.AudioBitrate}k");
}
// 設置分辨率
if (!string.IsNullOrEmpty(options.Resolution))
{
args.Add("-s");
args.Add(options.Resolution);
}
// 添加輸出文件路徑
args.Add($"\"{outputPath}\"");
return string.Join(" ", args);
}
/// <summary>
/// 更新轉換進度
/// </summary>
private void UpdateProgress(string data)
{
// 解析FFmpeg輸出,計算進度
if (data.Contains("time="))
{
try
{
var timeIndex = data.IndexOf("time=");
var timeStr = data.Substring(timeIndex + 5, 11);
var time = TimeSpan.Parse(timeStr);
// 假設我們已經知道總時長,這里簡化處理
double percentage = (time.TotalSeconds / 100.0) * 100;
OnProgress?.Invoke(Math.Min(percentage, 100));
}
catch
{
// 解析失敗時忽略
}
}
}
/// <summary>
/// 解析視頻信息
/// </summary>
private VideoInfo ParseVideoInfo(string ffmpegOutput)
{
var videoInfo = new VideoInfo();
// 解析時長
var durationMatch = System.Text.RegularExpressions.Regex.Match(ffmpegOutput, @"Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2})");
if (durationMatch.Success)
{
videoInfo.Duration = TimeSpan.Parse($"{durationMatch.Groups[1]}:{durationMatch.Groups[2]}:{durationMatch.Groups[3]}.{durationMatch.Groups[4]}");
}
// 解析分辨率
var resolutionMatch = System.Text.RegularExpressions.Regex.Match(ffmpegOutput, @"(\d{2,4})x(\d{2,4})");
if (resolutionMatch.Success)
{
videoInfo.Width = int.Parse(resolutionMatch.Groups[1].Value);
videoInfo.Height = int.Parse(resolutionMatch.Groups[2].Value);
}
return videoInfo;
}
}
/// <summary>
/// 視頻轉換選項類
/// </summary>
public class VideoConversionOptions
{
public string VideoCodec { get; set; }
public string AudioCodec { get; set; }
public int VideoBitrate { get; set; }
public int AudioBitrate { get; set; }
public string Resolution { get; set; }
}
/// <summary>
/// 視頻信息類
/// </summary>
public class VideoInfo
{
public TimeSpan Duration { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
3.2 使用示例
下面是如何使用FFmpegWrapper類的示例代碼:
static async Task Main(string[] args)
{
try
{
// 初始化FFmpeg包裝器
var ffmpeg = new FFmpegWrapper(@"D:\Software\ffmpeg-master-latest-win64-gpl-shared\bin\ffmpeg.exe");
// 設置進度回調
ffmpeg.OnProgress += (percentage) =>
{
Console.WriteLine($"轉換進度: {percentage:F2}%");
};
// 獲取視頻信息
string inputPath = @"D:\Video\1.mp4";
var videoInfo = await ffmpeg.GetVideoInfoAsync(inputPath);
Console.WriteLine($"視頻時長: {videoInfo.Duration}");
Console.WriteLine($"分辨率: {videoInfo.Width}x{videoInfo.Height}");
// 設置轉換選項
var options = new VideoConversionOptions
{
VideoCodec = "libx264", // H.264編碼
AudioCodec = "aac", // AAC音頻編碼
VideoBitrate = 2000, // 2000kbps視頻比特率
AudioBitrate = 128, // 128kbps音頻比特率
Resolution = "1280x720" // 720p分辨率
};
// 執行轉換
string outputPath = @"D:\output.mkv";
await ffmpeg.ConvertVideoAsync(inputPath, outputPath, options);
Console.WriteLine("視頻轉換完成!");
}
catch (Exception ex)
{
Console.WriteLine($"錯誤: {ex.Message}");
}
}
圖片
4. 常見視頻轉換場景
4.1 轉換為MP4格式
var options = new VideoConversionOptions
{
VideoCodec = "libx264",
AudioCodec = "aac",
VideoBitrate = 2000,
AudioBitrate = 128
};
await ffmpeg.ConvertVideoAsync("input.avi", "output.mp4", options);
4.2 轉換為WebM格式
var options = new VideoConversionOptions
{
VideoCodec = "libvpx-vp9",
AudioCodec = "libvorbis",
VideoBitrate = 1500,
AudioBitrate = 128
};
await ffmpeg.ConvertVideoAsync("input.mp4", "output.webm", options);
4.3 壓縮視頻
var options = new VideoConversionOptions
{
VideoCodec = "libx264",
AudioCodec = "aac",
VideoBitrate = 1000, // 降低比特率
Resolution = "1280x720" // 降低分辨率
};
await ffmpeg.ConvertVideoAsync("input.mp4", "compressed.mp4", options);
5. 總結
本文介紹了如何使用C#封裝FFmpeg實現視頻格式轉換功能。通過封裝,我們可以:
- 更方便地調用FFmpeg功能
- 監控轉換進度
- 獲取視頻信息
- 靈活設置轉換參數
這個實現可以作為基礎,根據實際需求進行擴展,比如添加更多的轉換選項、支持更多的格式等。
責任編輯:武曉燕
來源:
技術老小子