web-dev-qa-db-de.com

Verwenden Sie FFmpeg in .net?

Ich weiß, dass es eine ziemlich große Herausforderung ist, aber ich möchte einen einfachen Movie Player/Konverter in c # mit der FFmpeg-Bibliothek schreiben. Das erste Hindernis, das ich überwinden muss, ist das Umschließen der FFmpeg-Bibliothek in c #. Ich habe ffmpeg heruntergeladen, konnte es aber unter Windows nicht kompilieren. Daher habe ich eine vorkompilierte Version für mich heruntergeladen. Ok awesome. Dann fing ich an nach C # Wrappern zu suchen.

Ich habe mich umgesehen und ein paar Wrapper wie SharpFFmpeg ( http://sourceforge.net/projects/sharpffmpeg/ ) und ffmpeg-sharp ( http://code.google) gefunden .com/p/ffmpeg-sharp / ). Zunächst wollte ich ffmpeg-sharp verwenden, da es sich bei LGPL und SharpFFmpeg um GPL handelt. Es hatte jedoch einige Kompilierungsfehler. Es stellte sich heraus, dass es für den Mono-Compiler geschrieben wurde. Ich habe versucht, es mit Mono zu kompilieren, konnte aber nicht herausfinden, wie. Ich fing dann an, die Compiler-Fehler manuell zu beheben, stieß aber auf ein paar beängstigende und dachte, ich sollte diese lieber in Ruhe lassen. Also habe ich ffmpeg-sharp aufgegeben.

Dann habe ich mir SharpFFmpeg angeschaut und es sieht aus wie das was ich will, alle Funktionen P/Invoked für mich. Wie auch immer, die GPL? Die Dateien AVCodec.cs und AVFormat.cs sehen aus wie die Ports avcodec.c und avformat.c, von denen ich denke, dass ich sie selbst portieren könnte? Dann müssen Sie sich nicht um die Lizenzierung kümmern.

Aber ich möchte das richtig machen, bevor ich mit dem Codieren beginne. Sollte ich:

  1. Schreiben Sie eine eigene C++ - Bibliothek für die Interaktion mit ffmpeg, und lassen Sie mein C # -Programm mit der C++ - Bibliothek sprechen, um Videos abzuspielen/zu konvertieren usw.

OR

  1. Port avcodec.h und avformat.h (ist das alles, was ich brauche?), Um c # mit einer ganzen Menge von DllImports und schreiben Sie es vollständig in C #

Zuallererst denke ich, dass ich in C++ nicht besonders gut bin, da ich es selten benutze, aber ich weiß genug, um herumzukommen. Der Grund, warum ich denke, dass # 1 die bessere Option sein könnte, ist, dass die meisten FFmpeg-Tutorials in C++ sind und ich auch mehr Kontrolle über die Speicherverwaltung habe, als wenn ich es in c # machen würde.

Was denkst du? Hätten Sie auch nützliche Links (vielleicht ein Tutorial) für die Verwendung von FFmpeg?

61
daniel

Die ursprüngliche Frage ist jetzt mehr als 5 Jahre alt. Inzwischen gibt es eine Lösung für eine WinRT-Lösung von ffmpeg und ein Integrationsbeispiel von Microsoft .

29
tobltobs

ein paar andere verwaltete Wrapper zum Auschecken

Das Schreiben eigener Interop-Wrapper kann in .NET zeitaufwändig und schwierig sein. Das Schreiben einer C++ - Bibliothek für das Interop bietet einige Vorteile - insbesondere, weil Sie damit die Schnittstelle zum C # -Code erheblich vereinfachen können. Wenn Sie jedoch nur eine Teilmenge der Bibliothek benötigen, ist es möglicherweise einfacher, das Interop in C # auszuführen.

23
Mark Heath

GPL-kompiliertes ffmpeg kann nur aus einem Nicht-GPL-Programm (kommerzielles Projekt) verwendet werden, wenn es im separaten Prozess als Befehlszeilendienstprogramm aufgerufen wird. Alle mit der ffmpeg-Bibliothek verknüpften Wrapper (einschließlich des FFMpegInterop von Microsoft) können nur die LGPL-Version von ffmpeg verwenden.

Sie können meinen .NET-Wrapper für FFMpeg ausprobieren: Video Converter for .NET (Ich bin ein Autor dieser Bibliothek). FFMpeg.exe wird zur einfachen Bereitstellung in die DLL) eingebettet und verstößt nicht gegen GPL-Regeln (FFMpeg ist NICHT verknüpft und der Wrapper ruft es im separaten Prozess mit System.Diagnostics.Process auf).

