72 votes

Utiliser FFmpeg en .net ?

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

J'ai cherché un peu partout et j'ai trouvé quelques wrappers comme 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 il est LGPL et SharpFFmpeg est GPL. Cependant, il avait un certain nombre d'erreurs de compilation. Il s'avère qu'il a été écrit pour le compilateur mono, j'ai essayé de le compiler avec mono mais je n'ai pas trouvé comment. J'ai alors commencé à corriger manuellement les erreurs de compilation moi-même, mais je suis tombé sur quelques erreurs effrayantes et j'ai pensé que je ferais mieux de les laisser tranquilles. J'ai donc abandonné ffmpeg-sharp.

Ensuite, j'ai regardé SharpFFmpeg et il ressemble à ce que je veux, toutes les fonctions P/Invoked pour moi. Cependant, il est sous GPL ? Les deux fichiers AVCodec.cs et AVFormat.cs ressemblent à des ports de avcodec.c et avformat.c que je pense pouvoir porter moi-même ? Et je n'aurais pas à me soucier de la licence.

Mais je veux que ce soit bien fait avant de commencer à coder. Je devrais :

  1. Écrire ma propre bibliothèque C++ pour interagir avec ffmpeg, puis faire en sorte que mon programme C# communique avec la bibliothèque C++ pour lire/convertir les vidéos, etc.

OU

  1. Porter avcodec.h et avformat.h (est-ce tout ce dont j'ai besoin ?) en C# en utilisant un grand nombre de DllImports et l'écrire entièrement en C# ?

Tout d'abord, sachez que je ne suis pas un grand spécialiste du C++, car je l'utilise rarement, mais j'en sais assez pour me débrouiller. La raison pour laquelle je pense que le numéro 1 pourrait être la meilleure option est que la plupart des tutoriels FFmpeg sont en C++ et que j'aurais également plus de contrôle sur la gestion de la mémoire que si je devais le faire en C#.

Qu'en pensez-vous ? Auriez-vous également des liens utiles (peut-être un tutoriel) pour utiliser FFmpeg ?

0 votes

0 votes

Pourquoi ne pas faire quelque chose comme C# -> DirectShow -> FFMPEG ? Cela peut être hors sujet, mais assurez-vous également que vous ne finissez pas sur ffmpeg.org/shame.html

30voto

tobltobs Points 1523

La question initiale date maintenant de plus de 5 ans. Entre-temps, il existe maintenant une solution pour une solution WinRT à partir de ffmpeg et un échantillon d'intégration de Microsoft .

1 votes

C'est seulement pour Windows, des nouvelles pour une version linux ?

4 votes

Mentionner également qu'il s'agit de Windows 8 ou supérieur.

1 votes

Est-ce que c'est toujours d'actualité ? :)

27voto

Mark Heath Points 22240

Quelques autres wrappers gérés que vous pouvez consulter

L'écriture de vos propres wrappers d'interop peut être un processus long et difficile en .NET. L'écriture d'une bibliothèque C++ pour l'interopérabilité présente certains avantages, notamment celui de simplifier considérablement l'interface avec le code C#. Toutefois, si vous n'avez besoin que d'un sous-ensemble de la bibliothèque, il peut être plus facile de réaliser l'interopérabilité en C#.

0 votes

Salut Mark ! Tout ce dont j'ai besoin est un wrapper qui doit exposer une méthode : public static void Convert(string sourcePath, string targetPath, MediaType mediaType) (MediaType devrait se référer à un enum qui spécifie le type de fichier cible, par exemple AVI, MP4, MP3, etc.), est-ce que ce serait une perte de temps de développer un wrapper juste pour les capacités de conversion de ffmpeg (j'ai juste besoin d'une conversion de base pour que mon appareil puisse lire certains fichiers de formats non supportés). Un indice ? Pouvez-vous me rediriger vers un point de départ ? Est-ce vraiment si simple ? Merci !

0 votes

Il n'y a pas une bibliothèque comme swig pour envelopper automatiquement les détails interop pour vous ?

1 votes

@Shimmy si tout ce que vous voulez faire est de convertir des fichiers, la façon la plus simple de le faire est avec la ligne de commande ffmpeg.

8voto

Tomasz Żmuda Points 454

Vous pouvez utiliser ce paquet nuget :

Install-Package Xabe.FFmpeg

J'essaie de faire un wrapper FFmpeg facile à utiliser et multiplateforme.

Vous trouverez de plus amples informations à ce sujet sur le site Xabe.FFmpeg

Plus d'informations dans documentation

La conversion est simple :

var conversion = await FFmpeg.Conversions.FromSnippet.ToMp4(Resources.MkvWithAudio, output);
await conversion.Start();

5voto

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

Vous pouvez essayer mon wrapper .NET pour FFMpeg : Convertisseur vidéo pour .NET (Je suis un auteur de cette bibliothèque). Il intègre FFMpeg.exe dans la DLL pour un déploiement facile et ne viole pas les règles de la GPL (FFMpeg n'est PAS lié et le wrapper l'invoque dans un processus séparé avec System.Diagnostics.Process).

0 votes

Cela invoque ffmpeg.exe, n'est-ce pas, plutôt que d'utiliser la dll.

1 votes

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien à titre de référence. Les réponses ne comportant qu'un lien peuvent devenir invalides si la page liée change. - De la revue

1 votes

@dingo_d Merci pour la remarque, j'ai ajouté plus de détails à la réponse.

3voto

Bob Points 29

Une solution viable pour Linux et Windows est de s'habituer à utiliser la console ffmpeg dans votre code. J'empile les threads, j'écris une classe de contrôleur de threads simple, puis vous pouvez facilement utiliser toutes les fonctionnalités de ffmpeg que vous voulez utiliser.

A titre d'exemple, cette section contient utilise ffmpeg pour créer une vignette à partir d'un moment que je spécifie.

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

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

C'est la liste des threads que vous exécutez, j'utilise un timer pour mettre en Pole ces threads, vous pouvez aussi mettre en place un événement si le 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 différentes fonctionnalités de ffmpeg, thrd est évidemment le thread.

Une propriété de FfmpegStuff est la classe FilesToProcess, qui est utilisée pour transmettre des informations au processus appelé, et recevoir des informations une fois que le thread s'est 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é quelle vidéo utiliser, prise dans la base de données. fname est utilisé dans d'autres parties de mes fonctions qui utilisent FilesToProcess, mais pas ici. durationSeconds - est rempli par les threads qui ne font que collecter la durée de la vidéo. imgFiles est utilisé pour retourner toutes les vignettes qui ont été créées.

Je ne veux pas m'embourber dans mon code alors que le but est d'encourager l'utilisation de ffmpeg dans des fils facilement contrôlés.

Maintenant nous avons nos pièces que nous pouvons ajouter à notre liste de fils, 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();
        }
    }

Placer vos propres événements dans la classe contrôleur fonctionne bien, mais dans le cadre d'un travail vidéo, lorsque mon propre code n'effectue aucun traitement du fichier vidéo, le fait de polir puis d'invoquer un événement dans la classe contrôleur fonctionne tout aussi bien.

En utilisant cette méthode, j'ai lentement construit à peu près toutes les fonctions vidéo et photo que je pense pouvoir utiliser un jour, toutes contenues dans une seule classe, et cette classe, sous forme de fichier texte, est utilisable sur les versions Lunux et Windows, avec juste un petit nombre de directives de pré-traitement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X