Encapsuleur FFmpeg solide pour C # /. NET


91

Je cherche depuis un certain temps sur le Web un wrapper FFmpeg solide pour C # /. NET . Mais je n'ai pas encore trouvé quelque chose d'utile. J'ai trouvé les trois projets suivants, mais ils semblent tous morts au début de la phase alpha.

FFmpeg.NET
ffmpeg-sharp
FFLIB.NET

Ma question est donc de savoir si quelqu'un connaît un projet de wrapper plus mature?
Je ne recherche pas un moteur de transcodage complet avec des files d'attente de travaux et plus encore. Juste un simple wrapper pour ne pas avoir à faire un appel de ligne de commande, puis analyser la sortie de la console, mais je peux faire des appels de méthode et utiliser des écouteurs d'événements pour progresser.

Et n'hésitez pas à mentionner tous les projets actifs, même s'ils en sont encore à leurs débuts.



1
Quelque chose de nouveau avec ça? Votre emballage a-t-il progressé?
Avi

3
@Lillemanden avez-vous déjà publié ou open source votre wrapper?
Nick Benedict

Il est intéressant de noter que la question a presque 6 ans mais que l'OP (@JacobPoulRichardt) n'a accepté aucune des réponses.
Ofer Zelig

1
J'ai fini par utiliser un wrapper que j'ai créé moi-même, et en tant que tel, je n'ai utilisé aucun des projets suggérés. Comme je ne travaille plus avec ffmpeg, je n'ai pas eu le temps de revenir en arrière et d'essayer l'un d'entre eux non plus. Mais j'ai voté pour la plupart des réponses après les avoir écrémées. Je ne pense donc pas vraiment pouvoir dire que l'une des réponses soit plus «correcte» que les autres.
Jacob Poul Richardt

Réponses:


24

Ceci est mon propre wrapper: https://github.com/AydinAdn/MediaToolkit

MediaToolkit peut:

  • Convertissez les fichiers vidéo en divers autres formats vidéo.
  • Effectuer des tâches de transcodage vidéo.
    • Options configurables: Bit rate, Frame rate, Resolution / size, Aspect ratio,Duration of video
  • Effectuer des tâches de transcodage audio.
    • Options configurables: Audio sample rate
  • Convertissez la vidéo en formats physiques en utilisant les normes TV FILM, PAL ou NTSC
    • Médiums comprennent: DVD, DV, DV50, VCD,SVCD

Je le mets à jour au fur et à mesure, et vous êtes invités à l'utiliser, vous pouvez également l'installer à l'aide de la console du gestionnaire de packages.

PM> Install-Package MediaToolkit

Votre boîte à outils peut-elle multiplexer / rendre différents clips vidéo et audio dans une résolution de sortie donnée?
Antonio Petricca

Non, il a été conçu pour être utilisé par les personnes recherchant des conversions simples. Cela dit, la v2 sera bientôt disponible, ce qui vous permettra de faire tout ce que FFmpeg a à vous proposer.
Aydin

Merci Aydin, tenez-moi au courant de cette nouvelle version.
Antonio Petricca

Ça a l'air fabuleux! Bon travail jusqu'à présent!
SpoiledTechie.com

Hey Aydin, cela peut-il aussi enregistrer l'écran?
TEK

14

Après avoir essayé plusieurs wrappers, je suis allé avec ceci: FFmpeg a généré automatiquement des liaisons non sécurisées pour C # /. NET et Mono .

C'est un ensemble de liaisons d'interopérabilité de bas niveau pour chaque classe de l'espace de noms FFmpeg. Peut-être pas aussi pratique à utiliser qu'un véritable wrapper, mais IMO c'est la meilleure solution pour travailler avec FFmpeg dans .Net, si vous voulez faire des choses non triviales.

Avantages:

  • Travaux
  • Digne de confiance - pas de code wrapper tiers pour introduire des bogues, en supposant que vous faites confiance à FFMpeg lui-même.
  • Il est toujours mis à jour avec la dernière version de FFmpeg
  • Package de nuget unique pour toutes les liaisons
  • La documentation XML est incluse mais vous pouvez toujours utiliser la documentation en ligne FFmpeg .

