Вы должны войти, чтобы создавать сообщения и темы.

Как работать с потоком который содержит множество файлов?

Здравствуйте господа кодеры и кодерессы).

Проблема следующая. Мне надо конвертировать видео в набор картинок через процесс ffmpeg. Раньше я успешно это делал при помощи следующего кода:

Спойлер

public void VideoToImages1()
{
    var inputFile = @"D:\testVideo.avi";
    var outputFilesPattern = @"D:\image%03d.jpg" style="color: #25d39d !important";
    using (var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            UseShellExecute = false,
            CreateNoWindow = true,
            Arguments = $"-y -i {inputFile} {outputFilesPattern}",
            FileName = "ffmpeg.exe"
        },
        EnableRaisingEvents = true
    })
    {
        process.Start();
        process.WaitForExit();
    }            
}


Теперь же мне необходимо передавать видео через входной Stream и получать данные из выходного Stream. Для этого у меня следующий код. Он полностью рабочий так как я использовал его для конвертации видео и успешно передавал входные данные через Stream и получал выходные данные в через Stream и создавал корректный файл.
Проблема здесь в том что вместо того чтобы создать файлы в директории по указанному паттерну он возвращает эти файлы в потоке. В итоге я не знаю записать все файлы из Stream и как этот выходной обрабатывать так как он содержит множество файлов. В данный момент у меня создается лишь 1 картинка.
При указании выходного паттерна для файлов он ведь создает множество файлов на диске, а при указании выходного канала он ведь все выходные данные отправляет в выходной стрим.
Спойлер

public void VideoToImages2()
{
    var inputFile = @"D:\testVideo.avi";
    var outputFile = @"D:\resultImages.png" style="color: #25d39d !important";
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            RedirectStandardInput = true,
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
            Arguments = "-y -i - -f image2 -",
            FileName = _ffmpeg
        },
        EnableRaisingEvents = true
    };
    process.Start();

    //Write input data to input stream
    var inputTask = Task.Run(() =>
    {
        using (var input = new FileStream(inputFile, FileMode.Open))
        {
            input.CopyTo(process.StandardInput.BaseStream);
            process.StandardInput.Close();
        }
    });

    //Read multiple files from output stream
    var outputTask = Task.Run(() =>
    {
        //Problem here
        using (var output = new FileStream(outputFile, FileMode.Create))
            process.StandardOutput.BaseStream.CopyTo(output);
    });
    Task.WaitAll(inputTask, outputTask);
    process.WaitForExit();
}


Вот мне как раз таки нужно как то эти данные из этого стрима получить. Когда выходным файлом является один файл то его легко считать, куда-то записать или обработать каким то образом. А в этом случае как быть с множеством файлов в выходном потоке? Я пытался искать по документации, нигде информацию не нашел. Дело как раз таки в том как работать с этим выходным потоком.
Помогите пожалуйста.

Комментарий модератора:
Больше не оформляйте так код, пожалуйста. Посмотрите видео: Как оформлять свои темы и комментарии  |  Как делать крутые скриншоты

Привет. Посмотри. Может на мысль наведёт. 

Код

