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

时间:2017-03-22 19:06:31

标签: c# ffmpeg

我制作的程序可以处理一些视频文件。

我使用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)(调试窗口上没有输出)。试图也改为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的进度。

2 个答案:

答案 0 :(得分:5)

我发现了问题。

出于某种原因,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();

答案 1 :(得分:3)

几周前,当我在寻找问题的答案时,我已经找到了这篇文章。 我试图启动ffmpeg进程并将参数传递给它,但是完成所有操作都花了很长时间。此时,我使用Xabe.FFmpeg,因为它是开箱即用的,不必担心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();

here有可用的文档,该文档显示了如何获取当前的转化百分比。目前,我无法显示用于连接视频的输出,但它们正在处理视频。