Envoltorio sólido de FFmpeg para C # / .NET

91

He estado buscando en la web durante algún tiempo un contenedor FFmpeg sólido para C # / .NET . Pero todavía tengo que encontrar algo útil. Encontré los siguientes tres proyectos, pero todos parecen estar muertos en la etapa alfa inicial.

FFmpeg.NET
ffmpeg-nítido
FFLIB.NET

Entonces, mi pregunta es si alguien sabe de un proyecto de envoltura que sea más maduro.
No estoy buscando un motor de transcodificación completo con colas de trabajo y más. Solo un contenedor simple para no tener que hacer una llamada a la línea de comando y luego analizar la salida de la consola, pero puedo hacer llamadas a métodos y usar eventlisteners para el progreso.

Y no dude en mencionar cualquier proyecto activo, incluso si aún se encuentran en las primeras etapas.

Jacob Poul Richardt
fuente
1
posible duplicado de Alguien sabe de un conjunto de enlaces de C # para FFMPEG?
Paŭlo Ebermann
1
¿Algo nuevo con esto? ¿Tu envoltorio ha progresado?
Avi
3
@Lillemanden, ¿alguna vez lanzó o abrió su contenedor?
Nick Benedict
Es interesante que la pregunta tiene casi 6 años, pero el OP (@JacobPoulRichardt) no aceptó ninguna de las respuestas.
Ofer Zelig
1
Terminé usando una envoltura que hice yo mismo y, como tal, no usé ninguno de los proyectos sugeridos. Como ya no trabajo con ffmpeg, tampoco he tenido tiempo de volver y probar ninguno de ellos. Pero voté a favor de la mayoría de las respuestas después de leerlas. Así que realmente no creo que pueda decir que ninguna de las respuestas sea más "correcta" que las demás.
Jacob Poul Richardt

Respuestas:

24

Este es un contenedor propio: https://github.com/AydinAdn/MediaToolkit

MediaToolkit puede:

  • Convierta archivos de video en varios otros formatos de video.
  • Realice tareas de transcodificación de video.
    • Opciones configurables: Bit rate, Frame rate, Resolution / size, Aspect ratio,Duration of video
  • Realiza tareas de transcodificación de audio.
    • Opciones configurables: Audio sample rate
  • Convierta video a formatos físicos usando los estándares de TV FILM, PAL o NTSC
    • Medios incluyen: DVD, DV, DV50, VCD,SVCD

Lo actualizo a medida que avanzo, y puede usarlo, también puede instalarlo usando la Consola del Administrador de paquetes.

PM> Install-Package MediaToolkit
Aydin
fuente
¿Puede su kit de herramientas mux / renderizar diferentes clips de audio y video en una resolución de salida determinada?
Antonio Petricca
No, fue diseñado para ser utilizado por personas que buscan conversiones simples. Dicho esto, muy pronto llegará la versión 2, que le permitirá hacer todo lo que FFmpeg tiene para ofrecer.
Aydin
Gracias Aydin, manténgame informado sobre este nuevo lanzamiento.
Antonio Petricca
¡Parece fabuloso! ¡Buen trabajo hasta ahora!
SpoiledTechie.com
Hey Aydin, ¿esto también puede grabar la pantalla?
TEK
14

Después de probar varios contenedores, me decidí por esto: FFmpeg genera automáticamente enlaces inseguros para C # / .NET y Mono .

Es un conjunto de enlaces de interoperabilidad de bajo nivel para cada clase en el espacio de nombres FFmpeg. Tal vez no sea tan conveniente de usar como un contenedor real, pero IMO es la mejor solución para trabajar con FFmpeg en .Net, si desea hacer cosas no triviales.

Pros:

  • Trabajos
  • Confiable: no hay código contenedor de terceros para introducir errores, asumiendo que confía en FFMpeg.
  • Siempre está actualizado a la última versión de FFmpeg
  • Paquete único nuget para todos los enlaces
  • Se incluye documentación XML, pero aún puede utilizar la documentación en línea de FFmpeg .

Contras:

  • Nivel bajo: debes saber cómo trabajar con punteros a estructuras c .
  • Requiere algo de trabajo inicialmente para que funcione. Sugiero aprender de los ejemplos oficiales .

Nota: este hilo trata sobre el uso de la API de FFmpeg, pero para algunos casos de uso, es mejor usar simplemente la interfaz de línea de comandos de ffmpeg.exe .

orca
fuente
¿Lograste usarlo desde un proyecto que está dirigido a .Net Framework (no básico)? No estoy seguro de lo que me estoy perdiendo aquí
Yoav Feuerstein
@YoavFeuerstein Sí.
orca
10

He usado FFmpeg desde una aplicación de servicio ASP.NET / Windows (.NET). Pero terminé usando la línea de comandos, sin analizar la consola. Al usar esto, tenía una manera fácil de controlar, las actualizaciones de FFmpeg y la ejecución de múltiples conversiones en múltiples núcleos.

