4

I'm trying to pipe some stream to ffmpeg and capture it's output so that I can pass on another stream in my code. Here is a code example, that just stops the process from continuing after I write to its StandardInput.BaseStream.

internal class Program
    {
        private static void Main(string[] args)
        {
            var inputFile = @"C:\Temp\test.mp4";
            var outputFile = @"C:\Temp\test.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();
        }
    }

This example is pretty much the same as in the answer in this question: https://stackoverflow.com/a/8999542/2277280

What am I doing wrong? Why does the process not continue? Is it ffmpeg specific?

cmxl
  • 663
  • 12
  • 24
  • 1
    You may need to try reading the Standard Output similar to how you have the Error Output - based on the event handler. My guess is that the output buffer is full, since your code doesn't read it until after the input is completed. It is probably in a deadlocked state, where it can't continue the input, but also cannot output any more data to the output buffer. – Wiz Jun 04 '18 at 17:06

1 Answers1

12

I had to write and read from stdin and stdout asynchronously to avoid a deadlock. The comment from Wiz and this post took me in the right direction! Thanks! It was also important to close the StandardInput to make the process end. Otherwise it would still wait for more input and the stdout keeps open and would never finish copying. Following code works perfectly fine in my scenario:

private static void Main(string[] args)
        {
            var inputFile = @"C:\Temp\test.mp4";
            var outputFile = @"C:\Temp\test.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();
        }
cmxl
  • 663
  • 12
  • 24