【问题标题】:Solid FFmpeg wrapper for C#/.NET用于 C#/.NET 的实体 FFmpeg 包装器
【发布时间】:2011-01-10 21:44:51
【问题描述】:

一段时间以来,我一直在网上搜索用于 C#/.NET 的可靠 FFmpeg 包装器。但我还没有想出一些有用的东西。我找到了以下三个项目,但它们似乎都在早期的 alpha 阶段死了。

FFmpeg.NET
ffmpeg-sharp
FFLIB.NET

所以我的问题是,是否有人知道更成熟的包装器项目?
我不是在寻找具有作业队列等的完整转码引擎。 只是一个简单的包装器,因此我不必进行命令行调用然后解析控制台输出,而是可以进行方法调用并使用事件监听器来获取进度。

请随时提及任何活跃的项目,即使它们仍处于早期阶段。

【问题讨论】:

  • 这有什么新东西吗?你的 wrapper 有进展吗?
  • @Lillemanden 你有没有发布或开源你的包装器?
  • 有趣的是,这个问题已经有将近 6 年的历史了,但 OP (@JacobPoulRichardt) 没有接受任何答案。
  • 我最终使用了自己制作的包装器,因此没有使用任何建议的项目。由于我不再使用 ffmpeg,因此我也没有时间回去尝试其中的任何一个。但是在浏览了大部分答案后,他们对大部分答案都投了赞成票。所以我真的认为我不能说任何答案都比其他答案更“正确”。

标签: c# .net video ffmpeg video-processing


【解决方案1】:

这是我自己的包装器:https://github.com/AydinAdn/MediaToolkit

MediaToolkit 可以:

  • 将视频文件转换为其他各种视频格式。
  • 执行视频转码任务。
    • 可配置选项:Bit rateFrame rateResolution / sizeAspect ratioDuration of video
  • 执行音频转码任务。
    • 可配置选项:Audio sample rate
  • 使用 FILM、PAL 或 NTSC 电视标准将视频转换为物理格式
    • 媒体包括:DVDDVDV50VCDSVCD

我正在更新它,欢迎您使用它,您也可以使用包管理器控制台安装它。

PM> Install-Package MediaToolkit

【讨论】:

  • 您的工具包能否将不同的视频和音频剪辑混合/渲染为给定的输出分辨率之一?
  • 不,它是为追求简单转换的人设计的。也就是说,很快就会有 v2 版本,它可以让您完成 FFmpeg 提供的所有功能。
  • 谢谢 Aydin,请让我了解这个新版本。
  • 看起来棒极了!到目前为止做得很好!
  • 嘿Aydin,这也能录屏吗?
【解决方案2】:

在尝试了几个包装器之后,我选择了这个:FFmpeg auto generated unsafe bindings for C#/.NET and Mono

它是 FFmpeg 命名空间中每个类的一组低级互操作绑定。 使用起来可能不如实际的包装器方便,但如果您想做一些重要的事情,IMO 它是在 .Net 中使用 FFmpeg 的最佳解决方案。

优点:

  • 作品
  • 值得信赖 - 假设您信任 FFMpeg 本身,没有 3rd 方包装代码会引入错误。
  • 它总是更新到最新版本的 FFmpeg
  • 单个nuget package 用于所有绑定
  • 包含 XML 文档,但您仍然可以使用在线文档 FFmpeg documentation

缺点:

  • 低级:您必须知道如何使用指向 c 结构 的指针。
  • 最初需要一些工作才能使其正常工作。建议向the official examples学习。

注意:这个线程是关于使用 FFmpeg API,但对于某些用例,最好简单地使用 ffmpeg.exe 的command line interface

【讨论】:

  • 您是否设法从针对 .Net Framework(非核心)的项目中使用它?我不确定我在这里缺少什么
  • @YoavFeuerstein 是的。
【解决方案3】:

我从 ASP.NET / Windows 服务 (.NET) 应用程序中使用了 FFmpeg。 但我最终使用了命令行,没有解析控制台。 通过使用这个 - 我有一个简单的方法来控制 - 更新 FFmpeg 并在多个核心上运行多个转换。

【讨论】:

  • 好的,我开始做类似的事情。但我仍然希望有人有更好的解决方案。
【解决方案4】:

试试这个,我想我可能已经写了一些可以用作简单包装器的东西。

http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/

【讨论】:

  • 谢谢,但我开始自己写了。但是,如果我不能提出一些想法,我会的。
【解决方案5】:

