Использование FFmpeg в .net?

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

Но я хочу получить это право, прежде чем идти вперед и начинать кодирование. Должен ли я:

  • Напишите мою собственную библиотеку С++ для взаимодействия с ffmpeg, затем попросите мою программу С# поговорить с библиотекой С++, чтобы воспроизводить/конвертировать видео и т.д.

ИЛИ

  1. Порт avcodec.h и avformat.h(это все, что мне нужно?) до С#, используя много DllImports и полностью записывая его на С#?

Прежде всего, подумайте, что я не очень хорош на С++, поскольку я редко использую его, но я знаю достаточно, чтобы обойти. Причина, по которой я думаю, что № 1 может быть лучшим вариантом, заключается в том, что большинство учебников FFmpeg находятся на С++, и у меня также будет больше контроля над управлением памятью, чем если бы я сделал это в С#.

Как вы думаете? Также у вас возникнут какие-либо полезные ссылки (возможно, учебник) для использования FFmpeg?

Ответ 1

Оригинальный вопрос теперь более 5 лет. Тем временем теперь есть решение для решения WinRT от ffmpeg и образец интеграции из Microsoft.

Ответ 2

несколько других управляемых оберток для вас, чтобы проверить

Написание собственных оберток для взаимодействия может быть трудоемким и сложным процессом в .NET. Есть несколько преимуществ для написания библиотеки С++ для взаимодействия, в частности, поскольку это позволяет значительно упростить интерфейс, который является кодом С#. Однако, если вам нужно только подмножество библиотеки, это может сделать вашу жизнь проще всего сделать interop в С#.

Ответ 3

GPL-скомпилированный ffmpeg может использоваться из программы, отличной от GPL (коммерческий проект), только если он вызывается в отдельном процессе как утилита командной строки; все обертки, связанные с библиотекой ffmpeg (включая Microsoft FFMpegInterop), могут использовать только сборку LGPL ffmpeg.

Вы можете попробовать мою .NET-оболочку для FFMpeg: Video Converter for.NET (я являюсь автором этой библиотеки). Он внедряет FFMpeg.exe в DLL для легкого развертывания и не нарушает правила GPL (FFMpeg НЕ связан, и обертка вызывает его в отдельном процессе с помощью System.Diagnostics.Process).

Ответ 5

Решение, жизнеспособное как для 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, небольшое количество предпроцессорных директив.

Ответ 6

Вы можете использовать этот пакет 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()