Famdam
fuente
Ok, comencé con algo similar. Pero todavía espero que alguien tenga una mejor solución.
Jacob Poul Richardt
4

Puede usar este paquete nuget:

Sé que preguntaste sobre un proyecto maduro , pero no he visto ningún proyecto que cumpliera mis expectativas, así que decidí hacer el mío. Puede fácilmente poner en cola conversiones y ejecutarlo en paralelo, métodos para convertir medios a diferentes formatos, enviar sus propios argumentos a ffmpeg y analizar la salida de ffmpeg + event listener con el progreso actual.

Install-Package Xabe.FFmpeg

Estoy tratando de hacer un contenedor FFmpeg multiplataforma fácil de usar.

Puede encontrar más información al respecto en https://xabe.net/product/xabe_ffmpeg/

Más información aquí: https://xabe.net/product/xabe_ffmpeg/#documentation

La conversión es simple:

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

Si quieres progresar:

IConversion conversion = Conversion.ToMp4(Resources.MkvWithAudio, output);
conversion.OnProgress += (duration, length) => { currentProgress = duration; } 
await conversion.Start();
Tomasz Żmuda
fuente
Hola ... Necesito usar FFMPEG para transcodificar un flujo de datos proveniente de una página web y enviarlo a un servidor RTMP. Tengo la matriz de bytes en mi programa C # winform. Solo necesito transcodificar y enviar al servidor RTMP. ¿Puedo hacer eso usando esta envoltura? Hice esto usando un servidor nodejs usando socketio en Linux. En esa plataforma, envío el flujo binario a través de stdin y recibo el estado de conversión en stderr. ¿Puedo hacerlo usando Xabe wrapper?
jstuardo
3

Estoy jugando con una biblioteca contenedora ffmpeg llamada MediaHandler Pro de

http://www.mediasoftpro.com

parece prometedor hasta ahora.

Christophe Chang
fuente
¿Cómo te resultó esto? Además, ¿se MediaHandlergenera el spawn ffmpeg.execomo un proceso para hacer su trabajo, o existe una biblioteca P / Invoke real?
Glenn Slayden
Terminé usándolo en un par de proyectos. Funcionó bien en un entorno de producción con una carga pesada. Ha pasado un tiempo desde que lo usé, pero por lo que recuerdo, sí genera ffmpeg.exe como un proceso.
Christophe Chang
3

He estado investigando lo mismo y originalmente usé MediaToolKit (mencionado en otra respuesta) que funcionó muy bien para las conversiones, pero ahora necesito algo un poco más sólido.

Una opción que parece madura y aún activa es: https://github.com/hudl/HudlFfmpeg Sobre la cual puede leer más aquí: http://public.hudl.com/bits/archives/2014/08/15/announcing -hudlffmpeg-ac-framework-para-hacer-ffmpeg-interacción-simple /

Otra opción, que puede no ser adecuada para muchos casos, es invocar el exe directamente desde su código c #: http://www.codeproject.com/Articles/774093/Another-FFmpeg-exe-Csharp-Wrapper

ickydime
fuente
2

Hay otro sencillo aquí: http://ivolo.mit.edu/post/Metamorph-Convert-Audio-Video-to-Any-Format-on-Windows-Linux-and-Mac.aspx

Ilya
fuente
1
Gracias por el enlace, pero por lo que puedo ver, escribiste el tuyo en Java, no int C #.
Jacob Poul Richardt
Hola, lillemanden, el enlace que proporcioné está implementado en Java, y si descarga el zip al final del artículo, verá que hay un archivo jar dentro de él. Gracias, Ilya
Ilya
El enlace en respuesta parece muerto: "No se puede acceder a este sitio; ivolo.mit.edu tardó demasiado en responder".
Pang
2

Aquí tienes ... La mayor parte de este código tiene más de 2 años, por lo que le faltan muchas cosas asincrónicas y usa una convención de nomenclatura obsoleta. Funcionando en un entorno de producción durante bastante tiempo ~ 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();
    }

// para las cosas del corredor de procesos, busque ProcessRunner de Roger Knapp

JTtheGeek
fuente
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;

Esta envoltura no permitirá que el método caiga en un bucle. Prueba esto, funcionó para mí.

Mrinal
fuente
1

Bifurqué FFPMEG.net desde codeplex.

Todavía se está trabajando activamente.

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

No usa dlls, sino exe. Por lo que tiende a ser más estable.

SpoiledTechie.com
fuente
Parece lo que busco, pero ¿cómo se implementa esto en su proyecto?
TEK
Agregue este proyecto a su proyecto, luego asegúrese de que FFMPEG se encuentre dentro del proyecto correctamente. Todavía se está trabajando en ello.
SpoiledTechie.com
¿Puedo codificar y decodificar un marco como byte [] usando este FFMPEG.net? por ejemplo, byte [] encodeh264 (byte []) y byte [] decodeh264 (byte []).
Ahmad