如何在C#中获取FFmpeg音视频转码任务的处理进度?
实现FFmpeg转码进度监控的可行方案
核心思路
让FFmpeg输出结构化的进度数据,后端实时解析并计算百分比后同步给前端。该方案同时支持音频和视频文件,无需依赖任何FFmpeg封装库。
步骤1:获取输入媒体的总时长
转码进度的核心是当前处理时长 / 总时长,因此需要先获取输入文件的总时长。执行以下FFmpeg命令:
ffmpeg -i "输入文件路径" -show_entries format=duration -v quiet -of csv=p=0
这条命令会直接输出输入媒体的总时长(单位:秒,带小数),音频和视频文件均适用。
在C#中可通过启动临时进程执行该命令,捕获输出并转换为double类型的时长值:
private double GetMediaDuration(string inputPath, string ffmpegPath) { var processStartInfo = new ProcessStartInfo { FileName = ffmpegPath, Arguments = $"-i \"{inputPath}\" -show_entries format=duration -v quiet -of csv=p=0", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(processStartInfo)) { string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); if (double.TryParse(output.Trim(), out double duration)) { return duration; } throw new Exception("无法获取媒体时长"); } }
步骤2:启动转码进程并配置进度输出
启动转码时,添加-progress pipe:1参数,让FFmpeg把进度信息输出到标准输出流(而非默认的标准错误流),方便后端实时读取。完整转码参数示例:
ffmpeg -i "输入文件路径" -c:v libx264 -c:a aac "输出文件路径" -progress pipe:1
步骤3:实时解析进度数据
FFmpeg通过-progress输出的是键值对格式的文本,每行一个条目,例如:
frame=1500 fps=29.97 time=00:00:50.02 bitrate=1234.5kbits/s speed=1.2x ... progress=end
重点解析time字段,将其转换为秒数后,结合步骤1获取的总时长计算进度百分比。
C#中异步读取并解析的示例代码:
private async Task RunTranscodeWithProgress(string inputPath, string outputPath, string ffmpegPath, double totalDuration, Action<double> onProgressUpdated) { var processStartInfo = new ProcessStartInfo { FileName = ffmpegPath, Arguments = $"-i \"{inputPath}\" -c:v libx264 -c:a aac \"{outputPath}\" -progress pipe:1", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(processStartInfo)) { string line; while ((line = await process.StandardOutput.ReadLineAsync()) != null) { if (line.StartsWith("time=")) { string timeStr = line.Split('=')[1].Trim(); // 将时间字符串(如00:00:50.02)转换为秒数 double currentTime = ParseTimeString(timeStr); double progress = Math.Min((currentTime / totalDuration) * 100, 100); onProgressUpdated(progress); } else if (line == "progress=end") { onProgressUpdated(100); break; } } await process.WaitForExitAsync(); } } private double ParseTimeString(string timeStr) { // 拆分时、分、秒 string[] parts = timeStr.Split(':'); double hours = double.Parse(parts[0]); double minutes = double.Parse(parts[1]); double seconds = double.Parse(parts[2]); return hours * 3600 + minutes * 60 + seconds; }
关键注意事项
- 异步读取避免阻塞:必须用异步方式读取标准输出,防止主线程被卡死,同时保证进度实时更新。
- 进度边界处理:计算时要确保进度不会超过100%,转码结束时手动触发100%进度。
- 异常处理:添加进程启动失败、输出解析失败等异常捕获逻辑,避免崩溃。
- 跨场景适配:该方案对本地文件、网络流输入均有效(网络流获取时长时可能需要调整FFmpeg参数,但核心逻辑不变)。
方案优势
- 精度足够:基于媒体时长计算进度,不受编码格式、容器类型影响,音视频通用。
- 实现简单:无需依赖第三方封装库,仅通过FFmpeg原生参数和进程流读取即可完成。
- 实时性好:FFmpeg会频繁输出进度数据,前端可以得到流畅的进度更新。
内容的提问来源于stack exchange,提问作者Aenye_Cerbin
相关产品推荐
相关产品推荐

