C#使用FFmpeg冻结处理StandardInput和StandardOutput

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#使用FFmpeg冻结处理StandardInput和StandardOutput相关的知识,希望对你有一定的参考价值。

我正在尝试将一些流传输到ffmpeg并捕获它的输出,以便我可以在我的代码中传递另一个流。这是一个代码示例,它只是在我写入StandardInput.BaseStream后停止进程继续。

internal class Program
    {
        private static void Main(string[] args)
        {
            var inputFile = @"C:Temp	est.mp4";
            var outputFile = @"C:Temp	est.mp3";

            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    Arguments = "-i - -f mp3 -",
                    FileName = "ffmpeg.exe"
                },
                EnableRaisingEvents = true
            };

            process.ErrorDataReceived += (sender, eventArgs) => Console.WriteLine(eventArgs.Data);

            process.Start();
            process.BeginErrorReadLine();

            using (var input = new FileStream(inputFile, FileMode.Open))
            using (var output = new FileStream(outputFile, FileMode.Create))
            {
                input.CopyTo(process.StandardInput.BaseStream);
                process.StandardOutput.BaseStream.CopyTo(output);
            }

            process.WaitForExit();

            Console.WriteLine("done");
            Console.ReadLine();
        }
    }

这个例子与这个问题的答案几乎相同:https://stackoverflow.com/a/8999542/2277280

我究竟做错了什么?为什么这个过程不能继续?具体是ffmpeg吗?

答案

我不得不异步地从stdin和stdout写入和读取以避免死锁。 Wiz和this post的评论让我朝着正确的方向前进!谢谢!关闭StandardInput以使进程结束也很重要。否则它仍会等待更多输入,并且stdout保持打开状态,永远不会完成复制。以下代码在我的场景中完美运行:

private static void Main(string[] args)
        {
            var inputFile = @"C:Temp	est.mp4";
            var outputFile = @"C:Temp	est.mp3";

            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    Arguments = "-i - -f mp3 -",
                    FileName = "ffmpeg.exe"
                },
                EnableRaisingEvents = true
            };

            process.ErrorDataReceived += (sender, eventArgs) =>
            {
                Console.WriteLine(eventArgs.Data);
            };

            process.Start();
            process.BeginErrorReadLine();

            var inputTask = Task.Run(() =>
            {
                using (var input = new FileStream(inputFile, FileMode.Open))
                {
                    input.CopyTo(process.StandardInput.BaseStream);
                    process.StandardInput.Close();
                }
            });

            var outputTask = Task.Run(() =>
            {
                using (var output = new FileStream(outputFile, FileMode.Create))
                {
                    process.StandardOutput.BaseStream.CopyTo(output);
                }
            });


            Task.WaitAll(inputTask, outputTask);

            process.WaitForExit(); 

            Console.WriteLine("done");
            Console.ReadLine();
        }

以上是关于C#使用FFmpeg冻结处理StandardInput和StandardOutput的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 子进程冻结到 FFMPEG

VLC 冻结从使用 ffmpeg 的图像创建的低 1 FPS 视频

ffmpeg concat demuxer 在加入视频时冻结我的视频帧

FFmpeg 视频处理命令备忘

FFmpeg[25] - ffmpeg:libavformat/http.c:1435: error: undefined reference to ‘inflateEnd‘

在SerialPort.Close上C#Winform冻结