0

There are two process I am handling. Ffmpeg and fpcalc.

I have completed my appplication by encoding a wav file with ffmpeg, and reading it for purposes of chromaprinting with fpcalc.

However, I think the next step is to skip the saving of a wav file, and pipe the data directly into the fpcalc process.

I've been trying to understand how to pipe the stream data from ffpmeg stdout into the fpcalc process stdin.

Some of the code I've been testing and reading (below) has come from other answers, with regards to piping data out of a Process object in c#, specifically with ffmpeg, found here on Stack

private static void ExtractPCMAudio(string input, int duration)
    {
        Process proc = new Process();

        proc.StartInfo.FileName = @"ffmpeg.exe";
        proc.StartInfo.Arguments = $"-t 00:3:00 -i \"{input}\" -f wav -ac 1 -acodec pcm_s16le -ar 16000 -"; //"-" Dash pipes the stream
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardInput = true;
        proc.StartInfo.RedirectStandardOutput = true;

        proc.Start();

        FileStream baseStream = proc.StandardOutput.BaseStream as FileStream;

        byte[] audioBytes = null;
        int lastRead = 0;

        using (MemoryStream ms = new MemoryStream())
        {            
            byte[] buffer = new byte[4096];
            do
            {
                lastRead = baseStream.Read(buffer, 0, buffer.Length);
                ms.Write(buffer, 0, lastRead);
            } while (lastRead > 0);

            audioBytes = ms.ToArray();
        }
        
        proc.StandardInput.BaseStream.Close();
        
        baseStream.Close();
        FingerPrintAudio(audioBytes);
        Console.WriteLine("Done!");
        
    }


private static void FingerPrintAudio(byte[] audioBytes)
    {
        
        var fpcalc = "fpcalc.exe";
        var procStartInfo =
            new ProcessStartInfo(fpcalc, $" -raw -length 600 -json") 
            {
                RedirectStandardOutput = true,
                RedirectStandardInput = true,
                RedirectStandardError  = true,
                UseShellExecute        = false,
                CreateNoWindow         = true,
            };

        var process = new Process {StartInfo = procStartInfo};
        process.Start();            
        
        process.StandardInput.BaseStream.Write(audioBytes, 0, audioBytes.Length); //<--This is where the piping error happens.

        string processOutput = null;
        using (var sr = new StreamWriter("Test.json"))
        {
            while ((processOutput = process.StandardOutput.ReadLine()) != null)
            {
                sr.WriteLine(processOutput);
                Console.WriteLine(processOutput);
            }
            sr.Close();
        }
        
    }

Throughout many variations of the code, posted above, I seem to encounter an error: 'the pipe has ended'. I think it is a buffering error, where the process handling fpcalc is expecting more byte data, but is cut short?

Perhaps there is a better way to send stream data from one process and use it in a second process?

user2224583
  • 69
  • 1
  • 16
  • Does [this](https://stackoverflow.com/a/1349582/2738151) or [this](https://stackoverflow.com/a/61233837/2738151) answer your question? – Hernán Alarcón Dec 27 '20 at 00:25
  • yes, excellent. I suppose there is more wrong with my code then just piping the stream from one process to another. Thank you these links were indeed exactly what I needed. Now I just have to figure out how to get my fpclac process to accept the stream. – user2224583 Dec 27 '20 at 00:49
  • When you read a stream from a file windows will close the stream when you reach the end of the file. When reading from StandardInput when the application stops executing windows will automatically close the stream. Same doesn't happen when reading from memory stream. You code you have to put following inside the do loop : byte[] buffer = new byte[4096]; and change to byte[] buffer = new byte[buffer.Length]; The issue is with the last chunk where the size is less than 4096. You will read duplicate data left in the buffer from previous read. – jdweng Dec 27 '20 at 00:52

0 Answers0