C#调用FFMPEG时如何获取当前处理帧编号实现进度展示
实现方案
FFMPEG的进度信息默认输出到标准错误流,也可以通过指定参数输出结构化的进度数据,方便直接解析,具体实现步骤如下:
1 调整FFMPEG调用参数
在你现有的加水印FFMPEG命令基础上增加以下参数:
-nostdin:禁用交互输入,避免进程意外挂起-progress -:将结构化进度数据输出到标准输出流,每行格式为key=value,其中直接包含frame字段表示当前处理帧序号
参考完整命令示例:ffmpeg -y -nostdin -i 输入视频路径 -i 水印图片路径 -filter_complex "overlay=10:10" -progress - 输出视频路径
2 C# Process配置要点
需要对Process对象做如下配置,才能捕获实时输出内容:
- 设置
UseShellExecute = false,关闭Shell执行才能重定向进程流 - 设置
RedirectStandardOutput = true(配合上述-progress参数使用),如果没有加-progress参数就设置RedirectStandardError = true解析默认错误流日志 - 设置
EnableRaisingEvents = true,开启进程事件通知 - 注册
OutputDataReceived(对应标准输出)或ErrorDataReceived(对应标准错误)的事件处理方法,实时接收输出行
3 进度解析逻辑
你已经通过ffprobe拿到了视频总帧数totalFrames,在事件处理方法中匹配frame=开头的行,提取当前帧号计算进度即可,参考代码:
// 提前用ffprobe获取的视频总帧数,此处假设已经完成赋值 int totalFrames = 0; Process ffmpegProcess = new Process(); ffmpegProcess.StartInfo.FileName = "ffmpeg.exe"; // 替换为你自己的FFMPEG命令 ffmpegProcess.StartInfo.Arguments = "-y -nostdin -i input.mp4 -i watermark.png -filter_complex \"overlay=10:10\" -progress - output.mp4"; ffmpegProcess.StartInfo.UseShellExecute = false; ffmpegProcess.StartInfo.RedirectStandardOutput = true; ffmpegProcess.StartInfo.CreateNoWindow = true; ffmpegProcess.EnableRaisingEvents = true; // 注册输出事件处理逻辑 ffmpegProcess.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("frame=")) { if (int.TryParse(e.Data.Split('=')[1].Trim(), out int currentFrame) && totalFrames > 0) { double progress = Math.Round((double)currentFrame / totalFrames * 100, 2); // 用\r实现控制台同行刷新进度 Console.Write($"\r处理进度:{progress}% 当前帧:{currentFrame}/{totalFrames}"); } } }; ffmpegProcess.Start(); // 开启异步读取输出流 ffmpegProcess.BeginOutputReadLine(); // 等待处理完成 ffmpegProcess.WaitForExit(); Console.WriteLine("\n视频水印添加完成");
注意事项
- 不要使用同步的
ReadToEnd()方法读取输出流,会阻塞主线程导致进度无法实时更新 - 如果不需要结构化输出,也可以不加
-progress -参数,改为重定向标准错误流、注册ErrorDataReceived事件,同样匹配frame=开头的行即可,错误流还包含处理速度、已处理时长等额外信息 - 计算进度前需要校验总帧数不为0,避免出现除以0的异常
内容的提问来源于stack exchange,提问作者Saghar Francis
相关产品推荐
相关产品推荐