Les inconvénients:

  • Niveau bas: vous devez savoir travailler avec des pointeurs vers des structures c .
  • Nécessite un peu de travail au départ pour le faire fonctionner. Je suggère d'apprendre des exemples officiels .

Remarque: ce fil concerne l'utilisation de l'API FFmpeg, mais pour certains cas d'utilisation, il est préférable d'utiliser simplement l' interface de ligne de commande de ffmpeg.exe .


Avez-vous réussi à l'utiliser à partir d'un projet qui est ciblé pour .Net Framework (pas de base)? Je ne suis pas sûr de ce qui me manque ici
Yoav Feuerstein

@YoavFeuerstein Oui.
orca


10

J'ai utilisé FFmpeg à partir d'une application de service ASP.NET / Windows (.NET). Mais j'ai fini par utiliser la ligne de commande, sans analyser la console. En utilisant ceci - j'avais un moyen facile de contrôler - les mises à jour de FFmpeg et en exécutant plusieurs conversions sur plusieurs cœurs.


Ok, j'ai commencé sur quelque chose de similaire. Mais j'espère toujours que quelqu'un aura une meilleure solution.
Jacob Poul Richardt

4

Vous pouvez utiliser ce package nuget:

Je sais que vous avez posé des questions sur un projet mature , mais je n'ai vu aucun projet répondre à mes attentes, alors j'ai décidé de créer le mien. Vous pouvez facilement mettre en file d'attente les conversions et les exécuter en parallèle, des méthodes pour convertir les médias en différents formats, envoyer vos propres arguments à ffmpeg et analyser la sortie de l'écouteur d'événements ffmpeg + avec la progression actuelle.

Install-Package Xabe.FFmpeg

J'essaie de créer un wrapper FFmpeg multiplateforme facile à utiliser.

Vous pouvez trouver plus d'informations à ce sujet sur https://xabe.net/product/xabe_ffmpeg/

Plus d'informations ici: https://xabe.net/product/xabe_ffmpeg/#documentation

La conversion est simple:

IConversionResult result = await Conversion.ToMp4(Resources.MkvWithAudio, output).Start();

Si vous voulez progresser:

IConversion conversion = Conversion.ToMp4(Resources.MkvWithAudio, output);
conversion.OnProgress += (duration, length) => { currentProgress = duration; } 
await conversion.Start();

Bonjour ... J'ai besoin d'utiliser FFMPEG pour transcoder une donnée en streaming provenant d'une page Web et l'envoyer à un serveur RTMP. J'ai le tableau d'octets dans mon programme C # winform. Je n'ai besoin que de transcoder et d'envoyer au serveur RTMP. Puis-je faire cela en utilisant ce wrapper? J'ai fait cela en utilisant un serveur nodejs en utilisant socketio sous Linux. Dans cette plate-forme, j'envoie le flux binaire via stdin et reçois l'état de conversion dans stderr. Puis-je le faire en utilisant le wrapper Xabe?
jstuardo

3

Je joue avec une bibliothèque de wrapper ffmpeg appelée MediaHandler Pro de

http://www.mediasoftpro.com

semble prometteur jusqu'à présent.


Comment cela a-t-il fonctionné pour vous? De plus, MediaHandlerapparaît-il en ffmpeg.exetant que processus pour faire son travail, ou existe-t-il une bibliothèque P / Invoke réelle?
Glenn Slayden

J'ai fini par l'utiliser dans quelques projets. Cela a bien fonctionné dans un environnement de production sous forte charge. cela fait un moment que je ne l'ai pas utilisé, mais d'après ce dont je me souviens, oui, il génère ffmpeg.exe en tant que processus.
Christophe Chang

3

J'ai fait des recherches sur la même chose et j'ai utilisé à l'origine MediaToolKit (mentionné dans une autre réponse) qui fonctionnait très bien pour les conversions, mais maintenant j'ai besoin de quelque chose d'un peu plus robuste.

