2010-09-24 20 views
7

Ich bin derzeit auf der Suche nach libavutil, libavformat und libavcodec (alles Teil von FFMpeg) von .NET zugreifen.Gibt es in .NET eine Reihe funktionierender P/Invoke-Deklarationen für FFMpeg, libavutil, libavformat und libavcodec?

Derzeit bekomme ich die libraries from the automated builds of the shared FFMpeg package jede Nacht für Windows 32-Bit durchgeführt.

Ich verwende auch den Code aus der ffmpeg-sharp project. In diesem Projekt habe ich eine Reihe von Klassen entfernt, die nicht kompiliert wurden (sie sind Wrapperklassen, nicht die P/Invoke-Deklarationen).

Der Code kompiliert gut, aber ich habe ein paar Probleme.

Zuerst scheint es, dass der Build von av * .dll die cdecl calling convention verwendet, da ich eine Nummer von PInvokeStackImbalanceException empfing, wenn ich versuche, av_open_input_file aufzurufen. Das war leicht genug, um es richtig arbeiten zu lassen. Die Struktur AVFormatContext ist ausgefüllt.

Danach möchte ich av_find_stream_info anrufen, um Informationen über die Streams in der Datei zu erhalten. Beim Aufruf mit der AVFormatContext abgerufen von dem Aufruf an av_open_input_file wird jedoch eine AccessViolationException ausgelöst, die angibt, dass ich versuche, aus dem geschützten Speicher zu lesen oder zu schreiben.

Hat jemand P/Invoke verwendet, um auf die Bibliotheken libavutil, libavformat und libavcodec dll über P/Invoke zuzugreifen und es zum Laufen gebracht zu haben?

Ich sollte erwähnen, dass die Arbeit mit der Befehlszeilenversion von FFMpeg, während eine Lösung, in diesem Fall keine praktikable Lösung ist, Zugriff über die Bibliotheken erfolgen muss. Der Grund dafür ist, dass ich die Festplatte viel zu sehr durchdrehen muss, um das zu tun, was ich tun muss (ich muss eine Frame-für-Frame-Analyse von einigen sehr hochauflösenden Videos machen) und ich möchte die Festplatte vermeiden so viel wie möglich.

+0

Re: Festplatte Thrashing betrifft, habe ich nur etwas Erfolg mit der Erfassung ffmpeg Ausgang - ja Inhalt, nicht Metadaten - über die Stdout Rohr erreicht. Wenn dies zu Ihrem Szenario passt, gibt es keine Datei und es trifft nicht auf die Festplatte. –

Antwort

2

Das ist, was ich herausgefunden habe - nämlich, eine gute Menge der P/Invoke-Deklarationen im ffmpeg-sharp-Projekt sind falsch. Es gibt eine gute Anzahl von Stellen, an denen sie Strukturen in der Deklaration verwenden, die zurückgemagert werden, aber später an Entallotierungsroutinen übergeben werden müssen.

Da der Zeiger als Teil des Marshalling verloren wurde, verursacht dies die AccessViolationException ausgelöst werden beim Versuch, diese Struktur an andere Methoden übergeben, die einen gültigen Zeiger (wie ein Handle in Windows) akzeptieren. Anstatt sie als undurchsichtig zu behandeln (wie sie es sollten, wie Windows-APIs), ordnen sie die Strukturen zurück und verlieren dabei den Zeiger.

Die Lösung besteht darin, ihre API-Deklarationen so zu ändern, dass sie eine IntPtr übernehmen/zurückgeben und das Marshallen der Strukturen nach Bedarf durchführen, um sie nicht in die P/Invoke-Deklarationen aufzunehmen.

+0

Ich bin jetzt auf der Suche nach einem einfachen .NET-Wrapper, der eine globale Konvertierungsmethode verfügbar machen sollte und ffmpeg verwenden sollte. Ich muss auch jedes Mal, wenn sich der Fortschritt ändert, ein Ereignis auslösen, damit ich es asynchron ausführen und den Benutzer mit einem Prozentsatz benachrichtigen kann. – Shimmy

+0

Jetzt muss ich wirklich fragen: haben sie korrigiert? –

0

Ich habe von diesen Bibliotheken/Projekten entfernt. Alle Informationen, die ich zu der Zeit fand, wiesen auf diejenigen hin, die zu schnell mit neuen Versionen brechen und/oder einfach zu veraltet sind.

Was ich getan habe, war den ffmpeg-Prozess direkt ausgeführt, wie ich auf this answer erwähnt, durch Ändern eines Beispiels in einem Blog-Post, den ich dort verlinke. Bis zu diesem Datum hatten wir keine Probleme damit :)

Wenn das obige nicht für Ihr Szenario funktioniert, viel Glück.

+0

Ich änderte die Frage, aber ich sollte erwähnen, dass die Verwendung der Befehlszeile keine Option ist. Ich müsste die Festplatte viel zu sehr durcheinanderbringen, um das zu tun, was ich tun muss (ich muss eine Frame-für-Frame-Analyse von einigen sehr hochauflösenden Videos machen) und ich möchte die Festplatte so weit wie möglich meiden. – casperOne

+0

Ich habe es nicht getan, aber Sie könnten in der Lage sein, die Ausgabe umzuleiten, um zu vermeiden, auf die Festplatte gehen zu müssen, um es zu greifen – eglasius

+0

Ich habe es herausgefunden, siehe meine Antwort unten. Es ist mehr wie ffmpeg-sharp behandelt P/Invoke. Ich bin in der Lage, Stream/Codec-Informationen aus Dateien im Speicher zu erhalten. – casperOne

0

SharpFFmpeg importiert C++ - Bibliotheken. C++ - Code ist ein nicht verwalteter Code. Es benötigt Zeiger auf den nicht verwalteten Speicher."Marshal" -Klasse bietet eine Methode zum Zuweisen von nicht verwaltetem Speicher. Zum Beispiel:

IntPtr buffer = Marshal.AllocHGlobal(buf.Length + FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE); //buf is a byte array 

Auch, wenn Sie eine verwaltete Variable (alle C# Variable) auf die Funktion senden möchten, müssen Sie Marshal (Kopie) diese Variable auf den nicht verwalteten Speicher.

for (int i = 0; i < buf.Length; i++) 
     Marshal.StructureToPtr(buf[i], buffer + i, true); 

Jetzt können Sie einen Zeiger auf die Funktion senden.

FFmpeg.avcodec_decode_video(codecContextUnmanaged, frame, ref success, buffer, buf.Length); 

Es ist möglich, dass Sie einige nicht verwaltete Strukturen ändern müssen werden. Dazu müssen Sie die Struktur in einen verwalteten Speicher (Marshal.PtrToStructure-Methode) kopieren, dann ändern und erneut in einen nicht verwalteten Speicher kopieren.
Ich wurde von dem gleichen Problem viel gequält. Ich habe es gelöst, aber ich kann das Video sowieso nicht entschlüsseln.)) Ich hoffe meine Lösung wird jedem helfen.