Приветствую читатели, в этой статье я бы хотел рассказать о написанной мной OpenSource библиотеке MediaFileProcessor под платформу .NET (.netstandart 2.0). Исходный код доступен на GitHub Данная библиотека является универсальной оболочкой для исполняемых процессов в операционной системе (Windows/Linux).Библиотека позволяет файлам взаимодействовать с процессами через именованные каналы, потоки, массивы байтов и пути в директориях. Так же имеет некоторые полезные функции, такие как возможность декодирования потока на лету и получения из него набора файлов по их сигнатурам. В данной версии(1.0) в библиотеки реализованы оболочки над такими процессами как FFmpeg, ImageMagick и Pandoc.Эту библиотеку так же можно использовать для взаимодействия с сторонними процессами. Сначала расскажу какие мотивы сподвигли меня приступить к написанию данной библиотеки и какие проблемы она решает. В процессе работы над финтех проектом мне пришлось интегрироваться с такими сервисами Amazon  как Rekognition (фото и видео распознавание), Kinesis (передача видеопотока с устройств) и Transcribe(распознавание речи).  Мне необходимо было обрабатывать фото и видеофайлы в процессе взаимодействия с сервисами Amazon. Под обработкой я подразумеваю сжатие и обрезку видеофайлов и изображений, извлечение из видеофайла звуковой дорожки с последующим распознаванием и обработкой голоса, извлечение из видеофайла кадров, конвертация и конкатенация  набора видеофайлов. Обработку медиафайлов приходилось выполнять программно получая данные из сторонних сервисов. Для этого я использовал такие процессы как FFmpeg и ImageMagick. Для тех кто не в курсе  - FFmpeg и ImageMagick это OpenSource проекты для работы с видеофайлами и изображениями, использовать их инструменты приходится через их исполняемые файлы ffmpeg.exe и convert.exe. Конкретно в моем случае мне приходилось запускать эти процессы программно передавая туда аргументы. Проблема была в том что я зачастую имел файлы в виде массива байтов или в виде потоков. Чтобы передать эти файлы в исполняемые процессы мне приходилось физически создавать файлы в директории и передавать пути в качестве аргументов в эту процессы. У исполняемого процесса есть такие  понятия как StandartInput и StandartOutput, это способы взаимодействия с процессом через потоки, т.к. у меня файл был в видео потока я мог не создавать его физически в директории, а вместо этого передать этот поток в StandartInput процесса напрямую. Исполняемый процесс так же может выдать свой результат в виде потока в StandartOutput, а не записывать его физически в директорию. К примеру простейшая команда ffmpeg по конвертации видеофайла из одного формата в другой с получением входного файла через входной поток и выдачу результат в выходной поток. В данном примере у нас лишь один входной аргумент и мы можем передать его в входной поток, а так же результатом будет лишь 1 файл который мы можем получить через выходной поток. Но как быть в том случае когда нам надо передать через потоки 2 входных файла? Пример добавления аудио файла в видеофайл Или к примеру если нам надо извлечь набор кадров в формате jpg из видео в виде потока? В первом случае у нас указано 2 входных аргумента -i - -i - . Но входной поток у нас один, и мы не можем передать 2 потока с данными в один входной поток. Во втором случае исполняемый процесс выдаст нам набор кадров из видео в виде единого потока в выходной поток. Но как нам работать с этим одним потоком который содержит множество файлов. Чтобы решить эти и подобные проблемы я и написал библиотеку MediaFileProcessor. Эта библиотека позволяет передавать данные в любом виде в процессы и обрабатывать их результат. В первом случае, при использовании этой библиотеки потоки файлов будут переданы в входные аргументы в виде поток через именованные каналы (named pipes). Во втором случае библиотека может налету декодировать выходной поток процесса и извлечь файлы из этого потока по отдельности. Так же эта библиотека предоставляет удобную оболочку над вышеуказанными процессами и более того может быть настроена на взаимодействие с сторонним исполняемым процессом.   Ниже представления инструкция по использованию данной библиотеки и ее более подробное описание. После прочтения инструкции вы можете изучить исходный код т.к. он подробно закомментирован и имеет простую архитектуру. В начале следует определить данные для обработки. Данными для обработки является класс MediaFile.  Создать экземпляр данного класса можно из потока, пути к файлу, массива байтов, именованного канала, шаблона именования: При создании экземпляра из пути, именованного канала и шаблона именования необходимо указать тип получения данный через параметр MediaFileInputType. Для обработки видеофайлов средствами FFmpeg необходимо иметь его исполняемый файл ffmpeg.exe.Если вы не хотите скачивать его собственноручно то можете использовать следующий код: await VideoFileProcessor.DownloadExecutableFiles(); Данный код скачает архив по адресу https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip и распокует необходимый ffmpeg.exe в корневую директорию. Ниже представлен пример получения кадра из видео. За обработку видеофайлов средствами ffmpeg отвечает класс VideoFileProcessor. Следует создать его экземпляр: Создание через конструктор без параметров подразумевает что исполняемые файлы ffmpeg.exe и ffprobe.exe находятся в корневой папке. Если вы определили исполняемые файлы в другой директории то создавать экземпляр процессора следует задав пути к исполняемым файлам через конструктор: Чтобы указать как следует обрабатывать файл нам необходимо создать экземпляр VideoProcessingSettings. Далее следует определить конфигурацию для обработки: Далее надо лишь передать конфигурацию в метод  ExecuteAsync: Указанные методы конфигурации выдадут нам следующие аргументы для запуска процесса ffmpeg: -y  -ss 00:00:47.500  -i pathToOutputFile  -frames:v 1  -f image2 pathToInputFile. Необходимо СОБЛЮДАТЬ ПОРЯДОК конфигуарций, т.к. некоторые аргументы должны быть заданы до указания входного аргумента и некоторые после. При настройке конфигурации процесса вы можете задать входные данные используя метод SetInputFiles он принимает массив параметров в виде экземпляров класса MediaFile. Вам следует просто создать экземпляры этого класса из данных представленных в любом виде(путь, поток, байты, каналы, шаблоны) и передать в метод ```SetInputFiles```.  Метод SetOutputArguments отвечает за установку аргумента выходного файла. Через этот метод можно установить путь выходного файла, адрес rtp сервера для трансляции и т.д. Если этот метод не вызывать то это значит что результат обработки будет выдан в StandardOutput в виде потока. И метод ExecuteAsync вернет результат в потоке.  Если же вы установили свой выходной аргумент то StandardOutput будет пустой и ExecuteAsync вернет null. Если вам нужно установить аргумент которого нету в методах конфигурации то вы можете задать кастомные аргументы с помощью метода CustomArguments. Полный код: В текущей версии библиотеки уже реализованы некоторые варианты обработки видеофайлов с помощью ffmpeg: Извлечь кадр из видео  Обрезать видео  Конвертировать видео в набор изображений покадрово  Конвертировать изображения в видео  Извлечь аудиодорожку из видеофайла  Конвертировать в другой формат  Добавить Вотермарку  Удалить звук из видео  Добавить аудиофайл в видеофайл  Конвертировать видео в Gif анимацию  Сжать видео  Сжать изображение  Соединить набор видеофайлов в единый видеофайл  Добавить субтитры  Получить подробную информацию по метаданным видеофайла Ниже представлен пример применения извлечения кадра из видеофайла на определенном тайминге при условии что файл существует ФИЗИЧЕСКИ в директории Ниже представлен пример применения извлечения кадра из видеофайла на определенном тайминге при условии если у нас файл в видео массива байтов Ниже представлен пример применения извлечения кадра из видеофайла на определенном тайминге при условии если у нас файл в видео потока Все остальные методы работают точно также. Вы можете передать файлы в процесс в любом виде и получить в любом видео. Для обработки изображений применяется ImageMagick его класс ImageFileProcessor и его исполняемый файл convert.exe Для загрузки его исполняемого файла можете вызвать следующий код Данный код скачать исполняемый файл в корневую директорию с адреса https://imagemagick.org/archive/binaries/ImageMagick-7.1.0-61-portable-Q16-x64.zip Вся инструкция которая относилась к ffmpeg, так же относится и к ImageMagick. Обработчиком ImageMagick является класс ImageFileProcessor В текущей версии библиотеки уже реализованы некоторые варианты обработки изображений с помощью ImageMagick: Сжать изображение -Конвертировать изображение в другой формат -Изменить размер изображения -Преобразовать набор изображений в Gif анимацию Для обработки документов применяется процесс pandoc.exe, его процессор DocumentFileProcessor. В текущей версии библиотеки уже реализованы некоторые варианты обработки документов с помощью pandoc: -конвертирование файла .docx в .pdf Класс MultiStream предназначен для работы с набором потоков как с единым целлым. Если вам нужно передать множество файлов в единый входной поток процесса, то вам поможет класс MultiStream. К примеру вариант когда ffmpeg должен создать видео из набора изображений, и эти изображения следует передать единым потоком в входной поток процесса. Здесь мы создаем экземпляр класса MultiStream и через метод AddStream добавляем в этот потом несколько потоков с различными файлами. Теперь мы может эти потоки передать в процесс одним потоком в один входной поток Собираем тысячу изображений в один MultiStream и передаем в процесс У класса MultiStream есть метод ReadAsDataArray чтобы получить содержащиеся потоки в виде массивов байтов, и ReadAsStreamArray чтобы получить содержащиеся потоки в виде массива потоков. Когда мы используем функцию ffmpeg по разбиению видеофайла покадрово на изображения то он создает нам в указанной выходной директорию набор изображений. Но что если нам надо получить его результат на в директорию а в выходной поток. В таком случае он в единый выходной поток запищет все изображения полученные из видеофайла. В результате у нас в одном потоке будет множество файлов. Как нам получить эту файлы? Тут на помощь приходит метод расширения  GetMultiStreamBySignature(this Stream stream, byte[] fileSignature).  Этот следует вызвать на потоке который следует декодировать и передать в этот метод в качестве аргумента - сигнатуру извлекаемых файлов. Результатом этого метода будет MultiStream содержащий в себе массив потоков файлов. 1 поток для 1 файла. И уже используя его методы ReadAsDataArray или ReadAsStreamArray мы можем получить эти файлы в виде массива байтов или потоков. Наглядный пример декодирования потока: Для получения сигнатуры определенного формата файла есть метод расширения Если данный метод расширения не поддерживает определение сигнатуры нужного вам формата то дайте мне знать и я максимально быстро исправлю недочет. Если вам необходимо скачать файл то можете использовать статичный метод DownloadFile класса FileDownloadProcessor. Этот метод использует для скачивания не устаревщий WebClient а HttpClient и позволяет в процентах отслеживать прогресс скачивания. Для работы с zip архивами представлен класс ZipFileProcessor. Применения для распаковки скачанного архива ffmpeg и извлечение исполняемых файлов Пожалуй главным классом этой библиотеки является класс MediaFileProcess. Он является универсальной оболочкой для исполняемых процессов. При создании его экземпляра следует задать ему путь/имя исполняемого процесса, аргументы процесса, ProcessingSettings, входные потоки и наименования входных именованных каналов. Если в процесс необходимо передать множество потоков в разные входные аргументы, то в входных аргументам следует указать наименования именованных каналов и передать эти имена и входные потоки в соответствующие аргументы конструктора MediaFileProcess. Это необходимо т.к. в случае передачи разным потоков в разные входные аргументы применяются именованные каналы. Настройку самого исполняемого процесса необходимо выполнить в классе ProcessingSettings. Если при использовании этой библиотеки или при изучении исходного кода вы обнаружите какие либо ошибки то прошу дать мне знать и я постараюсь максимально быстро все поправить.  Спасибо за внимание. Full-Stack .NET Developer