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

C#执行外部程序并捕获(流式)输出,c#,ffmpeg,C#,Ffmpeg,我正在制作一个程序来处理一些视频文件 我正在使用ffmpeg可执行文件将多个文件合并到一个文件中。 这个命令需要几分钟才能完成,因此,我需要一种方法来“监视”输出,并在GUI上显示进度条 查看以下stackoverflow主题: 我制定了以下代码: Process ffmpeg = new Process { StartInfo = { FileName = @"d:\tmp\ffmpeg.exe", Arguments = "-f concat -safe

我正在制作一个程序来处理一些视频文件

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

查看以下stackoverflow主题:

我制定了以下代码:

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)
(调试窗口上没有输出)。已尝试更改为
控制台。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#“挂起”在ffmpeg完成之前(!ffmpeg.StandardOutput.EndOfStream)

如果在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进程并向其传递参数,但这一切都需要很长时间。在这一点上,我使用as-it来完成这项工作,不必担心ffmpeg可执行文件,因为它具有下载最新版本的功能

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();

有说明如何获取当前转换百分比的可用文档。此时,我想显示用于连接视频的输出不起作用,但他们正在处理它。

对于当前的ffmpeg版本,此块是否仍然正确?我尝试了上面的代码,ffmpeg仍然通过错误数据报告进度。