视频合并是多媒体处理中常见的需求,无论是拼接分段视频、创建视频集锦,还是处理长视频分片,使用 FFmpeg 都是一个高效的解决方案。本文将详细介绍如何使用 C# 和 Xabe.FFmpeg 库实现视频合并。
首先,在 Visual Studio 中安装 Xabe.FFmpeg NuGet 包:
BashInstall-Package Xabe.FFmpeg
确保系统中已安装 FFmpeg:
Windows: 可以使用 Chocolatey
Bash# 使用 Chocolatey
choco install ffmpeg
下载FFmpeg:
HTMLhttps://ffmpeg.org/download.html
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xabe.FFmpeg;
namespace App07
{
public class VideoMerger
{
public async Task MergeVideosAsync(List<string> inputFiles, string outputFile, IProgress<double> progress = null)
{
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
// 首先计算所有视频的总时长
double totalDuration = 0;
foreach (var file in inputFiles)
{
var mediaInfo = await FFmpeg.GetMediaInfo(file);
totalDuration += mediaInfo.Duration.TotalSeconds;
}
string listFilePath = "concat.txt";
using (StreamWriter writer = new StreamWriter(listFilePath))
{
foreach (var file in inputFiles)
{
writer.WriteLine($"file '{file}'");
}
}
var conversion = FFmpeg.Conversions.New()
.AddParameter($"-f concat -safe 0 -i {listFilePath}")
.SetOutput(outputFile)
.SetOverwriteOutput(true);
// 添加进度回调
conversion.OnProgress += (sender, args) =>
{
var progressValue = (args.Duration.TotalSeconds / totalDuration) * 100;
progress?.Report(Math.Min(progressValue, 100)); // 确保进度不超过100%
};
await conversion.Start();
if (File.Exists(listFilePath))
{
File.Delete(listFilePath);
}
}
}
}

C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xabe.FFmpeg;
namespace App07
{
public class VideoMergerAdvanced
{
public enum VideoQuality
{
Low,
Medium,
High,
VeryHigh
}
public async Task MergeVideosAsync(List<string> inputFiles, string outputFile,
VideoQuality quality = VideoQuality.Medium,
IProgress<double> progress = null)
{
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
// 获取第一个视频的信息来确定输出视频的参数
var firstVideoInfo = await FFmpeg.GetMediaInfo(inputFiles[0]);
var videoStream = firstVideoInfo.VideoStreams.First();
var resolution = GetResolution(videoStream.Width, videoStream.Height);
// 根据质量设置比特率
var (videoBitrate, audioBitrate) = GetBitratesByQuality(quality, resolution);
// 计算总时长用于进度显示
double totalDuration = 0;
foreach (var file in inputFiles)
{
var mediaInfo = await FFmpeg.GetMediaInfo(file);
totalDuration += mediaInfo.Duration.TotalSeconds;
}
// 创建concat文件
string listFilePath = "concat.txt";
using (StreamWriter writer = new StreamWriter(listFilePath))
{
foreach (var file in inputFiles)
{
writer.WriteLine($"file '{file}'");
}
}
try
{
var conversion = FFmpeg.Conversions.New()
.AddParameter($"-f concat -safe 0 -i \"{listFilePath}\"")
.AddParameter($"-c:v libx264") // 视频编码器
.AddParameter($"-b:v {videoBitrate}k") // 视频比特率
.AddParameter($"-c:a aac") // 音频编码器
.AddParameter($"-b:a {audioBitrate}k") // 音频比特率
.AddParameter("-preset medium") // 编码预设
.AddParameter("-threads 0") // 使用所有可用线程
.SetOutput(outputFile)
.SetOverwriteOutput(true);
// 添加进度报告
conversion.OnProgress += (sender, args) =>
{
if (totalDuration > 0)
{
var progressValue = (args.Duration.TotalSeconds / totalDuration) * 100;
progress?.Report(Math.Min(progressValue, 100));
}
};
await conversion.Start();
}
finally
{
if (File.Exists(listFilePath))
{
File.Delete(listFilePath);
}
}
}
private (int videoBitrate, int audioBitrate) GetBitratesByQuality(VideoQuality quality, string resolution)
{
switch (quality)
{
case VideoQuality.Low:
return resolution switch
{
"480p" => (1000, 96),
"720p" => (2000, 128),
"1080p" => (4000, 128),
"2K" => (8000, 192),
"4K" => (16000, 192),
_ => (2000, 128)
};
case VideoQuality.Medium:
return resolution switch
{
"480p" => (1500, 128),
"720p" => (3000, 192),
"1080p" => (6000, 192),
"2K" => (12000, 256),
"4K" => (25000, 256),
_ => (3000, 192)
};
case VideoQuality.High:
return resolution switch
{
"480p" => (2000, 192),
"720p" => (4000, 256),
"1080p" => (8000, 256),
"2K" => (16000, 320),
"4K" => (35000, 320),
_ => (4000, 256)
};
case VideoQuality.VeryHigh:
return resolution switch
{
"480p" => (2500, 256),
"720p" => (5000, 320),
"1080p" => (10000, 320),
"2K" => (20000, 320),
"4K" => (45000, 320),
_ => (5000, 320)
};
default:
return (4000, 192); // 默认中等质量
}
}
private string GetResolution(int width, int height)
{
if (width >= 3840 || height >= 2160) return "4K";
if (width >= 2560 || height >= 1440) return "2K";
if (width >= 1920 || height >= 1080) return "1080p";
if (width >= 1280 || height >= 720) return "720p";
return "480p";
}
}
}
视频比特率通常以 kbps(千比特每秒)为单位。常见设置:
// 视频比特率设置示例 .SetVideoBitrate(1000) // 1000 kbps = 1 Mbps
常见分辨率对应的推荐比特率:
音频比特率也是以 kbps 为单位。常见设置:
// 音频比特率设置示例 .SetAudioBitrate(128) // 128 kbps
常见音频比特率选择:

使用C#调用FFmpeg进行视频合并是一个强大而灵活的解决方案。通过合理使用FFmpeg的参数和正确的错误处理,可以实现稳定可靠的视频合并功能。在实际应用中,需要根据具体场景选择合适的合并方案,并注意处理各种边界情况。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!