C#调用ffmpeg录制桌面如何正确停止保存文件并隐藏黑窗口
C# 调用ffmpeg录屏隐藏控制台窗口方案
问题现象
使用C#调用ffmpeg通过gdigrab采集桌面录制视频时,直接调用Process.Close()终止进程会导致录制文件无法正常写入落盘;通过重定向标准输入向ffmpeg发送q键可实现进程正常退出、文件完整保存,但运行过程中会弹出ffmpeg的黑色控制台窗口:
问题根因
- 原代码
ProcessStartInfo.CreateNoWindow属性设为false,该值为true时才能阻止进程创建新控制台窗口 - 未配置
ProcessStartInfo.WindowStyle为隐藏状态 - 初版代码存在配置顺序错误:在调用
Process.Start()方法后才修改UseShellExecute、CreateNoWindow属性,此类启动参数必须在进程启动前设置才会生效 - 初版ffmpeg启动参数存在笔误:
- pix_fmt多了多余空格,会导致像素格式参数解析失败 - 原停止逻辑在发送
q指令后立刻调用Close(),未等待ffmpeg完成文件头、索引写入收尾,仍存在文件损坏风险
修正方案
- 所有进程启动参数全部放在
Process.Start()调用前配置 - 将
CreateNoWindow属性设为true - 将
WindowStyle属性设为ProcessWindowStyle.Hidden - 修正ffmpeg参数的空格笔误
- 发送
q退出指令后,等待进程自然退出,设置合理超时避免程序卡死,最后回收进程资源 - 输出文件名建议添加
.mp4后缀,避免ffmpeg无法识别输出封装格式
修正后完整代码
FFmpeg录制类
using System; using System.Diagnostics; namespace Testings { internal class FFmpeg_Capture { private Process _ffmpegProcess; public FFmpeg_Capture() { _ffmpegProcess = new Process(); } public void Start(string outputFileName, int framerate) { // 回收已有未退出进程 if (_ffmpegProcess != null && !_ffmpegProcess.HasExited) { _ffmpegProcess.Close(); _ffmpegProcess.Dispose(); } _ffmpegProcess = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo { FileName = @"D:\Captured Videos\ffmpeg.exe", WorkingDirectory = @"D:\Captured Videos\", // 隐藏控制台窗口核心配置 UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, // 重定向标准输入用于发送退出指令 RedirectStandardInput = true, Arguments = $"-y -f gdigrab -framerate {framerate} -i desktop -preset ultrafast -pix_fmt yuv420p {outputFileName}" }; _ffmpegProcess.StartInfo = startInfo; _ffmpegProcess.Start(); } public void Stop() { if (_ffmpegProcess == null || _ffmpegProcess.HasExited) { return; } // 写入q指令触发ffmpeg正常退出 _ffmpegProcess.StandardInput.Write('q'); _ffmpegProcess.StandardInput.Flush(); // 最多等待5秒,让ffmpeg完成文件收尾写入 _ffmpegProcess.WaitForExit(5000); // 回收进程资源 _ffmpegProcess.Close(); _ffmpegProcess.Dispose(); } } }
窗体调用逻辑
private bool recordToggle = false; private readonly FFmpeg_Capture record = new FFmpeg_Capture(); private void btnRecord_Click(object sender, EventArgs e) { recordToggle = !recordToggle; if (recordToggle) { btnRecord.Text = "Stop"; // 文件名添加mp4后缀,明确输出格式 record.Start("Testing.mp4", 60); } else { btnRecord.Text = "Record"; record.Stop(); } }
注意事项
- 无需额外将
q转为GBK编码字节写入,直接通过StandardInput.Write写入字符即可被ffmpeg识别 WaitForExit的超时时间可根据实际磁盘写入性能调整,设置超时是为了避免ffmpeg异常卡死时主程序无响应- 若需要获取ffmpeg运行日志,可额外配置重定向标准输出、标准错误流,不会影响窗口隐藏效果
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

