Как кодировать/декодировать видео с помощью С#?

Немного фона, мне была поручена исправление нескольких "маленьких" ошибок и поддержание этого решения для потоковой передачи видео по сети между двумя экземплярами нашего приложения. Решение было написано кем-то, которого больше нет здесь, поэтому в коде есть какая-то тайна, а также некоторые забавные подводные камни. Решение было написано с использованием ffmpeg с кодом С++, написанным для переноса кода, связанного с кодированием/декодированием, а также с некоторым потоковым кодом. Затем этот С++ был обернут SWIG, чтобы он мог взаимодействовать с С# и передавать видеоролики вверх, где они отображаются, используя VideoRendererElement, который живет в элемент управления WPF. Основная причина, по которой кадры передаются, заключается в том, что у нас есть некоторые пользовательские протоколы, которые нам нужны для отправки видеоданных, и они записываются с использованием С#, так как кадры видео пропускаются, мы обертываем их в наши собственные пакеты и отправляем их на проводе, Это решение работает, и мы можем транслировать видео с помощью наших пользовательских протоколов, хотя это что-то вроде кошмара для поддержания и работы.

Мой вопрос - есть ли лучший способ сделать это? Я ищу способы работать на более низком уровне с видеоданными (на С#), чтобы я мог снимать видеокадры и упаковывать их в свои собственные пакеты, отправлять их и получать и восстанавливать видео на другая сторона. ffmpeg, похоже, является общим решением, но я столкнулся с множеством проблем с ним, и проблема GPL/LGPL, о которой я думаю, является проблемой.

Основной поток, который я ищу, video file → encode → wrap в пакете → передача по проводке по протоколу X → получение видеоданных из пакета → декодирование → рендеринг/сохранение на диск

Ответ 1

DirectShow - ваш друг. DirectShow - это уровень низкого уровня, используемый большинством "мультимедийных" приложений Windows, таких как Media Player, Audio Encoders и т.д.

Даже если эта библиотека была создана для родных разработчиков, вы можете получить доступ к ней из управляемого мира благодаря DirectShow.net. http://directshownet.sourceforge.net Это хорошо известная и стабильная управляемая оболочка для DirectShow.

Единственное, что вам нужно сделать, это немного узнать DirectShow, чтобы понять концепцию графиков и фильтров, а затем создать собственные фильтры и графы, чтобы использовать возможности DirectShow!

Ответ 2

В нашем проекте мы используем Microsoft Expression Encoder. Это не бесплатно. Он может конвертировать видео в разные форматы и размеры, извлекать миниатюры и т.д.

Вот пример:

using Microsoft.Expression.Encoder;

//...
//skiped
//...

MediaItem mediaItem = new MediaItem(videoToEncode.SourceFilePath);
mediaItem.ApplyPreset(PresetFilePath);

Job job = new Job();
job.ApplyPreset(PresetFilePath); // path to preset file, where settings of bit-rate, codec etc
job.MediaItems.Add(mediaItem);

job.EncodeProgress += OnProgress;
job.EncodeCompleted += EncodeCompleted;

job.DefaultMediaOutputFileName = "{OriginalFilename}.encoded.{DefaultExtension}";
job.CreateSubfolder = false;

job.OutputDirectory = videoToEncode.EncodedFilePath;
job.Encode();

Ответ 3

У меня были всевозможные проблемы с использованием ffmpeg, завернутых в DLL. Мой видеопроект был довольно прост - мне просто нужен конвертер, чтобы взять один миниатюру из WMV.

Попробовав только то, что вы описали, моим решением было просто скопировать двоичный файл ffmpeg.exe в мой проект как внешнюю библиотеку. это также аккуратно обойти любые проблемы с лицензированием кода, AFAIK...

        Guid temp = Guid.NewGuid();

        // just throw our ffmpeg commands at cmd.exe
        System.Diagnostics.ProcessStartInfo psi = 
            new System.Diagnostics.ProcessStartInfo("cmd.exe");

        psi.WorkingDirectory = Page.MapPath(@"~\Lib\ffmpeg.rev12665");

        psi.UseShellExecute = false;
        psi.RedirectStandardError = true;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardInput = true;

        System.Diagnostics.Process ps = System.Diagnostics.Process.Start(psi);

        StreamReader outputReader = ps.StandardOutput;
        StreamReader errorReader = ps.StandardError;
        StreamWriter inputWrite = ps.StandardInput;

        // uses extra cheap logging facility
        inputWrite.WriteLine("echo \"Ripping " + copiedFile + " " + 
            temp.ToString() + "\" >> log.txt");

        inputWrite.WriteLine("ffmpeg.exe -i \"" + copiedFile + 
            "\" -f image2 -vframes 1 -y -ss 2 tmp\\" + temp.ToString() + 
            ".jpg");

        inputWrite.WriteLine("exit");

        ps.WaitForExit(3000);

        if (ps.HasExited)
        {
            string thumbFile = Page.MapPath(@"~\Lib\ffmpeg.rev12665\tmp") + 
                @"\" + temp.ToString() + ".jpg";
            // ...
        }

Командная строка ffmpeg может сильно отличаться от моего примера, но это самый стабильный способ, с помощью которого я нашел миниатюры. Другие материалы, которые я нашел в Интернете относительно ffmpeg, специально не имели этого решения (cmd.exe), но это единственный, с которым я хорошо работал. Удачи!

Ответ 4

То, что вы можете попробовать, - SharpFFmpeg. Он лицензирован с использованием GPL, хотя вы можете увидеть, как они написали свою обертку, и вы могли бы написать свой собственный или получить представление о том, как исправить ваше текущее решение.

Изменить:

Там похожая обертка, называемая ffmpeg-sharp на code.google.com, которая использует LGPL - вы можете использовать это в коммерческих Приложения. Я подозреваю, что обе эти обертки делают то же самое, хотя SharpFFmpeg старше и, вероятно, более зрелым.

Ответ 5

Я снова написал VideoRendererElement, когда не было эффективных способов рендеринга видео в WPF (v3.0). Он использует хакерство, чтобы заставить его работать.

Если вы хотите немного упростить ситуацию, отбросьте VRE и используйте InteropBitmap для рендеринга (WriteableBitmap в порядке, но не так эффективен). Также снимите SWIG и сделайте вашу С++ dll библиотекой CLI/С++, таким образом вы можете напрямую поговорить с С++ с С# (и наоборот).

Другой способ, которым вы можете пойти, - просто создать исходный фильтр DirectShow, содержащий ваши материалы для транспорта/декодирования, и вы можете использовать что-то вроде WPF MediaKit сделать рендеринг в WPF (он использует D3DImage. 0 хаки).

Кроме того, не бойтесь LGPL. Пока вы держите его в своей собственной DLL и не меняете источник, вы в пределах лицензионных ограничений.

Ответ 6

Вы также можете посмотреть различные SDK Microsoft Windows Media, доступные для загрузки. В проекте несколько лет назад мы использовали SDK Windows Media Format для извлечения эскизов из загруженного видео. Эти SDK также имеют пример кода .NET.

Ответ 7

Мы конвертируем видеофайлы в различные форматы вывода (divx encoded avi, flv, mp4 и т.д.) для нашего приложения mediadatabase. Поскольку мы всегда работали с CLI-приложениями для преобразования медиа (поговорим о растрировании EPS файлов в JPG с помощью ImageMagick/GS), мы в значительной степени полагались на FFMPEG-CLI.

В нашей специальной среде мы использовали "немые" UNIX-серверы в качестве конверсионных машин (есть только библиотеки sshd, ffmpeg, misc. ffmpeg и samba). Они управляются через CLI PuTTy из С# (веб-сервис WCF) через команды SSH для выполнения реального преобразования.

Вызов ffmpeg происходит через ssh и специализирован для каждого типа TransformationType. Закладка CLI запуска запускается через пространство имен С# System.Diagnostics.Process, события для сообщений о выходе и ошибках обрабатываются для целей ведения журнала.

В Интернете много ресурсов, связанных с такими вопросами, как "Как я могу конвертировать mpg в flv с помощью ffmpeg?", немного исследований поможет вам. Поскольку мы говорим об авторском праве, я не могу публиковать полные отрывки кода. Но это должно дать вам архитектурное представление о надежном, быстром кодировании видео с использованием С#.