Une option qui semble mature et toujours active est: https://github.com/hudl/HudlFfmpeg dont vous pouvez en savoir plus ici: http://public.hudl.com/bits/archives/2014/08/15/announcing -hudlffmpeg-ac-framework-pour-faire-ffmpeg-interaction-simple /

Une autre option, qui peut ne pas convenir à de nombreux cas, consiste à appeler l'exe directement à partir de votre code c #: http://www.codeproject.com/Articles/774093/Another-FFmpeg-exe-Csharp-Wrapper


2

1
Merci pour le lien, mais pour autant que je sache, vous avez écrit le vôtre en Java, pas en int C #.
Jacob Poul Richardt

Salut Lillemanden, le lien que j'ai donné est en fait implémenté en Java, et si vous téléchargez le zip en bas de l'article, vous verrez qu'il y a un fichier d'archive jar à l'intérieur. Merci, Ilya
Ilya

Le lien en réponse semble mort: "Ce site ne peut pas être atteint - ivolo.mit.edu a mis trop de temps à répondre."
Pang

2

Voilà ... La plupart de ce code a plus de 2 ans, il manque donc beaucoup de trucs asynchrones et utilise une convention de dénomination obsolète. Fonctionnement dans un environnement de production pendant un certain temps ~ JT

internal static class FFMpegArgUtils
    {
        public static string GetEncodeVideoFFMpegArgs(string sSourceFile, MP4Info objMp4Info, double nMbps, int iWidth, int iHeight, bool bIncludeAudio, string sOutputFile)
        {
            //Ensure file contains a video stream, otherwise this command will fail
            if (objMp4Info != null && objMp4Info.VideoStreamCount == 0)
            {
                throw new Exception("FFMpegArgUtils::GetEncodeVideoFFMpegArgs - mp4 does not contain a video stream");
            }

            int iBitRateInKbps = (int)(nMbps * 1000);


            StringBuilder sbArgs = new StringBuilder();
            sbArgs.Append(" -y -threads 2 -i \"" + sSourceFile + "\" -strict -2 "); // 0 tells it to choose how many threads to use

            if (bIncludeAudio == true)
            {
                //sbArgs.Append(" -acodec libmp3lame -ab 96k");
                sbArgs.Append(" -acodec aac -ar 44100 -ab 96k");
            }
            else
            {
                sbArgs.Append(" -an");
            }


            sbArgs.Append(" -vcodec libx264 -level 41 -r 15 -crf 25 -g 15  -keyint_min 45 -bf 0");

            //sbArgs.Append(" -vf pad=" + iWidth + ":" + iHeight + ":" + iVideoOffsetX + ":" + iVideoOffsetY);
            sbArgs.Append(String.Format(" -vf \"scale=iw*min({0}/iw\\,{1}/ih):ih*min({0}/iw\\,{1}/ih),pad={0}:{1}:({0}-iw)/2:({1}-ih)/2\"",iWidth, iHeight));

            //Output File
            sbArgs.Append(" \"" + sOutputFile + "\"");
            return sbArgs.ToString();
        }

        public static string GetEncodeAudioFFMpegArgs(string sSourceFile, string sOutputFile)
        {
            var args = String.Format(" -y -threads 2 -i \"{0}\" -strict -2  -acodec aac -ar 44100 -ab 96k -vn \"{1}\"", sSourceFile, sOutputFile);
            return args;


            //return GetEncodeVideoFFMpegArgs(sSourceFile, null, .2, 854, 480, true, sOutputFile);
            //StringBuilder sbArgs = new StringBuilder();
            //int iWidth = 854;
            //int iHeight = 480;
            //sbArgs.Append(" -y -i \"" + sSourceFile + "\" -strict -2 "); // 0 tells it to choose how many threads to use
            //sbArgs.Append(" -acodec aac -ar 44100 -ab 96k");
            //sbArgs.Append(" -vcodec libx264 -level 41 -r 15 -crf 25 -g 15  -keyint_min 45 -bf 0");
            //sbArgs.Append(String.Format(" -vf \"scale=iw*min({0}/iw\\,{1}/ih):ih*min({0}/iw\\,{1}/ih),pad={0}:{1}:({0}-iw)/2:({1}-ih)/2\"", iWidth, iHeight));
            //sbArgs.Append(" \"" + sOutputFile + "\"");
            //return sbArgs.ToString();
        }
    }