你可以使用这个 nuget 包:

我知道您询问了成熟项目,但我还没有看到任何项目满足我的期望,所以我决定自己做。 您可以轻松地将转换排队并并行运行,将媒体转换为不同格式的方法,将您自己的参数发送到 ffmpeg 并使用当前进度解析来自 ffmpeg + 事件侦听器的输出。

Install-Package Xabe.FFmpeg

我正在尝试制作易于使用的跨平台 FFmpeg 包装器。

您可以在https://xabe.net/product/xabe_ffmpeg/找到更多信息

更多信息在这里:https://xabe.net/product/xabe_ffmpeg/#documentation

转换很简单:

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

如果你想要进步:

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

【讨论】:

  • 您好...我需要使用 FFMPEG 对来自网页的流数据进行转码并将其发送到 RTMP 服务器。我的 C# winform 程序中有字节数组。我只需要转码并发送到 RTMP 服务器。我可以使用这个包装器来做到这一点吗?我在 Linux 中使用使用 socketio 的 nodejs 服务器做到了这一点。在那个平台上,我通过标准输入发送二进制流,并在标准错误中接收转换状态。我可以使用 Xabe 包装器吗?
【解决方案6】:

我正在玩一个名为 MediaHandler Pro 的 ffmpeg 包装库

http://www.mediasoftpro.com

目前看来很有希望。

【讨论】:

  • 这对您来说效果如何?另外,MediaHandler 是否将 ffmpeg.exe 作为一个进程来完成其工作,还是有一个实际的 P/Invoke 库?
  • 我最终在几个项目中使用了它。它在高负载下的生产环境中运行良好。我已经有一段时间没有使用它了,但据我记得,是的,它确实将 ffmpeg.exe 作为一个进程生成。
【解决方案7】:

我一直在研究同样的东西,最初使用的是 MediaToolKit(在另一个答案中提到),它非常适合转换,但现在我需要一些更强大的东西。

一个看似成熟且仍然有效的选项是: https://github.com/hudl/HudlFfmpeg 您可以在此处阅读更多信息: http://public.hudl.com/bits/archives/2014/08/15/announcing-hudlffmpeg-a-c-framework-to-make-ffmpeg-interaction-simple/

另一个可能不适合许多情况的选项是直接从您的 c# 代码调用 exe: http://www.codeproject.com/Articles/774093/Another-FFmpeg-exe-Csharp-Wrapper

【讨论】:

    【解决方案8】:

    【讨论】:

    • 感谢您的链接,但据我所知,您是用 Java 编写的,而不是 int C#。
    • 嗨 lillemanden,我提供的链接实际上是用 Java 实现的,如果你下载文章底部的 zip,你会看到里面有一个 jar 存档文件。谢谢,伊利亚
    • 答案中的链接似乎已失效:“无法访问此站点 - ivolo.mit.edu 响应时间过长。”
    【解决方案9】:

    你去吧...大部分代码已经有 2 年以上的历史了,所以缺少很多异步的东西,并且使用了过时的命名约定。在生产环境中运行了相当长的一段时间 ~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();
        }
    

    // 对于流程运行程序的内容,请查找 Roger Knapp 的 ProcessRunner

    【讨论】:

      【解决方案10】:
              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;
      

      这个包装器不会让方法陷入循环。 试试这个,它对我有用。

      【讨论】:

        【解决方案11】:

        我从 codeplex 分叉了 FFPMEG.net。

        仍在积极进行中。

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

        它不使用 dll,而是使用 exe。所以它往往更稳定。

        【讨论】:

        • 看起来像我所追求的,但是如何在他们的项目中实现这一点?
        • 将此项目添加到您的项目中,然后确保 FFMPEG 正确位于项目中。它仍在进行中。
        • 我可以使用这个 FFMPEG.net 将帧编码和解码为 byte[] 吗?例如,byte[] encodeh264(byte[]) 和 byte[] decodeh264(byte[])。
        【解决方案12】:

        请参阅Auto Generated FFmpeg wrapper for C#/.NET and Mono,这是一个很棒的项目,它似乎是目前唯一真正的、完整的 .NET FFmpeg 互操作包装器。

        【讨论】:

          猜你喜欢
          • 2011-10-06
          • 1970-01-01
          • 2014-05-16
          • 1970-01-01
          • 2021-06-26
          • 2012-04-21
          • 1970-01-01
          • 1970-01-01
          • 2020-03-15
          相关资源
          最近更新 更多