web-dev-qa-db-fra.com

Utilisation de FFmpeg dans .net?

Je sais donc que c’est un défi de taille, mais je veux écrire un lecteur/convertisseur de base en c # en utilisant la bibliothèque FFmpeg. Cependant, le premier obstacle que je dois surmonter est de placer la bibliothèque FFmpeg dans c #. J'ai téléchargé ffmpeg mais je n'ai pas pu le compiler sous Windows. J'ai donc téléchargé une version précompilée. Ok génial. Ensuite, j'ai commencé à chercher des wrappers en C #.

J'ai regardé autour de moi et j'ai trouvé quelques wrappers tels que SharpFFmpeg ( http://sourceforge.net/projects/sharpffmpeg/ ) et ffmpeg-sharp ( http://code.google .com/p/ffmpeg-sharp / ). Tout d’abord, je voulais utiliser ffmpeg-sharp car sa LGPL et SharpFFmpeg étaient une GPL. Cependant, il y avait quelques erreurs de compilation. Il s’avère qu’il a été écrit pour le compilateur mono, j’ai essayé de le compiler en mono mais je ne savais pas comment. J'ai ensuite commencé à corriger moi-même manuellement les erreurs du compilateur, mais j'en ai rencontré quelques-unes effrayantes et je me suis dit que je devrais mieux les laisser. J'ai donc abandonné le ffmpeg-sharp.

Ensuite, j'ai regardé SharpFFmpeg et cela ressemble à ce que je veux, à toutes les fonctions P/Invoked pour moi. Cependant sa GPL? Les fichiers AVCodec.cs et AVFormat.cs ressemblent tous les deux aux ports de avcodec.c et avformat.c dont je pense pouvoir me porter moi-même? Alors ne pas avoir à se soucier de la licence.

Mais je veux que tout soit clair avant de commencer et de commencer à coder. Devrais-je:

  1. Écrivez ma propre bibliothèque C++ pour interagir avec ffmpeg, puis demandez à mon programme C # de communiquer avec la bibliothèque C++ afin de lire/convertir des vidéos, etc.

OR

  1. Port avcodec.h et avformat.h (est-ce tout ce dont j'ai besoin?) Pour c # en utilisant beaucoup de DllImports et l'écrire entièrement en C #?

Tout d'abord, considérez que je ne suis pas très bon en C++, car je l'utilise rarement, mais j'en sais assez pour me déplacer. La raison pour laquelle je pense que # 1 pourrait être la meilleure option est que la plupart des tutoriels de FFmpeg sont en C++ et que je contrôlerais également davantage la gestion de la mémoire que si je le faisais en c #.

Qu'est-ce que tu penses? De plus, auriez-vous des liens utiles (peut-être un tutoriel) pour utiliser FFmpeg?

61
daniel

La question initiale a maintenant plus de 5 ans. Dans l'intervalle, il existe maintenant une solution pour une solution WinRT de ffmpeg et un exemple d'intégration de Microsoft .

29
tobltobs

quelques autres wrappers gérés à vérifier

Écrire vos propres wrappers interop peut être un processus long et difficile sous .NET. L'écriture d'une bibliothèque C++ pour l'interopérabilité présente certains avantages, notamment parce qu'elle vous permet de simplifier grandement l'interface que le code C #. Toutefois, si vous n'avez besoin que d'un sous-ensemble de la bibliothèque, il vous sera peut-être plus facile de simplement effectuer l'interopérabilité en C #.

23
Mark Heath

Ffmpeg compilé avec la GPL peut être utilisé à partir d'un programme non-GPL (projet commercial) uniquement s'il est appelé dans le processus séparé en tant qu'utilitaire de ligne de commande; tous les wrappers liés à la bibliothèque ffmpeg (y compris FFMpegInterop de Microsoft) peuvent uniquement utiliser la version LGPL de ffmpeg.

Vous pouvez essayer mon wrapper .NET pour FFMpeg: Video Converter for .NET (je suis un auteur de cette bibliothèque). Il incorpore FFMpeg.exe dans le DLL pour un déploiement facile et ne casse pas les règles GPL (FFMpeg n'est PAS lié et l'encapsuleur l'invoque dans le processus séparé avec System.Diagnostics.Process).

5

Vous pouvez utiliser ce paquet de nuget:

Install-Package Xabe.FFmpeg

J'essaie de créer un wrapper FFmpeg multi-plateforme facile à utiliser.

Vous pouvez trouver plus d'informations à ce sujet à Xabe.FFmpeg

Plus d'infos dans documentation

La conversion est simple:

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

Une solution viable à la fois pour Linux et Windows consiste à s’habituer à l’utilisation de la console ffmpeg dans votre code. J'empile des threads, j'écris une simple classe de contrôleur de threads, vous pouvez ensuite utiliser facilement les fonctionnalités de ffmpeg que vous souhaitez utiliser.

Par exemple, cela contient des sections qui utilisent ffmpeg pour créer une miniature à partir d’une heure que je spécifie.

Dans le contrôleur de fil, vous avez quelque chose comme

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

Quelle est la liste des threads que vous exécutez, je me sers d’un minuteur pour pointer ces threads, vous pouvez également configurer un événement si Pole'ing ne convient pas à votre application. Dans ce cas, la classe Thrdffmpeg contient,

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

FFmpegStuff contient les diverses fonctionnalités de ffmpeg, thrd est évidemment le fil.

Une propriété de FfmpegStuff est la classe FilesToProcess, utilisée pour transmettre des informations au processus appelé et recevoir des informations une fois le thread arrêté.

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 (J'utilise une base de données) indique au processus threadé la vidéo à utiliser extraite de la base de données. fname est utilisé dans d'autres parties de mes fonctions qui utilisent FilesToProcess, mais ne sont pas utilisées ici. durationSeconds - est rempli par les threads qui collectent simplement la durée de la vidéo. imgFiles est utilisé pour renvoyer toutes les vignettes créées.

Je ne veux pas m'embourber dans mon code quand il s'agit d'encourager l'utilisation de ffmpeg dans des threads faciles à contrôler.

Maintenant, nous avons nos morceaux que nous pouvons ajouter à notre liste de discussions, donc dans notre contrôleur nous faisons quelque chose comme:

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

Maintenant, Pole'ing nos fils devient une tâche simple,

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

Transférer vos propres événements dans la classe de contrôleur fonctionne bien, mais en vidéo, lorsque mon propre code ne traite en réalité aucun des fichiers vidéo, poler puis invoquer un événement dans la classe de contrôle fonctionne également.

En utilisant cette méthode, j'ai construit lentement à peu près toutes les fonctions de vidéos et de photos que je n'utiliserai jamais, toutes contenues dans la même classe, et cette classe en tant que fichier texte pouvant être utilisée dans les versions Lunux et Windows, avec seulement un petit nombre des directives de pré-traitement.

2
Bob

Vous pouvez essayer un simple wrapper ffmpeg .NET à partir d'ici: http://ivolo.mit.edu/post/Convert-Audio-Video-to-Any-Format-using-C.aspx

2
Ilya