Ответ 1
Оригинальный вопрос теперь более 5 лет. Тем временем теперь есть решение для решения WinRT от ffmpeg и образец интеграции из Microsoft.
Итак, я знаю, что это довольно большая проблема, но я хочу написать базовый проигрыватель фильмов/конвертер в С#, используя библиотеку FFmpeg. Однако первым препятствием, которое мне нужно преодолеть, является обертывание библиотеки FFmpeg в С#. Я загрузил ffmpeg, но не смог скомпилировать его в Windows, поэтому я загрузил предварительно скомпилированную версию для меня. Отлично. Затем я начал искать оболочки С#.
Я просмотрел и нашел несколько оберток, таких как SharpFFmpeg (http://sourceforge.net/projects/sharpffmpeg/) и ffmpeg-sharp (http://code.google.com/p/ffmpeg-sharp/). Прежде всего, я хотел использовать ffmpeg-sharp, поскольку его LGPL и SharpFFmpeg - это GPL. Однако в нем было довольно много ошибок компиляции. Оказывается, это было написано для монокомпилятора, я попытался скомпилировать его с моно, но не мог понять, как это сделать. Затем я начал вручную исправлять ошибки компилятора, но натолкнулся на несколько страшных и подумал, что лучше оставить их в покое. Поэтому я отказался от ffmpeg-sharp.
Затем я посмотрел на SharpFFmpeg, и похоже, что я хочу, все функции P/Invoked для меня. Однако его GPL? Оба файла AVCodec.cs и AVFormat.cs выглядят как порты avcodec.c и avformat.c, которые, как я полагаю, я мог бы портировать? Тогда вам не придется беспокоиться о лицензировании.
Но я хочу получить это право, прежде чем идти вперед и начинать кодирование. Должен ли я:
ИЛИ
Прежде всего, подумайте, что я не очень хорош на С++, поскольку я редко использую его, но я знаю достаточно, чтобы обойти. Причина, по которой я думаю, что № 1 может быть лучшим вариантом, заключается в том, что большинство учебников FFmpeg находятся на С++, и у меня также будет больше контроля над управлением памятью, чем если бы я сделал это в С#.
Как вы думаете? Также у вас возникнут какие-либо полезные ссылки (возможно, учебник) для использования FFmpeg?
Оригинальный вопрос теперь более 5 лет. Тем временем теперь есть решение для решения WinRT от ffmpeg и образец интеграции из Microsoft.
несколько других управляемых оберток для вас, чтобы проверить
Написание собственных оберток для взаимодействия может быть трудоемким и сложным процессом в .NET. Есть несколько преимуществ для написания библиотеки С++ для взаимодействия, в частности, поскольку это позволяет значительно упростить интерфейс, который является кодом С#. Однако, если вам нужно только подмножество библиотеки, это может сделать вашу жизнь проще всего сделать interop в С#.
GPL-скомпилированный ffmpeg может использоваться из программы, отличной от GPL (коммерческий проект), только если он вызывается в отдельном процессе как утилита командной строки; все обертки, связанные с библиотекой ffmpeg (включая Microsoft FFMpegInterop), могут использовать только сборку LGPL ffmpeg.
Вы можете попробовать мою .NET-оболочку для FFMpeg: Video Converter for.NET (я являюсь автором этой библиотеки). Он внедряет FFMpeg.exe в DLL для легкого развертывания и не нарушает правила GPL (FFMpeg НЕ связан, и обертка вызывает его в отдельном процессе с помощью System.Diagnostics.Process).
Вы можете попробовать простую обертку ffmpeg.NET отсюда: http://ivolo.mit.edu/post/Convert-Audio-Video-to-Any-Format-using-C.aspx
Решение, жизнеспособное как для Linux, так и для Windows, - это просто использовать консоль ffmpeg в вашем коде. Я складываю потоки, пишу простой класс контроллера потока, тогда вы можете легко использовать все функциональные возможности ffmpeg, которые хотите использовать.
В качестве примера в этом разделе используются секции ffmpeg для создания эскиза с указанного мной момента времени.
В контроллере потока у вас есть что-то вроде
List<ThrdFfmpeg> threads = new List<ThrdFfmpeg>();
Какой список потоков вы используете, я использую таймер для полюса этих потоков, вы также можете настроить событие, если Pole'ing не подходит для вашего приложения. В этом случае класс Thrdffmpeg содержит,
public class ThrdFfmpeg
{
public FfmpegStuff ffm { get; set; }
public Thread thrd { get; set; }
}
FFmpegStuff содержит различные функциональные возможности ffmpeg, thrd - это, очевидно, поток.
Свойством в FfmpegStuff является класс FilesToProcess, который используется для передачи информации вызываемому процессу и получения информации после остановки потока.
public class FileToProcess
{
public int videoID { get; set; }
public string fname { get; set; }
public int durationSeconds { get; set; }
public List<string> imgFiles { get; set; }
}
VideoID (я использую базу данных) сообщает потоковому процессу, какое видео использовать, взятое из базы данных. fname используется в других частях моих функций, которые используют FilesToProcess, но не используются здесь. durationSeconds - заполняется потоками, которые просто собирают продолжительность видео. imgFiles используется для возврата созданных эскизов.
Я не хочу увязываться в моем коде, когда целью этого является поощрение использования ffmpeg в легко контролируемых потоках.
Теперь у нас есть наши части, которые мы можем добавить в наш список тем, поэтому в нашем контроллере мы делаем что-то вроде
AddThread()
{
ThrdFfmpeg thrd;
FileToProcess ftp;
foreach(FileToProcess ff in `dbhelper.GetFileNames(txtCategory.Text))`
{
//make a thread for each
ftp = new FileToProcess();
ftp = ff;
ftp.imgFiles = new List<string>();
thrd = new ThrdFfmpeg();
thrd.ffm = new FfmpegStuff();
thrd.ffm.filetoprocess = ftp;
thrd.thrd = new `System.Threading.Thread(thrd.ffm.CollectVideoLength);`
threads.Add(thrd);
}
if(timerNotStarted)
StartThreadTimer();
}
Теперь Pole'ing наших потоков становится простой задачей,
private void timerThreads_Tick(object sender, EventArgs e)
{
int runningCount = 0;
int finishedThreads = 0;
foreach(ThrdFfmpeg thrd in threads)
{
switch (thrd.thrd.ThreadState)
{
case System.Threading.ThreadState.Running:
++runningCount;
//Note that you can still view data progress here,
//but remember that you must use your safety checks
//here more than anywhere else in your code, make sure the data
//is readable and of the right sort, before you read it.
break;
case System.Threading.ThreadState.StopRequested:
break;
case System.Threading.ThreadState.SuspendRequested:
break;
case System.Threading.ThreadState.Background:
break;
case System.Threading.ThreadState.Unstarted:
//Any threads that have been added but not yet started, start now
thrd.thrd.Start();
++runningCount;
break;
case System.Threading.ThreadState.Stopped:
++finishedThreads;
//You can now safely read the results, in this case the
//data contained in FilesToProcess
//Such as
ThumbnailsReadyEvent( thrd.ffm );
break;
case System.Threading.ThreadState.WaitSleepJoin:
break;
case System.Threading.ThreadState.Suspended:
break;
case System.Threading.ThreadState.AbortRequested:
break;
case System.Threading.ThreadState.Aborted:
break;
default:
break;
}
}
if(flash)
{//just a simple indicator so that I can see
//that at least one thread is still running
lbThreadStatus.BackColor = Color.White;
flash = false;
}
else
{
lbThreadStatus.BackColor = this.BackColor;
flash = true;
}
if(finishedThreads >= threads.Count())
{
StopThreadTimer();
ShowSample();
MakeJoinedThumb();
}
}
Ввод ваших собственных событий в класс контроллера хорошо работает, но при работе с видео, когда мой собственный код фактически не выполняет какую-либо обработку видеофайлов, также работает проверка, а затем вызов события в контрольном классе.
Используя этот метод, я медленно создавал практически все функции видео и неподвижных изображений, которые, я думаю, когда-либо использовал, все они содержались в одном классе, и этот класс как текстовый файл можно использовать в версиях Lunux и Windows, небольшое количество предпроцессорных директив.
Вы можете использовать этот пакет nuget:
Install-Package Xabe.FFmpeg
Я пытаюсь сделать простую в использовании кросс-платформенную упаковку FFmpeg.
Дополнительную информацию об этом можно найти на https://github.com/tomaszzmuda/Xabe.FFmpeg
Дополнительная информация здесь: https://github.com/tomaszzmuda/Xabe.FFmpeg/wiki/Getting-an-information-about-video
Конверсия проста:
bool result = await ConversionHelper.ToMp4("myVideo.mkv", "output.mp4")
.Start()