C#执行外部程序并捕获(流)输出 [英] C# execute external program and capture (stream) the output

查看:511
本文介绍了C#执行外部程序并捕获(流)输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我正在使用ffmpeg可执行文件来合并一个文件中的多个文件。
这个命令需要几分钟的时间才能完成,所以我需要一个监视输出的方法,并在GUI上显示一个进度条。



以下stackoverflow主题:





我做了这个代码:

 code>进程ffmpeg = new进程
{
StartInfo =
{
FileName = @d:\tmp\ffmpeg.exe,
Arguments =-f concat -safe 0 -i __sync.txt -c copy output.mp4,
UseShellExecute = fals e,
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完成任务没有任何错误。但是,$ code> Debug.WriteLine(e.Data)从不被调用(在Debug窗口中没有输出)。试图更改为 Console.WriteLine (再次,没有输出)。



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

 进程ffmpeg = new进程
{
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。



所以,在第一个版本之后,在$ code> ffmpeg之后。 BeginOutputReadLine(); ,我包括以下行:
ffmpeg.BeginErrorReadLine();



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



最终代码:

 处理ffmpeg = new进程
{
StartInfo = {
FileName = @d:\tmp\videos\ffmpeg.exe ,
Arguments =-f concat -safe 0 -i __sync.txt -c copy output.mp4,
UseSh ellExecute = 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();


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:

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.

解决方案

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

这篇关于C#执行外部程序并捕获(流)输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