internal class CreateEncodedVideoCommand : ConsoleCommandBase
    {
        public event ProgressEventHandler OnProgressEvent;

        private string _sSourceFile;
        private  string _sOutputFolder;
        private double _nMaxMbps;

        public double BitrateInMbps
        {
            get { return _nMaxMbps; }
        }

        public int BitrateInKbps
        {
            get { return (int)Math.Round(_nMaxMbps * 1000); }
        }

        private int _iOutputWidth;
        private int _iOutputHeight;

        private bool _bIsConverting = false;
        //private TimeSpan _tsDuration;
        private double _nPercentageComplete;
        private string _sOutputFile;
        private string _sOutputFileName;


        private bool _bAudioEnabled = true;
        private string _sFFMpegPath;
        private string _sExePath;
        private string _sArgs;
        private MP4Info _objSourceInfo;
        private string _sOutputExt;

        /// <summary>
        /// Encodes an MP4 to the specs provided, quality is a value from 0 to 1
        /// </summary>
        /// <param name="nQuality">A value from 0 to 1</param>
        /// 
        public CreateEncodedVideoCommand(string sSourceFile, string sOutputFolder, string sFFMpegPath, double nMaxBitrateInMbps, MP4Info objSourceInfo, int iOutputWidth, int iOutputHeight, string sOutputExt)
        {
            _sSourceFile = sSourceFile;
            _sOutputFolder = sOutputFolder;
            _nMaxMbps = nMaxBitrateInMbps;
            _objSourceInfo = objSourceInfo;
            _iOutputWidth = iOutputWidth;
            _iOutputHeight = iOutputHeight;
            _sFFMpegPath = sFFMpegPath;
            _sOutputExt = sOutputExt;
        }

        public void SetOutputFileName(string sOutputFileName)
        {
            _sOutputFileName = sOutputFileName;
        }


        public override void Execute()
        {
            try
            {
                _bIsConverting = false;

                string sFileName = _sOutputFileName != null ? _sOutputFileName : Path.GetFileNameWithoutExtension(_sSourceFile) + "_" + _iOutputWidth + "." + _sOutputExt;
                _sOutputFile = _sOutputFolder + "\\" + sFileName;

                _sExePath = _sFFMpegPath;
                _sArgs = FFMpegArgUtils.GetEncodeVideoFFMpegArgs(_sSourceFile, _objSourceInfo,_nMaxMbps, _iOutputWidth, _iOutputHeight, _bAudioEnabled, _sOutputFile);

                InternalExecute(_sExePath, _sArgs);
            }
            catch (Exception objEx)
            {
                DispatchException(objEx);
            }
        }

        public override string GetCommandInfo()
        {
            StringBuilder sbInfo = new StringBuilder();
            sbInfo.AppendLine("CreateEncodeVideoCommand");
            sbInfo.AppendLine("Exe: " + _sExePath);
            sbInfo.AppendLine("Args: " + _sArgs);
            sbInfo.AppendLine("[ConsoleOutput]");
            sbInfo.Append(ConsoleOutput);
            sbInfo.AppendLine("[ErrorOutput]");
            sbInfo.Append(ErrorOutput);

            return base.GetCommandInfo() + "\n" + sbInfo.ToString();
        }

        protected override void OnInternalCommandComplete(int iExitCode)
        {
            DispatchCommandComplete( iExitCode == 0 ? CommandResultType.Success : CommandResultType.Fail);
        }

        override protected void OnOutputRecieved(object sender, ProcessOutputEventArgs objArgs)
        {
            //FMPEG out always shows as Error
            base.OnOutputRecieved(sender, objArgs);

            if (_bIsConverting == false && objArgs.Data.StartsWith("Press [q] to stop encoding") == true)
            {
                _bIsConverting = true;
            }
            else if (_bIsConverting == true && objArgs.Data.StartsWith("frame=") == true)
            {
                //Capture Progress
                UpdateProgressFromOutputLine(objArgs.Data);
            }
            else if (_bIsConverting == true && _nPercentageComplete > .8 && objArgs.Data.StartsWith("frame=") == false)
            {
                UpdateProgress(1);
                _bIsConverting = false;
            }
        }

        override protected void OnProcessExit(object sender, ProcessExitedEventArgs args)
        {
            _bIsConverting = false;
            base.OnProcessExit(sender, args);
        }

        override public void Abort()
        {
            if (_objCurrentProcessRunner != null)
            {
                //_objCurrentProcessRunner.SendLineToInputStream("q");
                _objCurrentProcessRunner.Dispose();
            }
        }

        #region Helpers

        //private void CaptureSourceDetailsFromOutput()
        //{
        //    String sInputStreamInfoStartLine = _colErrorLines.SingleOrDefault(o => o.StartsWith("Input #0"));
        //    int iStreamInfoStartIndex = _colErrorLines.IndexOf(sInputStreamInfoStartLine);
        //    if (iStreamInfoStartIndex >= 0)
        //    {
        //        string sDurationInfoLine = _colErrorLines[iStreamInfoStartIndex + 1];
        //        string sDurantionTime = sDurationInfoLine.Substring(12, 11);

        //        _tsDuration = VideoUtils.GetDurationFromFFMpegDurationString(sDurantionTime);
        //    }
        //}

        private void UpdateProgressFromOutputLine(string sOutputLine)
        {
            int iTimeIndex = sOutputLine.IndexOf("time=");
            int iBitrateIndex = sOutputLine.IndexOf(" bitrate=");

            string sCurrentTime = sOutputLine.Substring(iTimeIndex + 5, iBitrateIndex - iTimeIndex - 5);
            double nCurrentTimeInSeconds = double.Parse(sCurrentTime);
            double nPercentageComplete = nCurrentTimeInSeconds / _objSourceInfo.Duration.TotalSeconds;

            UpdateProgress(nPercentageComplete);
            //Console.WriteLine("Progress: " + _nPercentageComplete);
        }

        private void UpdateProgress(double nPercentageComplete)
        {
            _nPercentageComplete = nPercentageComplete;
            if (OnProgressEvent != null)
            {
                OnProgressEvent(this, new ProgressEventArgs( _nPercentageComplete));
            }
        }

        #endregion

        //public TimeSpan Duration { get { return _tsDuration; } }

        public double Progress { get { return _nPercentageComplete;  } }
        public string OutputFile { get { return _sOutputFile; } }

        public bool AudioEnabled
        {
            get { return _bAudioEnabled; }
            set { _bAudioEnabled = value; }
        }
}