5

Sie können dieses Nuget-Paket verwenden:

Install-Package Xabe.FFmpeg

Ich versuche, einen benutzerfreundlichen, plattformübergreifenden FFmpeg-Wrapper zu erstellen.

Weitere Informationen hierzu finden Sie unter Xabe.FFmpeg

Weitere Infos in Dokumentation

Die Konvertierung ist einfach:

IConversionResult result = await Conversion.ToMp4(Resources.MkvWithAudio, output).Start();
5
Tomasz Żmuda

Eine für Linux und Windows praktikable Lösung besteht darin, sich an die Verwendung von console ffmpeg in Ihrem Code zu gewöhnen. Ich staple Threads, schreibe eine einfache Thread-Controller-Klasse, dann können Sie ganz einfach die Funktionalität von ffmpeg nutzen, die Sie verwenden möchten.

In diesem Abschnitt wird beispielsweise ffmpeg verwendet, um eine Miniaturansicht aus einem von mir angegebenen Zeitpunkt zu erstellen.

Im Threadcontroller hast du sowas

List<ThrdFfmpeg> threads = new List<ThrdFfmpeg>();

Welches ist die Liste der Threads, die Sie ausführen? Ich verwende einen Zeitgeber, um diese Threads zu polen. Sie können auch ein Ereignis einrichten, wenn das Polen für Ihre Anwendung nicht geeignet ist. In diesem Fall enthält die Klasse Thrdffmpeg,

public class ThrdFfmpeg
{
    public FfmpegStuff ffm { get; set; }
    public Thread thrd { get; set; }
}

FFmpegStuff enthält die verschiedenen ffmpeg-Funktionen, thrd ist offensichtlich der Thread.

Eine Eigenschaft in FfmpegStuff ist die Klasse FilesToProcess, mit der Informationen an den aufgerufenen Prozess übergeben und empfangen werden, sobald der Thread gestoppt wurde.

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 (ich verwende eine Datenbank) teilt dem Thread-Prozess mit, welches Video aus der Datenbank entnommen werden soll. fname wird in anderen Teilen meiner Funktionen verwendet, die FilesToProcess verwenden, aber hier nicht verwendet. durationSeconds - wird von den Threads ausgefüllt, die nur die Videodauer erfassen. Mit imgFiles werden alle erstellten Miniaturansichten zurückgegeben.

Ich möchte nicht in meinem Code hängen bleiben, wenn der Zweck darin besteht, die Verwendung von ffmpeg in leicht zu kontrollierenden Threads zu fördern.

Jetzt haben wir unsere Teile, die wir zu unserer Thread-Liste hinzufügen können, also machen wir in unserem Controller so etwas wie:

        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();
        }

Jetzt wird das Polieren unserer Fäden zu einer einfachen Aufgabe,

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();
        }
    }

Das Übertragen eigener Ereignisse in die Controller-Klasse funktioniert gut, aber in der Videoarbeit funktioniert das Aufrufen eines Ereignisses in der Controlling-Klasse genauso gut, wenn mein eigener Code die Videodateiverarbeitung nicht ausführt.

Mit dieser Methode habe ich so gut wie jede Video- und Standbildfunktion, von der ich glaube, dass sie jemals verwendet wird, langsam aufgebaut. Alle in dieser einen Klasse enthaltenen Funktionen und diese Klasse als Textdatei können in der Lunux- und Windows-Version mit nur einer kleinen Anzahl verwendet werden von Pre-Process-Richtlinien.

2
Bob

Sie können einen einfachen ffmpeg-Wrapper von hier aus ausprobieren: http://ivolo.mit.edu/post/Convert-Audio-Video-to-Any-Format-using-C.aspx

2
Ilya