Trình bao bọc FFmpeg rắn cho C # /. NET


91

Tôi đã tìm kiếm trên web một thời gian cho một trình bao bọc FFmpeg vững chắc cho C # /. NET . Nhưng tôi vẫn chưa nghĩ ra điều gì hữu ích. Tôi đã tìm thấy ba dự án sau đây, nhưng tất cả chúng dự kiến ​​sẽ chết trong giai đoạn đầu alpha.

FFmpeg.NET
ffmpeg-nét
FFLIB.NET

Vì vậy, câu hỏi của tôi là nếu có ai biết về một dự án wrapper trưởng thành hơn?
Tôi không tìm kiếm một công cụ chuyển mã đầy đủ với hàng đợi công việc và hơn thế nữa. Chỉ là một trình bao bọc đơn giản, do đó tôi không phải thực hiện một cuộc gọi dòng lệnh và sau đó phân tích cú pháp đầu ra của bảng điều khiển, nhưng có thể thực hiện các cuộc gọi phương thức và sử dụng trình tạo sự kiện để tiến trình.

Và vui lòng đề cập đến bất kỳ dự án nào đang hoạt động, ngay cả khi chúng đang ở giai đoạn đầu.



1
Có gì mới với cái này không? Trình bao bọc của bạn có tiến bộ gì không?
Avi

3
@Lillemanden bạn đã từng phát hành hoặc mã nguồn mở trình bao bọc của mình chưa?
Nick Benedict

Điều thú vị là câu hỏi đã gần 6 năm tuổi nhưng OP (@JacobPoulRichardt) không chấp nhận bất kỳ câu trả lời nào.
Ofer Zelig,

1
Tôi đã kết thúc bằng cách sử dụng một trình bao bọc do chính tôi tạo ra và do đó không sử dụng bất kỳ dự án nào được đề xuất. Vì tôi không còn làm việc với ffmpeg nữa, nên tôi cũng không có thời gian để quay lại và thử bất kỳ cái nào trong số chúng. Nhưng đã tán thành hầu hết các câu trả lời sau khi đọc lướt chúng. Vì vậy, tôi không thực sự nghĩ rằng tôi có thể nói rằng bất kỳ câu trả lời nào trong số các câu trả lời là "đúng" hơn những câu khác.
Jacob Poul Richardt

Câu trả lời:


24

Đây là một trình bao bọc của riêng tôi: https://github.com/AydinAdn/MediaToolkit

MediaToolkit có thể:

  • Chuyển đổi các tệp video thành nhiều định dạng video khác nhau.
  • Thực hiện các tác vụ chuyển mã video.
    • Tùy chọn cấu hình: Bit rate, Frame rate, Resolution / size, Aspect ratio,Duration of video
  • Thực hiện các tác vụ chuyển mã âm thanh.
    • Các tùy chọn có thể định cấu hình: Audio sample rate
  • Chuyển đổi video sang các định dạng vật lý sử dụng các tiêu chuẩn TV FILM, PAL hoặc NTSC
    • Phương tiện bao gồm: DVD, DV, DV50, VCD,SVCD

Tôi đang cập nhật nó khi tôi tiếp tục và bạn được hoan nghênh sử dụng nó, bạn cũng có thể cài đặt nó bằng cách sử dụng Bảng điều khiển Trình quản lý Gói.

PM> Install-Package MediaToolkit

Bộ công cụ của bạn có thể mux / hiển thị các đoạn video và âm thanh khác nhau thành một trong những độ phân giải đầu ra nhất định không?
Antonio Petricca

Không, nó được thiết kế để sử dụng cho những người theo đuổi các chuyển đổi đơn giản. Điều đó nói rằng, có v2 sắp ra mắt sẽ cho phép bạn làm mọi thứ mà FFmpeg đưa ra.
Aydin

Cảm ơn Aydin, hãy thông báo cho tôi về bản phát hành mới này.
Antonio Petricca

Trông tuyệt vời! Công việc tốt cho đến nay!
SpoiledTechie.com 14/02/15

