在C#中实现FFmpeg编码进度捕获与进度条更新的可靠方案
在C#中可靠捕获FFmpeg编码进度并更新进度条
你的核心问题是FFmpeg默认将进度日志输出到标准错误流(stderr),但你绑定的是OutputDataReceived事件(对应标准输出流stdout),所以根本接收不到数据。下面是完整的解决方案:
关键修正点
- 改用
ErrorDataReceived事件捕获FFmpeg的stderr输出 - 调用
BeginErrorReadLine()启动异步读取错误流 - 跨线程更新UI(事件回调在非UI线程,直接操作控件会报错)
- 解析FFmpeg的进度行,提取有效进度数据
完整实现代码
int totalFiles = 0; int completedFiles = 0; if (openFileDialog1.ShowDialog() == DialogResult.OK) { totalFiles = openFileDialog1.FileNames.Length; // 全局进度条:追踪总文件完成数 progressBarGlobal.Maximum = totalFiles; progressBarGlobal.Value = 0; foreach (string inputFile in openFileDialog1.FileNames) { string outputFile = Path.Combine(Path.GetDirectoryName(inputFile), $"{Path.GetFileNameWithoutExtension(inputFile)}_encoded{Path.GetExtension(inputFile)}"); // 当前文件编码进度条:0-100% progressBarSingle.Maximum = 100; progressBarSingle.Value = 0; labelStatus.Text = $"正在编码:{Path.GetFileName(inputFile)}"; Process ffmpegProcess = new Process(); ffmpegProcess.StartInfo.FileName = "ffmpeg.exe"; // 添加-v quiet -stats参数,只保留进度统计输出,减少冗余日志 ffmpegProcess.StartInfo.Arguments = $"-i \"{inputFile}\" -c:v libx264 -crf 23 -c:a aac -b:a 128k -v quiet -stats \"{outputFile}\""; ffmpegProcess.StartInfo.CreateNoWindow = true; ffmpegProcess.StartInfo.RedirectStandardError = true; ffmpegProcess.StartInfo.UseShellExecute = false; // 绑定错误流接收事件(FFmpeg进度输出在这里) ffmpegProcess.ErrorDataReceived += (sender, e) => { if (string.IsNullOrEmpty(e.Data)) return; // 匹配总时长和当前编码时间的行 var durationMatch = System.Text.RegularExpressions.Regex.Match(e.Data, @"Duration: (\d+:\d+:\d+\.\d+)"); var timeMatch = System.Text.RegularExpressions.Regex.Match(e.Data, @"time=(\d+:\d+:\d+\.\d+)"); if (durationMatch.Success && timeMatch.Success) { // 解析时长为秒数计算进度 TimeSpan totalDuration = TimeSpan.Parse(durationMatch.Groups[1].Value); TimeSpan currentTime = TimeSpan.Parse(timeMatch.Groups[1].Value); int progress = (int)((currentTime.TotalSeconds / totalDuration.TotalSeconds) * 100); // 跨线程更新UI控件 progressBarSingle.Invoke((Action)(() => { progressBarSingle.Value = progress > 100 ? 100 : progress; })); } }; ffmpegProcess.Start(); ffmpegProcess.BeginErrorReadLine(); ffmpegProcess.WaitForExit(); ffmpegProcess.Close(); // 更新全局进度 completedFiles++; progressBarGlobal.Invoke((Action)(() => { progressBarGlobal.Value = completedFiles; })); } labelStatus.Text = "所有文件编码完成"; }
额外优化建议
- 异常处理:给Process操作添加try-catch块,避免单个文件编码失败导致整个流程中断
- 取消功能:添加取消按钮,调用
ffmpegProcess.Kill()终止当前编码任务 - 细节显示:在标签中同步显示当前文件的进度百分比(如"当前进度:65%"),提升用户体验
内容的提问来源于stack exchange,提问作者sadra hoseini
相关产品推荐
相关产品推荐