public abstract class ConsoleCommandBase : CommandBase, ICommand
    {
        protected ProcessRunner _objCurrentProcessRunner;
        protected   List<String> _colOutputLines;
        protected List<String> _colErrorLines;


        private int _iExitCode;

        public ConsoleCommandBase()
        {
            _colOutputLines = new List<string>();
            _colErrorLines = new List<string>();
        }

        protected void InternalExecute(string sExePath, string sArgs)
        {
            InternalExecute(sExePath, sArgs, null, null, null);
        }

        protected void InternalExecute(string sExePath, string sArgs, string sDomain, string sUsername, string sPassword)
        {
            try
            {
                if (_objCurrentProcessRunner == null || _bIsRunning == false)
                {
                    StringReader objStringReader = new StringReader(string.Empty);

                    _objCurrentProcessRunner = new ProcessRunner(sExePath, sArgs);

                    _objCurrentProcessRunner.SetCredentials(sDomain, sUsername, sPassword);

                    _objCurrentProcessRunner.OutputReceived += new ProcessOutputEventHandler(OnOutputRecieved);
                    _objCurrentProcessRunner.ProcessExited += new ProcessExitedEventHandler(OnProcessExit);
                    _objCurrentProcessRunner.Run();

                    _bIsRunning = true;
                    _bIsComplete = false;
                }
                else
                {
                    DispatchException(new Exception("Processor Already Running"));
                }
            }
            catch (Exception objEx)
            {
                DispatchException(objEx);
            }
        }

        protected virtual void OnOutputRecieved(object sender, ProcessOutputEventArgs args)
        {
            try
            {
                if (args.Error == true)
                {
                    _colErrorLines.Add(args.Data);
                    //Console.WriteLine("Error: " + args.Data);
                }
                else
                {
                    _colOutputLines.Add(args.Data);
                    //Console.WriteLine(args.Data);
                }
            }
            catch (Exception objEx)
            {
                DispatchException(objEx);
            }
        }

        protected virtual void OnProcessExit(object sender, ProcessExitedEventArgs args)
        {
            try
            {
                Console.Write(ConsoleOutput);
                _iExitCode = args.ExitCode;

                _bIsRunning = false;
                _bIsComplete = true;

                //Some commands actually fail to succeed
                //if(args.ExitCode != 0)
                //{
                //    DispatchException(new Exception("Command Failed: " + this.GetType().Name + "\nConsole: " + ConsoleOutput + "\nConsoleError: " + ErrorOutput));
                //}

                OnInternalCommandComplete(_iExitCode);

                if (_objCurrentProcessRunner != null)
                {
                    _objCurrentProcessRunner.Dispose();
                    _objCurrentProcessRunner = null;    
                }
            }
            catch (Exception objEx)
            {
                DispatchException(objEx);
            }
        }

        abstract protected void OnInternalCommandComplete(int iExitCode);

        protected string JoinLines(List<String> colLines)
        {
            StringBuilder sbOutput = new StringBuilder();
            colLines.ForEach( o => sbOutput.AppendLine(o));
            return sbOutput.ToString();
        }

        #region Properties
        public int ExitCode
        {
            get { return _iExitCode; }
        }
        #endregion

        public override string GetCommandInfo()
        {
            StringBuilder sbCommandInfo = new StringBuilder();
            sbCommandInfo.AppendLine("Command:  " + this.GetType().Name);
            sbCommandInfo.AppendLine("Console Output");
            if (_colOutputLines != null)
            {
                foreach (string sOutputLine in _colOutputLines)
                {
                    sbCommandInfo.AppendLine("\t" + sOutputLine);
                }
            }
            sbCommandInfo.AppendLine("Error Output");
            if (_colErrorLines != null)
            {
                foreach (string sErrorLine in _colErrorLines)
                {
                    sbCommandInfo.AppendLine("\t" + sErrorLine);
                }
            }
            return sbCommandInfo.ToString();
        }

        public String ConsoleOutput { get { return JoinLines(_colOutputLines); } }
        public String ErrorOutput { get { return JoinLines(_colErrorLines);} }

    }

