Sylens
Sylens

Reputation: 1177

How to transcode a stream of data using FFMpeg (C#)

How can I send in a stream of bytes which is MP3 audio to FFMpeg and get the output to a stream of PCM bytes? I do not want to write the incoming stream to a file and let FFMpeg work on the file. I want the transcoding to happen in real-time.

I am aware that we can pipe in a stream of data to FFMpeg using the pipe command, how can I stream the data from my C# program.

Assuming I have an array of bytes.

Upvotes: 3

Views: 5074

Answers (1)

Sylens
Sylens

Reputation: 1177

To solve this, I have spawned a new FFMpeg process. Then I used the pipe command and sent in the data via standard input, and got the output using the standard output. I then converted the output I received to a byte array. The new byte array is the transcoded data. You can write this byte buffer to a memory stream or a file stream, you can do what you like.

        var startInfo = new ProcessStartInfo('path/to/ffmpeg');
        startInfo.RedirectStandardInput = true;
        startInfo.RedirectStandardOutput = true;
        startInfo.UseShellExecute = false;

        var argumentBuilder = new List<string>();
        argumentBuilder.Add("-loglevel panic"); // this makes sure only data is sent to stdout
        argumentBuilder.Add("-i pipe:.mp3"); //this sets the input to stdin

        // the target audio specs are as follows
        argumentBuilder.Add($"-f wav");
        argumentBuilder.Add("-ac 1");
        argumentBuilder.Add($"-ar 44100");
        argumentBuilder.Add("pipe:1"); // this sets the output to stdout

        startInfo.Arguments = String.Join(" ", argumentBuilder.ToArray());

        _ffMpegProcess = new Process();
        _ffMpegProcess.StartInfo = startInfo;

        _ffMpegProcess.Start();

We have to write the data to the FFMpeg input channel using Standard Input, we can do it like so:

        _ffMpegProcess.StandardInput.BaseStream.Write(byteBuffer);

This will make FFMpeg return the results to the Standard Output, we will need to listen to it now, like so:

        while (true)
        {
            var bytes = new byte[1024]
            var result = await _ffMpegProcess.StandardOutput.BaseStream.ReadAsync(bytes);

            if (result == 0)
            {
               // no data retrieved
            }
            else
            {
               // do something with the data
            }
        }

Upvotes: 7

Related Questions