You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中FFmpeg实现管道到管道的音频数据流转问题排查与解决

Fixing FFmpeg Hang When Redirecting Both Input and Output Pipes in C#

What's Causing the Hang?

This is a classic pipe deadlock scenario, and here's why it's happening:

  • When you first run await audioStream.CopyToAsync(ffmpeg.StandardInput.BaseStream), FFmpeg starts processing the incoming audio data immediately and writes the converted PCM to its standard output.
  • Pipe buffers have a fixed size. Once the output buffer fills up, FFmpeg gets blocked trying to write more data—it can't proceed to read more input until there's space in the output buffer.
  • But your code is still waiting for the entire input stream to finish copying before even starting to read the output. So you end up with a standoff: your app waits for input to finish, FFmpeg waits for output buffer space, and nothing moves forward.

When you remove RedirectStandardOutput = true, FFmpeg sends output directly to the console instead of a pipe. The OS handles console output differently (it doesn't block the writing process the same way a full pipe does), so FFmpeg can keep processing until the input is done, hence no hang.

The Fix: Process Input and Output in Parallel

You need to start both the input writing and output reading operations at the same time so they can run in parallel. This prevents the output buffer from filling up and blocking FFmpeg while you're still feeding input. We can use Task.WhenAll to wait for both tasks to complete.

Here's your updated Do method:

async Task Do() { 
    using (var ffmpeg = CreateStream()) { 
        if (ffmpeg == null) return; 

        // Task to handle feeding input to FFmpeg
        var inputTask = Task.Run(async () => {
            using (var audioStream = GetAudioStream()) { 
                await audioStream.CopyToAsync(ffmpeg.StandardInput.BaseStream); 
                ffmpeg.StandardInput.Close(); // Signal FFmpeg there's no more input
            }
        });

        // Task to handle reading output from FFmpeg
        var outputTask = Task.Run(async () => {
            using (var outputStream = CreatePCMStream()) { 
                try { 
                    await ffmpeg.StandardOutput.BaseStream.CopyToAsync(outputStream); 
                } finally { 
                    await outputStream.FlushAsync(); 
                } 
            }
        });

        // Wait for both tasks to finish
        await Task.WhenAll(inputTask, outputTask);

        Console.WriteLine("\n\ndone\n\n");
    } 
}

Extra Tips to Avoid Headaches

  1. Keep Your FFmpeg Arguments Correct: Your current args (-i pipe:0 -f s16le pipe:1) are perfect—they correctly tell FFmpeg to read from stdin and write PCM to stdout, no changes needed here.
  2. Redirect Standard Error Too: FFmpeg might write error messages to stderr, and if you don't redirect that, it can cause another potential deadlock. Add a task to read stderr in the background:
var errorTask = Task.Run(async () => {
    var errorLog = await ffmpeg.StandardError.ReadToEndAsync();
    if (!string.IsNullOrWhiteSpace(errorLog)) {
        Console.WriteLine("FFmpeg Errors:\n" + errorLog);
    }
});

Then add errorTask to the Task.WhenAll call to wait for it alongside input and output tasks.
3. Leverage using Blocks: You're already doing this well, but just a reminder—using ensures streams and the FFmpeg process are properly cleaned up, even if something goes wrong.

With this setup, input and output operations run in parallel, so FFmpeg never gets stuck waiting for output buffer space while you're still sending input. Your app will process the audio without hanging, no intermediate files required.

内容的提问来源于stack exchange,提问作者greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 15:34:10