CommandBase : ICommand
    {
        protected IDedooseContext _context;
        protected Boolean _bIsRunning = false;
        protected Boolean _bIsComplete = false;

        #region Custom Events
        public event CommandCompleteEventHandler OnCommandComplete;
        event CommandCompleteEventHandler ICommand.OnCommandComplete
        {
            add { if (OnCommandComplete != null) { lock (OnCommandComplete) { OnCommandComplete += value; } } else { OnCommandComplete = new CommandCompleteEventHandler(value); } }
            remove { if (OnCommandComplete != null) { lock (OnCommandComplete) { OnCommandComplete -= value; } } }
        }

        public event UnhandledExceptionEventHandler OnCommandException;
        event UnhandledExceptionEventHandler ICommand.OnCommandException
        {
            add { if (OnCommandException != null) { lock (OnCommandException) { OnCommandException += value; } } else { OnCommandException = new UnhandledExceptionEventHandler(value); } }
            remove { if (OnCommandException != null) { lock (OnCommandException) { OnCommandException -= value; } } }
        }

        public event ProgressEventHandler OnProgressUpdate;
        event ProgressEventHandler ICommand.OnProgressUpdate
        {
            add { if (OnProgressUpdate != null) { lock (OnProgressUpdate) { OnProgressUpdate += value; } } else { OnProgressUpdate = new ProgressEventHandler(value); } }
            remove { if (OnProgressUpdate != null) { lock (OnProgressUpdate) { OnProgressUpdate -= value; } } }
        }
        #endregion

        protected CommandBase()
        {
            _context = UnityGlobalContainer.Instance.Context;
        }

        protected void DispatchCommandComplete(CommandResultType enResult)
        {
            if (enResult == CommandResultType.Fail)
            {
                StringBuilder sbMessage = new StringBuilder();
                sbMessage.AppendLine("Command Commpleted with Failure: "  + this.GetType().Name);
                sbMessage.Append(GetCommandInfo());
                Exception objEx = new Exception(sbMessage.ToString());
                DispatchException(objEx);
            }
            else
            {
                if (OnCommandComplete != null)
                {
                    OnCommandComplete(this, new CommandCompleteEventArgs(enResult));
                }
            }
        }

        protected void DispatchException(Exception objEx)
        {
            if (OnCommandException != null)
            { 
                OnCommandException(this, new UnhandledExceptionEventArgs(objEx, true)); 
            }
            else
            {
                _context.Logger.LogException(objEx, MethodBase.GetCurrentMethod());
                throw objEx;
            }
        }

        protected void DispatchProgressUpdate(double nProgressRatio)
        {
            if (OnProgressUpdate != null) { OnProgressUpdate(this, new ProgressEventArgs(nProgressRatio)); } 
        }

        public virtual string GetCommandInfo()
        {
            return "Not Implemented: " + this.GetType().Name;
        }

        public virtual void Execute() { throw new NotImplementedException(); }
        public virtual void Abort() { throw new NotImplementedException(); }

        public Boolean IsRunning { get { return _bIsRunning; } }
        public Boolean IsComplete { get { return _bIsComplete; } }

        public double GetProgressRatio()
        {
            throw new NotImplementedException();
        }
    }

