如何通过标准输入向FFmpeg传递多个输入流?
如何通过C#的Process向FFmpeg传递多个输入文件
当你需要用FFmpeg处理多个输入(对应命令行参数-i - -i -)时,直接通过单一的StandardInput流无法实现——FFmpeg会将整个流视为第一个输入的内容,直到流结束才会尝试读取第二个输入,但此时流已关闭,无法写入第二个文件。
最可靠的解决方案是使用命名管道(Named Pipes),为每个输入文件创建独立的管道,让FFmpeg从不同的管道读取数据,实现多输入的独立传递。
修改后的代码示例
using System.IO; using System.IO.Pipes; using System.Diagnostics; using System.Threading.Tasks; public async void MergeVideoAndAudio() { var videoInputPath = @"C:\testvideo.avi"; var audioInputPath = @"C:\testaudio.mp3"; var outputFile = @"C:\outputFile.mp4"; // 创建两个命名管道,分别用于视频和音频输入 using var videoPipe = new NamedPipeServerStream("ffmpeg_video_pipe", PipeDirection.Out, 1, PipeTransmissionMode.Byte); using var audioPipe = new NamedPipeServerStream("ffmpeg_audio_pipe", PipeDirection.Out, 1, PipeTransmissionMode.Byte); var process = new Process { StartInfo = new ProcessStartInfo { RedirectStandardInput = false, // 不再依赖标准输入,改用命名管道 UseShellExecute = false, CreateNoWindow = true, // Windows下命名管道的路径格式为\\.\pipe\[管道名] Arguments = $"-y -i \\\\.\\pipe\\ffmpeg_video_pipe -i \\\\.\\pipe\\ffmpeg_audio_pipe {outputFile}", FileName = _ffmpeg }, EnableRaisingEvents = true }; process.Start(); // 并行向两个管道写入数据 var videoTask = Task.Run(async () => { await videoPipe.WaitForConnectionAsync(); // 等待FFmpeg连接管道 using var videoFile = new FileStream(videoInputPath, FileMode.Open); await videoFile.CopyToAsync(videoPipe); videoPipe.WaitForPipeDrain(); // 确保数据全部写入管道 videoPipe.Close(); // 关闭管道,告知FFmpeg该输入流结束 }); var audioTask = Task.Run(async () => { await audioPipe.WaitForConnectionAsync(); using var audioFile = new FileStream(audioInputPath, FileMode.Open); await audioFile.CopyToAsync(audioPipe); audioPipe.WaitForPipeDrain(); audioPipe.Close(); }); await Task.WhenAll(videoTask, audioTask); process.WaitForExit(); }
关键说明
- 命名管道的优势:每个输入对应独立的数据流,FFmpeg可以分别读取,不会出现流混淆的问题,适用于任意格式的输入文件合并(比如视频+音频)。
- 管道连接逻辑:必须等待FFmpeg与管道建立连接(
WaitForConnectionAsync)后再写入数据,避免数据丢失。 - 流结束标记:写入完成后关闭管道,FFmpeg会识别到该输入流的EOF,继续处理下一个输入。
补充:单一StandardInput流的局限性
如果强行使用单一StandardInput流,仅能通过FFmpeg的concat协议处理同格式的文件,但需要先构造一个文本清单文件传递给FFmpeg,再依次写入实际文件数据,这种方式仅适用于特定场景,通用性远不如命名管道。
内容的提问来源于stack exchange,提问作者Stiven Diplet
相关产品推荐
相关产品推荐