Này Aydin, cái này cũng có thể quay màn hình được không?
TEK

14

Sau khi thử một số trình bao bọc, tôi đã làm được điều này: FFmpeg tự động tạo các liên kết không an toàn cho C # /. NET và Mono .

Đó là một tập hợp các liên kết tương tác cấp thấp cho mọi lớp trong không gian tên FFmpeg. Có thể không thuận tiện để sử dụng như một trình bao bọc thực tế, nhưng IMO là giải pháp tốt nhất để làm việc với FFmpeg trong .Net, nếu bạn muốn làm những việc không nhỏ.

Ưu điểm:

  • Làm
  • Đáng tin cậy - không có mã trình bao bọc của bên thứ 3 để giới thiệu lỗi, giả sử bạn tin tưởng chính FFMpeg.
  • Nó luôn được cập nhật lên phiên bản mới nhất của FFmpeg
  • Gói nuget đơn cho tất cả các ràng buộc
  • Tài liệu XML được bao gồm nhưng bạn vẫn có thể sử dụng tài liệu FFmpeg tài liệu trực tuyến .

Nhược điểm:

  • Mức độ thấp: Bạn phải biết cách làm việc với con trỏ đến cấu trúc c .
  • Yêu cầu một số công việc ban đầu để làm cho nó hoạt động. Tôi đề nghị học hỏi từ các ví dụ chính thức .

Lưu ý: chủ đề này là về việc sử dụng API FFmpeg, nhưng đối với một số trường hợp sử dụng, tốt nhất bạn chỉ cần sử dụng giao diện dòng lệnh của ffmpeg.exe .


Bạn có quản lý để sử dụng nó từ một dự án được nhắm mục tiêu cho .Net Framework (không phải lõi) không? Tôi không chắc chắn những gì tôi đang mất tích ở đây
Yoav Feuerstein

@YoavFeuerstein Có.
orca


10

Tôi đã sử dụng FFmpeg từ ứng dụng dịch vụ ASP.NET / Windows (.NET). Nhưng cuối cùng tôi đã sử dụng dòng lệnh mà không phân tích cú pháp bảng điều khiển. Bằng cách sử dụng điều này - tôi đã có một cách dễ dàng để kiểm soát - cập nhật FFmpeg và chạy nhiều chuyển đổi trên nhiều lõi.


Ok, tôi đã bắt đầu vào một cái gì đó tương tự. Nhưng tôi vẫn hy vọng ai đó có một giải pháp tốt hơn.
Jacob Poul Richardt

4

Bạn có thể sử dụng gói nuget này:

Tôi biết rằng bạn đã hỏi về dự án trưởng thành , nhưng tôi chưa thấy bất kỳ dự án nào đáp ứng đầy đủ mong đợi của tôi nên tôi quyết định làm của riêng tôi. Bạn có thể dễ dàng xếp hàng các chuyển đổi và chạy nó song song, các phương pháp chuyển đổi phương tiện sang các định dạng khác nhau, gửi các đối số của riêng bạn đến ffmpeg và phân tích cú pháp đầu ra từ trình nghe sự kiện ffmpeg + với tiến trình hiện tại.

Install-Package Xabe.FFmpeg

Tôi đang cố gắng tạo trình bao bọc FFmpeg đa nền tảng, dễ sử dụng.

Bạn có thể tìm thêm thông tin về điều này tại https://xabe.net/product/xabe_ffmpeg/

Thông tin thêm tại đây: https://xabe.net/product/xabe_ffmpeg/#documentation

Chuyển đổi rất đơn giản:

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

Nếu bạn muốn tiến bộ:

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

Xin chào ... Tôi cần sử dụng FFMPEG để chuyển mã dữ liệu truyền trực tuyến đến từ một trang web và gửi nó đến máy chủ RTMP. Tôi có mảng byte trong chương trình winform C # của mình. Tôi chỉ cần chuyển mã và gửi đến máy chủ RTMP. Tôi có thể làm điều đó bằng cách sử dụng trình bao bọc này không? Tôi đã làm điều này bằng cách sử dụng máy chủ nodejs sử dụng socketio trong Linux. Trong nền tảng đó, tôi gửi luồng nhị phân qua stdin và nhận trạng thái chuyển đổi trong stderr. Tôi có thể làm điều đó bằng cách sử dụng trình bao bọc Xabe không?
jstuardo