public delegate void CommandCompleteEventHandler(object sender, CommandCompleteEventArgs e);

    public interface ICommand
    {
        event CommandCompleteEventHandler OnCommandComplete;
        event UnhandledExceptionEventHandler OnCommandException;
        event ProgressEventHandler OnProgressUpdate;

        double GetProgressRatio();
        string GetCommandInfo();

        void Execute();
        void Abort();
    }

// pour les trucs du processus runner, recherchez ProcessRunner de Roger Knapp


1
        string result = String.Empty;
        StreamReader srOutput = null;
        var oInfo = new ProcessStartInfo(exePath, parameters)
        {
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true
        };

        var output = string.Empty;

        try
        {
            Process process = System.Diagnostics.Process.Start(oInfo);
            output = process.StandardError.ReadToEnd();
            process.WaitForExit();
            process.Close();
        }
        catch (Exception)
        {
            output = string.Empty;
        }
        return output;

Ce wrapper ne laissera pas la méthode tomber dans une boucle. Essayez ceci, cela a fonctionné pour moi.


1

J'ai bifurqué FFPMEG.net à partir de codeplex.

Toujours activement travaillé.

https://github.com/spoiledtechie/FFMpeg.Net

Il n'utilise pas les dll, mais plutôt l'exe. Donc, il a tendance à être plus stable.


On dirait ce que je cherche, mais comment l'implémenter dans leur projet?
TEK

Ajoutez ce projet à votre projet, puis assurez-vous que FFMPEG se trouve correctement dans le projet. Son travail est toujours en cours.
SpoiledTechie.com

Puis-je encoder et décoder une image sous forme d'octet [] en utilisant ce FFMPEG.net? par exemple, byte [] encodeh264 (byte []) et byte [] decodeh264 (byte []).
Ahmad le

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.