C# execute external program and capture (stream) t

2019-04-11 09:46发布

问题:

I'm making a program to work with some video files.

I'm using the ffmpeg executable to merge several files in a single file. This command takes several minutes to finish, so, I need a way to "monitor" the output, and show a progress bar on GUI.

Looking at the following stackoverflow topics:

  • How to parse command line output from c#?
  • Process.start: how to get the output?
  • How To: Execute command line in C#, get STD OUT results

I made this code:

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

When I run this code, the ffmpeg start to merge files, I can see the ffmpeg process on Windows Task Manager, and if I wait long enough, the ffmpeg finish the job without any error. But, the Debug.WriteLine(e.Data) is never called (no output on Debug window). Tried to change to Console.WriteLine too (again, no output).

So, after this, I tried this another version:

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

Again, the ffmpeg is started without any error, but the C# "hangs" on While (!ffmpeg.StandardOutput.EndOfStream) until ffmpeg is finished.

If I execute the exact command on Windows prompt, a lot of output text is showed with progress of ffmpeg.

回答1:

I found the problem.

For some reason, ffmpeg output the progress on stderr, not stdout.

So, on first version, after the ffmpeg.BeginOutputReadLine();, I included the following line: ffmpeg.BeginErrorReadLine();.

Now, I can monitor the progress using the stderr of ffmpeg.

Final code:

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


回答2:

I have found this post few weeks ago when I was looking for answer for my problem. I tried to start ffmpeg process and pass arguments to it but it take sooo long to do everything. At this point I use Xabe.FFmpeg as it doing this out of the box and don't have to worry about ffmpeg executables because have feature to download latest version.

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

There is documentation available here that shows how to get current percent of conversion. At this moment I thing showing output for concatenating videos doesn't work but they are working on it.



标签: c# ffmpeg