Как кодировать/декодировать видео с помощью С#?
Немного фона, мне была поручена исправление нескольких "маленьких" ошибок и поддержание этого решения для потоковой передачи видео по сети между двумя экземплярами нашего приложения. Решение было написано кем-то, которого больше нет здесь, поэтому в коде есть какая-то тайна, а также некоторые забавные подводные камни. Решение было написано с использованием 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?", немного исследований поможет вам. Поскольку мы говорим об авторском праве, я не могу публиковать полные отрывки кода. Но это должно дать вам архитектурное представление о надежном, быстром кодировании видео с использованием С#.