internal class Program
  {
      private const string Pathffmpeg = @"C:\work\Studio\Tests\ffmpeg\bin\ffmpeg.exe";
      private const string PathFile = @"C:\Users\Vikto\OneDrive\Документы\Test.mp4";
      private const string PathOutput = @"C:\Users\Vikto\Desktop\Моя папка на рабочем столе\";

      private static async Task Main()
      {
          await Start(Pathffmpeg, File.ReadAllBytes(PathFile));
          File.WriteAllBytes(@"C:\Users\Vikto\Desktop\8888\a1.avi", Start2(Pathffmpeg, File.ReadAllBytes(PathFile)).ToArray());

         // MemoryStream mstream = Start3(Pathffmpeg, File.ReadAllBytes(PathFile)); 
      }

       private static async Task Start(string pathffmpeg, byte[] write)
      {
          string args = @$"-i pipe:, ""{PathOutput}\%d.png" style="color: #25d39d !important""";
          using Process proc = Process.Start(new ProcessStartInfo()
          {
              FileName = pathffmpeg,
              Arguments = args,
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = false,
          }) ?? throw new NullReferenceException();
          await proc.StandardInput.BaseStream.WriteAsync(write);
          proc.StandardInput.Dispose();
          await proc.WaitForExitAsync();
      }

      private static MemoryStream Start2(string path, byte[] write)
      {

          string args = @$"-i pipe:, -f avi pipe:";
          using Process proc = Process.Start(new ProcessStartInfo()
          {
              FileName = path,
              Arguments = args,
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = true,
              RedirectStandardError = false
          }) ?? throw new NullReferenceException();

          MemoryStream memoryStream = new MemoryStream();

          Parallel.Invoke(async () =>
          {
              await proc.StandardInput.BaseStream.WriteAsync(write);
              await proc.StandardInput.BaseStream.DisposeAsync();
          }, () =>
          {
              proc.StandardOutput.BaseStream.CopyTo(memoryStream);
              proc.Dispose();
          });
          return memoryStream;
      }

       private static MemoryStream Start3(string path, byte[] write)
      {
          string args = @$"-i pipe:, -c:v png -f image2pipe pipe:";
          using Process proc = Process.Start(new ProcessStartInfo()
          {
              FileName = path,
              Arguments = args,
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = true,
              RedirectStandardError = false
          }) ?? throw new NullReferenceException();

          MemoryStream memoryStream = new MemoryStream();

          Parallel.Invoke(async () =>
          {
              await proc.StandardInput.BaseStream.WriteAsync(write);
              await proc.StandardInput.BaseStream.DisposeAsync();
          }, () =>
          {
              proc.StandardOutput.BaseStream.CopyTo(memoryStream);
              proc.Dispose();
          });

          return memoryStream;
        }


Первый вариант из стрима в последовательность png файлов в директории.
Второй вариант как у тебя из стрима в стрим, но только для одиночных файлов.
Если нужно именно и из стрима в стрим, последовательность png без выгрузки на диск. К сожалению я не разобрался до конца. Стрим можно получить, третий вариант, но вопрос его дешифровки остаётся открытым. Насколько я понимаю человек вроде как-то смог этого добиться. Удачи. 🌈

P.S. Твой код там исключение выводит. Достаточно посмотреть в вывод консоли ffmpeg. Можно даже тупо MemoryStream в bitmap запихнуть, и получить как раз один файл png, размера всех изображений(бесполезный).

Лайкнул Overd
Overd
Цитата: Viсtor от 12.01.2023, 07:20

Привет. Посмотри. Может на мысль наведёт. 

Код

 
 
 
 
internal class Program
{
private const string Pathffmpeg = @"C:\work\Studio\Tests\ffmpeg\bin\ffmpeg.exe";
private const string PathFile = @"C:\Users\Vikto\OneDrive\Документы\Test.mp4";
private const string PathOutput = @"C:\Users\Vikto\Desktop\Моя папка на рабочем столе\";
 
private static async Task Main()
{
await Start(Pathffmpeg, File.ReadAllBytes(PathFile));
File.WriteAllBytes(@"C:\Users\Vikto\Desktop\8888\a1.avi", Start2(Pathffmpeg, File.ReadAllBytes(PathFile)).ToArray());
 
// MemoryStream mstream = Start3(Pathffmpeg, File.ReadAllBytes(PathFile));
}
 
private static async Task Start(string pathffmpeg, byte[] write)
{
string args = @$"-i pipe:, ""{PathOutput}\%d.png""";
using Process proc = Process.Start(new ProcessStartInfo()
{
FileName = pathffmpeg,
Arguments = args,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = false,
}) ?? throw new NullReferenceException();
await proc.StandardInput.BaseStream.WriteAsync(write);
proc.StandardInput.Dispose();
await proc.WaitForExitAsync();
}
 
private static MemoryStream Start2(string path, byte[] write)
{
 
string args = @$"-i pipe:, -f avi pipe:";
using Process proc = Process.Start(new ProcessStartInfo()
{
FileName = path,
Arguments = args,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = false
}) ?? throw new NullReferenceException();
 
MemoryStream memoryStream = new MemoryStream();
 
Parallel.Invoke(async () =>
{
await proc.StandardInput.BaseStream.WriteAsync(write);
await proc.StandardInput.BaseStream.DisposeAsync();
}, () =>
{
proc.StandardOutput.BaseStream.CopyTo(memoryStream);
proc.Dispose();
});
return memoryStream;
}
 
private static MemoryStream Start3(string path, byte[] write)
{
string args = @$"-i pipe:, -c:v png -f image2pipe pipe:";
using Process proc = Process.Start(new ProcessStartInfo()
{
FileName = path,
Arguments = args,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = false
}) ?? throw new NullReferenceException();
 
MemoryStream memoryStream = new MemoryStream();
 
Parallel.Invoke(async () =>
{
await proc.StandardInput.BaseStream.WriteAsync(write);
await proc.StandardInput.BaseStream.DisposeAsync();
}, () =>
{
proc.StandardOutput.BaseStream.CopyTo(memoryStream);
proc.Dispose();
});
 
return memoryStream;
}
internal class Program { private const string Pathffmpeg = @"C:\work\Studio\Tests\ffmpeg\bin\ffmpeg.exe"; private const string PathFile = @"C:\Users\Vikto\OneDrive\Документы\Test.mp4"; private const string PathOutput = @"C:\Users\Vikto\Desktop\Моя папка на рабочем столе\"; private static async Task Main() { await Start(Pathffmpeg, File.ReadAllBytes(PathFile)); File.WriteAllBytes(@"C:\Users\Vikto\Desktop\8888\a1.avi", Start2(Pathffmpeg, File.ReadAllBytes(PathFile)).ToArray()); // MemoryStream mstream = Start3(Pathffmpeg, File.ReadAllBytes(PathFile)); } private static async Task Start(string pathffmpeg, byte[] write) { string args = @$"-i pipe:, ""{PathOutput}\%d.png" style="color: #25d39d !important"""; using Process proc = Process.Start(new ProcessStartInfo() { FileName = pathffmpeg, Arguments = args, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = false, }) ?? throw new NullReferenceException(); await proc.StandardInput.BaseStream.WriteAsync(write); proc.StandardInput.Dispose(); await proc.WaitForExitAsync(); } private static MemoryStream Start2(string path, byte[] write) { string args = @$"-i pipe:, -f avi pipe:"; using Process proc = Process.Start(new ProcessStartInfo() { FileName = path, Arguments = args, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = false }) ?? throw new NullReferenceException(); MemoryStream memoryStream = new MemoryStream(); Parallel.Invoke(async () => { await proc.StandardInput.BaseStream.WriteAsync(write); await proc.StandardInput.BaseStream.DisposeAsync(); }, () => { proc.StandardOutput.BaseStream.CopyTo(memoryStream); proc.Dispose(); }); return memoryStream; } private static MemoryStream Start3(string path, byte[] write) { string args = @$"-i pipe:, -c:v png -f image2pipe pipe:"; using Process proc = Process.Start(new ProcessStartInfo() { FileName = path, Arguments = args, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = false }) ?? throw new NullReferenceException(); MemoryStream memoryStream = new MemoryStream(); Parallel.Invoke(async () => { await proc.StandardInput.BaseStream.WriteAsync(write); await proc.StandardInput.BaseStream.DisposeAsync(); }, () => { proc.StandardOutput.BaseStream.CopyTo(memoryStream); proc.Dispose(); }); return memoryStream; }
 
internal class Program
  {
      private const string Pathffmpeg = @"C:\work\Studio\Tests\ffmpeg\bin\ffmpeg.exe";
      private const string PathFile = @"C:\Users\Vikto\OneDrive\Документы\Test.mp4";
      private const string PathOutput = @"C:\Users\Vikto\Desktop\Моя папка на рабочем столе\";

      private static async Task Main()
      {
          await Start(Pathffmpeg, File.ReadAllBytes(PathFile));
          File.WriteAllBytes(@"C:\Users\Vikto\Desktop\8888\a1.avi", Start2(Pathffmpeg, File.ReadAllBytes(PathFile)).ToArray());

         // MemoryStream mstream = Start3(Pathffmpeg, File.ReadAllBytes(PathFile)); 
      }

       private static async Task Start(string pathffmpeg, byte[] write)
      {
          string args = @$"-i pipe:, ""{PathOutput}\%d.png" style="color: #25d39d !important""";
          using Process proc = Process.Start(new ProcessStartInfo()
          {
              FileName = pathffmpeg,
              Arguments = args,
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = false,
          }) ?? throw new NullReferenceException();
          await proc.StandardInput.BaseStream.WriteAsync(write);
          proc.StandardInput.Dispose();
          await proc.WaitForExitAsync();
      }

      private static MemoryStream Start2(string path, byte[] write)
      {

          string args = @$"-i pipe:, -f avi pipe:";
          using Process proc = Process.Start(new ProcessStartInfo()
          {
              FileName = path,
              Arguments = args,
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = true,
              RedirectStandardError = false
          }) ?? throw new NullReferenceException();

          MemoryStream memoryStream = new MemoryStream();

          Parallel.Invoke(async () =>
          {
              await proc.StandardInput.BaseStream.WriteAsync(write);
              await proc.StandardInput.BaseStream.DisposeAsync();
          }, () =>
          {
              proc.StandardOutput.BaseStream.CopyTo(memoryStream);
              proc.Dispose();
          });
          return memoryStream;
      }

       private static MemoryStream Start3(string path, byte[] write)
      {
          string args = @$"-i pipe:, -c:v png -f image2pipe pipe:";
          using Process proc = Process.Start(new ProcessStartInfo()
          {
              FileName = path,
              Arguments = args,
              UseShellExecute = false,
              RedirectStandardInput = true,
              RedirectStandardOutput = true,
              RedirectStandardError = false
          }) ?? throw new NullReferenceException();

          MemoryStream memoryStream = new MemoryStream();

          Parallel.Invoke(async () =>
          {
              await proc.StandardInput.BaseStream.WriteAsync(write);
              await proc.StandardInput.BaseStream.DisposeAsync();
          }, () =>
          {
              proc.StandardOutput.BaseStream.CopyTo(memoryStream);
              proc.Dispose();
          });

          return memoryStream;
        }


Первый вариант из стрима в последовательность png файлов в директории.
Второй вариант как у тебя из стрима в стрим, но только для одиночных файлов.
Если нужно именно и из стрима в стрим, последовательность png без выгрузки на диск. К сожалению я не разобрался до конца. Стрим можно получить, третий вариант, но вопрос его дешифровки остаётся открытым. Насколько я понимаю человек вроде как-то смог этого добиться. Удачи. 🌈

P.S. Твой код там исключение выводит. Достаточно посмотреть в вывод консоли ffmpeg. Можно даже тупо MemoryStream в bitmap запихнуть, и получить как раз один файл png, размера всех изображений(бесполезный).

Спасибо за наводки, кажись я вышел на нужную тропу. Как решу задачу отпишусь.