gpt4 book ai didi

c# - 从 C# 写入两个标准输入管道

转载 作者:行者123 更新时间:2023-12-04 23:11:53 24 4
gpt4 key购买 nike

我正在使用我的 C# 应用程序中的 FFMPEG 从原始未编码帧构建视频流。对于一个输入流,这相当简单:

var argumentBuilder = new List<string>();
argumentBuilder.Add("-loglevel panic");
argumentBuilder.Add("-f h264");
argumentBuilder.Add("-i pipe:");
argumentBuilder.Add("-c:v libx264");
argumentBuilder.Add("-bf 0");
argumentBuilder.Add("-pix_fmt yuv420p");
argumentBuilder.Add("-an");
argumentBuilder.Add(filename);

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

var _ffMpegProcess = new Process();
_ffMpegProcess.EnableRaisingEvents = true;
_ffMpegProcess.OutputDataReceived += (s, e) => { Debug.WriteLine(e.Data); };
_ffMpegProcess.ErrorDataReceived += (s, e) => { Debug.WriteLine(e.Data); };

_ffMpegProcess.StartInfo = startInfo;

Console.WriteLine($"[log] Starting write to {filename}...");

_ffMpegProcess.Start();
_ffMpegProcess.BeginOutputReadLine();
_ffMpegProcess.BeginErrorReadLine();

for (int i = 0; i < videoBuffer.Count; i++)
{
_ffMpegProcess.StandardInput.BaseStream.Write(videoBuffer[i], 0, videoBuffer[i].Length);
}

_ffMpegProcess.StandardInput.BaseStream.Close();
我试图解决的挑战之一是写入两个输入管道,类似于我可以通过引用 pipe:4 从 Node.js 执行此操作的方式。或 pipe:5 .看来我只能直接写入标准输入,但不能将其拆分为“ channel ”。
在 C# 中执行此操作的方法是什么?

最佳答案

根据所写的here在睡个好觉(我梦想可以使用 Stream.CopyAsync 的地方),这是解决方案的骨架:

string pathToFFmpeg = @"C:\ffmpeg\bin\ffmpeg.exe";

string[] inputs = new[] { "video.m4v", "audio.mp3" };

string output = "output2.mp4";

var npsss = new NamedPipeServerStream[inputs.Length];
var fss = new FileStream[inputs.Length];

try
{
for (int i = 0; i < fss.Length; i++)
{
fss[i] = File.OpenRead(inputs[i]);
}

// We use Guid for pipeNames
var pipeNames = Array.ConvertAll(inputs, x => Guid.NewGuid().ToString("N"));

for (int i = 0; i < npsss.Length; i++)
{
npsss[i] = new NamedPipeServerStream(pipeNames[i], PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
}

string pipeNamesFFmpeg = string.Join(" ", pipeNames.Select(x => $@"-i \\.\pipe\{x}"));

using (var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = pathToFFmpeg,
Arguments = $@"-loglevel debug -y {pipeNamesFFmpeg} -c:v copy -c:a copy ""{output}""",
UseShellExecute = false,
}
})
{
Console.WriteLine($"FFMpeg path: {pathToFFmpeg}");
Console.WriteLine($"Arguments: {proc.StartInfo.Arguments}");

proc.EnableRaisingEvents = false;
proc.Start();

var tasks = new Task[npsss.Length];

for (int i = 0; i < npsss.Length; i++)
{
var pipe = npsss[i];
var fs = fss[i];

pipe.WaitForConnection();

tasks[i] = fs.CopyToAsync(pipe)
// .ContinueWith(_ => pipe.FlushAsync()) // Flush does nothing on Pipes
.ContinueWith(x => {
pipe.WaitForPipeDrain();
pipe.Disconnect();
});
}

Task.WaitAll(tasks);

proc.WaitForExit();
}
}
finally
{
foreach (var fs in fss)
{
fs?.Dispose();
}

foreach (var npss in npsss)
{
npss?.Dispose();
}
}
有各种注意点:
  • 并非所有格式都与管道兼容。例如,许多 .mp4 不是,因为它们的 moov 原子位于文件末尾,但 ffmpeg 立即需要它,并且管道不可搜索(ffmpeg 无法到达管道末尾,请阅读 moov atom 然后转到管道的开头)。见 here例如
  • 我在流式传输结束时收到错误消息。该文件似乎是正确的。我不知道为什么。其他一些人发出了信号,但我没有看到任何解释
    \.\pipe\55afc0c8e95f4a4c9cec5ae492bc518a:参数无效
    \.\pipe\92205c79c26a410aa46b9b35eb3bbff6:参数无效
  • 我通常不使用TaskAsync ,所以我不能 100% 确定我写的内容是否正确。此代码不起作用,例如:
    tasks[i] = pipe.WaitForConnectionAsync().ContinueWith(x => fs.CopyToAsync(pipe, 4096)).ContinueWith(...);
    嗯,也许最后一个可以解决:
    tasks[i] = ConnectAndCopyToPipe(fs, pipe);
    接着
    public static async Task ConnectAndCopyToPipe(FileStream fs, NamedPipeServerStream pipe)
    {
    await pipe.WaitForConnectionAsync();
    await fs.CopyToAsync(pipe);
    // await fs.FlushAsync(); // Does nothing
    pipe.WaitForPipeDrain();
    pipe.Disconnect();
    }
  • 关于c# - 从 C# 写入两个标准输入管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65543304/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com