【问题标题】:C# execute external program and capture (stream) the outputC# 执行外部程序并捕获(流)输出
【发布时间】:2017-08-15 02:17:22
【问题描述】:

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

我正在使用 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 的进度。

【问题讨论】:

    标签: c# ffmpeg


    【解决方案1】:

    几周前我在寻找问题的答案时发现了这篇文章。 我试图启动 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 显示如何获取当前的转化百分比。目前,我显示连接视频的输出不起作用,但他们正在处理它。

    【讨论】:

      【解决方案2】:

      我发现了问题。

      由于某种原因,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 版本中是否仍然正确?我在上面尝试了您的代码,ffmpeg 仍然通过错误数据报告进度。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-30
      • 2012-05-09
      • 2023-03-16
      • 1970-01-01
      • 2013-12-23
      • 2013-01-10
      相关资源
      最近更新 更多