用于 C#/.NET 的实体 FFmpeg 包装器

Posted

技术标签:

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

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

FFmpeg.NETffmpeg-sharp FFLIB.NET

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

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

【问题讨论】:

Anyone know of a set of C# bindings for FFMPEG?的可能重复 这有什么新东西吗?你的 wrapper 有进展吗? @Lillemanden 你有没有发布或开源你的包装器? 有趣的是,这个问题已经有将近 6 年的历史了,但 OP (@JacobPoulRichardt) 没有接受任何答案。 我最终使用了自己制作的包装器,因此没有使用任何建议的项目。由于我不再使用 ffmpeg,因此我也没有时间回去尝试其中的任何一个。但是在浏览了大部分答案后,他们对大部分答案都投了赞成票。所以我真的认为我不能说任何答案都比其他答案更“正确”。 【参考方案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】:

这里还有一个简单的:http://ivolo.mit.edu/post/Metamorph-Convert-Audio-Video-to-Any-Format-on-Windows-Linux-and-Mac.aspx

【讨论】:

感谢您的链接,但据我所知,您是用 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 互操作包装器。

【讨论】:

以上是关于用于 C#/.NET 的实体 FFmpeg 包装器的主要内容,如果未能解决你的问题,请参考以下文章

是否有用于 WinInet 的 .Net 包装器

用于 JQuery 日期时间选择器的 ASP.Net 包装器控件

是否有用于 OData 协议 Uri 的 .NET 类包装器

C++11新特性 :函数对象包装器

使用 java-ffmpeg 包装器,还是简单地使用 java 运行时来执行 ffmpeg?

用于 std::reverse() 的 C++11 便利包装器