3

Tôi đang chơi với một thư viện trình bao bọc ffmpeg có tên là MediaHandler Pro từ

http://www.mediasoftpro.com

có vẻ hứa hẹn cho đến nay.


Làm thế nào mà điều này giải quyết cho bạn? Ngoài ra, liệu MediaHandlersinh sản ffmpeg.exenhư một quy trình để thực hiện công việc của nó, hay có một thư viện P / Invoke thực tế không?
Glenn Slayden

Tôi đã sử dụng nó trong một vài dự án. Nó hoạt động tốt trong môi trường sản xuất chịu tải nặng. nó đã được một thời gian kể từ khi tôi sử dụng nó, nhưng từ những gì tôi nhớ, vâng, nó sinh ra ffmpeg.exe như một quá trình.
Christophe Chang

3

Tôi đã nghiên cứu điều tương tự và ban đầu sử dụng MediaToolKit (được đề cập trong một câu trả lời khác) hoạt động tốt cho chuyển đổi nhưng bây giờ tôi cần một cái gì đó mạnh mẽ hơn một chút.

Một tùy chọn có vẻ đã trưởng thành và vẫn còn hoạt động là: https://github.com/hudl/HudlFfmpeg Bạn có thể đọc thêm tại đây: http://public.hudl.com/bits/archives/2014/08/15/annocting -hudlffmpeg-ac-framework-to-make-ffmpeg-tương tác-đơn giản /

Một tùy chọn khác, có thể không phù hợp với nhiều trường hợp, là gọi exe trực tiếp từ mã c # của bạn: http://www.codeproject.com/Articles/774093/A Another-FFmpeg-exe-Csharp-Wrapper


2

1
Cảm ơn vì liên kết, nhưng theo như tôi có thể thấy bạn đã viết của bạn bằng Java, không phải int C #.
Jacob Poul Richardt

Xin chào lillemanden, liên kết tôi đưa ra thực sự được triển khai bằng Java, và nếu bạn tải xuống tệp zip ở cuối bài viết, bạn sẽ thấy rằng có một tệp lưu trữ jar bên trong nó. Cảm ơn, Ilya
Ilya

Liên kết trong câu trả lời dường như đã chết: "Không thể truy cập trang web này - ivolo.mit.edu đã mất quá nhiều thời gian để phản hồi."
Pang

2

Đây rồi ... Hầu hết mã này đã hơn 2 năm tuổi nên thiếu rất nhiều nội dung không đồng bộ và sử dụng quy ước đặt tên lỗi thời. Hoạt động trong môi trường sản xuất khá lâu rồi ~ 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();
    }

// đối với công cụ chạy tiến trình, hãy tìm ProcessRunner của 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;

Trình bao bọc này sẽ không để phương thức rơi vào vòng lặp. Hãy thử điều này, nó đã làm việc cho tôi.


1

Tôi đã tách FFPMEG.net từ codeplex.

Vẫn đang được tích cực làm việc.

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

Nó không sử dụng dlls, mà là exe. Vì vậy, nó có xu hướng ổn định hơn.


Có vẻ như những gì tôi đang theo đuổi, nhưng làm thế nào để một người thực hiện điều này trong dự án của họ?
TEK

Thêm dự án này vào dự án của bạn, sau đó đảm bảo FFMPEG đang ở bên trong dự án một cách chính xác. Nó vẫn đang được làm việc.
SpoiledTechie.com

Tôi có thể mã hóa và giải mã khung dưới dạng byte [] bằng FFMPEG.net này không? ví dụ, byte [] encodeh264 (byte []) và byte [] decodeh264 (byte []).
Ahmad

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.