C#执行外部程序并捕获(流)输出

我正在制作一个程序来处理一些video文件。

我正在使用ffmpeg可执行文件将多个文件合并到一个文件中。 此命令需要几分钟才能完成,因此,我需要一种方法来“监视”输出,并在GUI上显示进度条。

查看以下stackoverflow主题:

  • 如何解析c#的命令行输出?
  • Process.start:如何获得输出?
  • 操作方法:在C#中执行命令行,获取STD OUT结果

我做了这个代码:

Process ffmpeg = new Process { StartInfo = { FileName = @"d:\tmp\ffmpeg.exe", Arguments = "-f concat -safe 0 -i __sync.txt -c copy output.mp4", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, WorkingDirectory = @"d:\tmp" } } ffmpeg.EnableRaisingEvents = true; ffmpeg.OutputDataReceived += (s, e) => Debug.WriteLine(e.Data); ffmpeg.ErrorDataReceived += (s, e) => Debug.WriteLine($@"Error: {e.Data}"); ffmpeg.Start(); ffmpeg.BeginOutputReadLine(); ffmpeg.WaitForExit(); 

当我运行此代码时,ffmpeg开始合并文件,我可以在Windows任务管理器上看到ffmpeg进程,如果我等待足够长时间,ffmpeg完成作业没有任何错误。 但是,从不调用Debug.WriteLine(e.Data) (调试窗口上没有输出)。 试图改为Console.WriteLine (再次,没有输出)。

所以,在此之后,我尝试了另一个版本:

 Process ffmpeg = new Process { StartInfo = { FileName = @"d:\tmp\ffmpeg.exe", Arguments = "-f concat -safe 0 -i __sync.txt -c copy output.mp4", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, WorkingDirectory = @"d:\tmp" } } ffmpeg.Start(); while (!ffmpeg.StandardOutput.EndOfStream) { var line = ffmpeg.StandardOutput.ReadLine(); System.Diagnostics.Debug.WriteLine(line); Console.WriteLine(line); } ffmpeg.WaitForExit(); 

同样,ffmpeg启动时没有任何错误,但是C#“挂起”在While (!ffmpeg.StandardOutput.EndOfStream)直到ffmpeg完成。

如果我在Windows提示符下执行确切的命令,则会显示许多输出文本,其中包含ffmpeg的进度。

我发现了问题。

出于某种原因,ffmpeg输出stderr的进度,而不是stdout。

所以,在第一个版本上,在ffmpeg.BeginOutputReadLine(); ,我包括以下行: ffmpeg.BeginErrorReadLine();

现在,我可以使用ffmpeg的stderr监视进度。

最终代码:

 Process ffmpeg = new Process { StartInfo = { FileName = @"d:\tmp\videos\ffmpeg.exe", Arguments = "-f concat -safe 0 -i __sync.txt -c copy output.mp4", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, WorkingDirectory = @"d:\tmp\videos\gopro" } }; ffmpeg.EnableRaisingEvents = true; ffmpeg.OutputDataReceived += (s, e) => Debug.WriteLine(e.Data); ffmpeg.ErrorDataReceived += (s, e) => Debug.WriteLine($@"Error: {e.Data}"); ffmpeg.Start(); ffmpeg.BeginOutputReadLine(); ffmpeg.BeginErrorReadLine(); ffmpeg.WaitForExit(); 

几个星期前,当我在寻找问题的答案时,我发现了这篇文章。 我试图启动ffmpeg进程并将参数传递给它,但是做一切都需要很长时间。 此时我使用Xabe.FFmpeg开箱即用,并且不必担心ffmpeg可执行文件,因为它具有下载最新版本的function。

 bool conversionResult = await new Conversion().SetInput(Resources.MkvWithAudio) .AddParameter(String.Format("-f image2pipe -i pipe:.bmp -maxrate {0}k -r {1} -an -y {2}",bitrate, fps, outputfilename)) .Start(); 

这里提供的文档显示了如何获得当前转换百分比。 此时我显示连接video的输出不起作用,但他们正在研究它。