FFMpeg не может начать использовать API процесса

#c# #ffmpeg #process #ipc

Вопрос:

Поэтому я пытаюсь использовать FFProbe для извлечения мультимедийной информации с помощью API процесса, я нахожусь в сети 5 и хочу оставаться кроссплатформенным. Прежде чем я начал возиться, я попробовал ядро FFMpeg для извлечения метаданных, но оно работает только в Windows и не может обрабатывать многострочные теги, анализируется только последняя строка. Поэтому я попытался вручную передать выходные данные в свое приложение. Первоначально я использовал CliWrap для аккуратной передачи выходных данных в a StringBuilder , как я обычно делаю в других репозиториях.

 var output = new StringBuilder();
var args = new[] { "-i", filePath };
var pResult = await Cli.Wrap(GetFFProbeFilePath())
    .WithArguments(args)
    .WithStandardOutputPipe(PipeTarget.ToStringBuilder(output))
    .ExecuteAsync(cancellationToken);
 
  • filePath : любой медиафайл.
  • GetFFProbeFilePath() : очищает %ПУТЬ% для ffmpeg, возвращает «C:ProgramDatachocolateybinffprobe.exe».
  • cancellationToken : None для тестовых случаев.

Но это не сработало. Вывод всегда остается пустым. Поэтому я выполнил следующую команду, используя не повышенный cmd: C:\ProgramData\chocolatey\bin\ffprobe.exe -i my/lovely/file.mp3 и консоль отображает вывод полностью, без ошибок.

Естественно, это вина CliWrap, потому что я совершенен; вот почему я заменил его простым вызовом API процесса:

 var output = new StringBuilder();
using (var p = new Process())
{
    p.StartInfo.FileName = "C:\ProgramData\chocolatey\bin\ffprobe.exe";
    p.StartInfo.Arguments = String.Join(' ', args);
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();
    output.Append(await p.StandardOutput.ReadToEndAsync());
    await p.WaitForExitAsync(cancellationToken);
}
 

По-прежнему вывод пуст. Поэтому вместо использования канала, который я записываю в вывод файла:

 using var p = new Process();
p.StartInfo.FileName = "C:\ProgramData\chocolatey\bin\ffprobe.exe";
p.StartInfo.Arguments = " -i ""   filePath   "" 2> "   ""C:\temp\metadata.log"";
if (!p.Start())
    throw new Exception();
await p.WaitForExitAsync(cancellationToken);
 
  • C:temp : 777

The temporary file is not created, from that I conclude that the process has not exited successfully. Even though no exception is thrown (I tried piping the errors as well: nothing).

Затем я продолжаю выполнять эту команду 20 раз и задаюсь вопросом, почему она работает в ps amp; cmd, но не в C#:

C:ProgramDatachocolateybinffprobe.exe -i my/lovely/file.mp3 2> "C:tempmetadata.log"

Пока я не запустил его с помощью [Win] [R], и вместо завершения процесса я получил графический сбой и сообщение об ошибке Windows, файл не был создан. После некоторых экспериментов я обнаружил, что то же самое поведение для start команды в cmd.

Почему в имени (вставьте божество предпочтения) есть разница между [Win] [R] и cmd, и почему он выходит из строя при запуске с C#? Как мне преодолеть это странное поведение, сохраняя при этом кросс-платформенную совместимость?

Кстати, все это прекрасно работает в linux.

Изменить: При запуске процесса cmd вручную FFProbe вызывается правильно, но я все еще не получаю никаких данных в выходном конвейере, так cmd.exe как ничего не записывает, и я не могу передать FFProbe.

 var output = new StringBuilder();
_ = await Cli.Wrap("cmd.exe")
   .WithArguments("/C ffprobe -i "my/lovely/file.mp3" 2> "C:\temp\metadata.log"") 
   .WithStandardOutputPipe(PipeTarget.ToStringBuilder(output))
   .ExecuteAsync(cancellationToken);
 

Это фактически создает metadata.log файл, но без вывода , так как я перенаправляю только вывод cmd.exe , а не ffprobe .
Моя текущая мысль заключается в том, что я мог бы открыть a conhost и вручную передать ffprobe выходные данные на вход консоли, явно указав конвейер в аргументах команды, которые опять же не будут работать в linux таким же образом, что противоречит цели.

Комментарии:

1. Вы уверены, что FFProbe записывает свои выходные данные в stdout, а не в stderr? Некоторые программы делают это, особенно когда сообщают о прогрессе или какой-либо другой промежуточной информации. Кроме того, в вашем окончательном редактировании, что произойдет, если вы удалите канал из аргументов ( 2> ... детали) и передадите вывод и ошибку непосредственно через CliWrap?