Pembungkus FFmpeg padat untuk C # /. NET

91

Saya telah mencari web untuk beberapa waktu untuk pembungkus FFmpeg yang solid untuk C # /. NET . Tetapi saya belum menemukan sesuatu yang berguna. Saya telah menemukan tiga proyek berikut, tetapi semuanya tampak mati pada tahap alfa awal.

FFmpeg.NET
ffmpeg-sharp
FFLIB.NET

Jadi pertanyaan saya adalah apakah ada yang tahu tentang proyek pembungkus yang lebih matang?
Saya tidak mencari mesin transcoding lengkap dengan antrian pekerjaan dan banyak lagi. Hanya pembungkus sederhana jadi saya tidak perlu membuat panggilan baris perintah dan kemudian mengurai output konsol, tetapi dapat membuat panggilan metode dan menggunakan eventlisteners untuk kemajuan.

Dan jangan ragu untuk menyebutkan proyek aktif apa pun, meskipun proyek tersebut masih dalam tahap awal.

Jacob Poul Richardt
sumber
1
kemungkinan duplikat Ada yang tahu tentang satu set binding C # untuk FFMPEG?
Paŭlo Ebermann
1
Ada yang baru dengan ini? Apakah pembungkus Anda membuat kemajuan?
Avi
3
@Lillemanden Apakah Anda pernah merilis atau membuat open source wrapper Anda?
Nick Benedict
Menarik bahwa pertanyaannya sudah hampir 6 tahun tetapi OP (@JacobPoulRichardt) tidak menerima jawaban apa pun.
Ofer Zelig
1
Saya akhirnya menggunakan pembungkus yang saya buat sendiri, dan karena itu tidak menggunakan proyek yang disarankan. Karena saya tidak lagi bekerja dengan ffmpeg, saya tidak punya waktu untuk kembali dan mencoba salah satunya. Tetapi telah memberi suara positif sebagian besar jawaban setelah membaca sekilas. Jadi saya tidak benar-benar berpikir saya dapat mengatakan bahwa jawaban mana pun lebih "benar" daripada yang lain.
Jacob Poul Richardt

Jawaban:

24

Ini adalah pembungkus saya sendiri: https://github.com/AydinAdn/MediaToolkit

MediaToolkit dapat:

  • Konversikan file video ke dalam berbagai format video lainnya.
  • Lakukan tugas transcoding video.
    • Pilihan konfigurasi: Bit rate, Frame rate, Resolution / size, Aspect ratio,Duration of video
  • Lakukan tugas transcoding audio.
    • Opsi dapat dikonfigurasi: Audio sample rate
  • Konversi video ke format fisik menggunakan standar TV FILM, PAL atau NTSC
    • Media meliputi: DVD, DV, DV50, VCD,SVCD

Saya memperbaruinya saat saya melanjutkan, dan Anda dipersilakan untuk menggunakannya, Anda juga dapat menginstalnya menggunakan Package Manager Console.

PM> Install-Package MediaToolkit
Aydin
sumber
Dapatkah toolkit Anda mux / membuat klip video dan audio yang berbeda menjadi salah satu resolusi keluaran yang diberikan?
Antonio Petricca
Tidak, itu dirancang untuk digunakan bagi orang-orang yang mengejar konversi sederhana. Konon, ada v2 yang akan segera hadir yang akan memungkinkan Anda untuk melakukan semua yang ditawarkan FFmpeg.
Aydin
Terima kasih Aydin, beri tahu saya tentang rilis baru ini.
Antonio Petricca
Tampak luar biasa! Kerja bagus sejauh ini!
SpoiledTechie.com
Hai Aydin, bisakah ini juga merekam layar?
TEK
14

Setelah mencoba beberapa pembungkus, saya melanjutkan dengan ini: FFmpeg otomatis menghasilkan pengikatan yang tidak aman untuk C # /. NET dan Mono .

Ini adalah satu set binding interop tingkat rendah untuk setiap kelas di namespace FFmpeg. Mungkin tidak senyaman untuk digunakan sebagai pembungkus yang sebenarnya, tetapi IMO adalah solusi terbaik untuk bekerja dengan FFmpeg di .Net, jika Anda ingin melakukan hal-hal yang tidak sepele.

Kelebihan:

  • Bekerja
  • Dapat dipercaya - tidak ada kode pembungkus pihak ketiga untuk memperkenalkan bug, dengan asumsi Anda mempercayai FFMpeg itu sendiri.
  • FFmpeg selalu diperbarui ke versi terbaru
  • Paket nuget tunggal untuk semua binding
  • Dokumentasi XML disertakan tetapi Anda masih dapat menggunakan dokumentasi FFmpeg dokumentasi online .

Kekurangan:

  • Level rendah: Anda harus tahu cara bekerja dengan pointer ke c struct .
  • Membutuhkan beberapa pekerjaan pada awalnya untuk membuatnya berfungsi. Saya menyarankan untuk belajar dari contoh resmi .

Catatan: utas ini adalah tentang menggunakan FFmpeg API, tetapi untuk beberapa kasus penggunaan, sebaiknya gunakan antarmuka baris perintah ffmpeg.exe .

orca
sumber
Apakah Anda berhasil menggunakannya dari proyek yang ditargetkan untuk .Net Framework (bukan inti)? Saya tidak yakin apa yang saya lewatkan di sini
Yoav Feuerstein
@Yoaveuerstein Ya.
orca
10

Saya telah menggunakan FFmpeg dari aplikasi ASP.NET / Windows service (.NET). Tapi saya akhirnya menggunakan baris perintah, tanpa mengurai konsol. Dengan menggunakan ini - saya memiliki cara mudah untuk mengontrol - pembaruan FFmpeg dan menjalankan banyak konversi pada banyak Cores.

Famdam
sumber
Oke, saya mulai dengan yang serupa. Tapi saya masih berharap seseorang memiliki solusi yang lebih baik.
Jacob Poul Richardt
4

Anda dapat menggunakan paket nuget ini:

Saya tahu bahwa Anda bertanya tentang proyek yang matang , tetapi saya belum melihat proyek apa pun yang memenuhi harapan saya, jadi saya memutuskan untuk membuatnya sendiri. Anda dapat dengan mudah mengantri konversi dan menjalankannya secara paralel, metode untuk mengonversi media ke format yang berbeda, mengirim argumen Anda sendiri ke ffmpeg dan mengurai keluaran dari ffmpeg + event listener dengan kemajuan saat ini.

Install-Package Xabe.FFmpeg

Saya mencoba membuat pembungkus FFmpeg lintas platform yang mudah digunakan.

Anda dapat menemukan informasi lebih lanjut tentang ini di https://xabe.net/product/xabe_ffmpeg/

Info lebih lanjut di sini: https://xabe.net/product/xabe_ffmpeg/#documentation

Konversi sederhana:

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

Jika Anda menginginkan kemajuan:

IConversion conversion = Conversion.ToMp4(Resources.MkvWithAudio, output);
conversion.OnProgress += (duration, length) => { currentProgress = duration; } 
await conversion.Start();
Tomasz Żmuda
sumber
Halo ... Saya perlu menggunakan FFMPEG untuk mentranskode data streaming yang berasal dari halaman web dan mengirimkannya ke server RTMP. Saya memiliki array byte dalam program winform C # saya. Saya hanya perlu melakukan transcode dan mengirim ke server RTMP. Bisakah saya melakukannya menggunakan pembungkus ini? Saya melakukan ini menggunakan server nodejs menggunakan socketio di Linux. Di platform itu, saya mengirim aliran biner melalui stdin dan menerima status konversi di stderr. Bisakah saya melakukannya menggunakan pembungkus Xabe?
jstuardo
3

Saya bermain-main dengan perpustakaan pembungkus ffmpeg yang disebut MediaHandler Pro dari

http://www.mediasoftpro.com

tampaknya menjanjikan sejauh ini.

Christophe Chang
sumber
Bagaimana ini berhasil untuk Anda? Juga, apakah MediaHandlerspawn ffmpeg.exesebagai proses untuk melakukan tugasnya, atau apakah ada pustaka P / Invoke yang sebenarnya?
Glenn Slayden
Saya akhirnya menggunakannya dalam beberapa proyek. Ini bekerja dengan baik dalam lingkungan produksi di bawah beban berat. sudah lama sejak saya menggunakannya, tetapi dari yang saya ingat, ya itu menelurkan ffmpeg.exe sebagai sebuah proses.
Christophe Chang
3

Saya telah meneliti hal yang sama dan awalnya menggunakan MediaToolKit (disebutkan dalam jawaban lain) yang bekerja sangat baik untuk konversi tetapi sekarang saya membutuhkan sesuatu yang sedikit lebih kuat.

Salah satu opsi yang tampaknya dewasa dan masih aktif adalah: https://github.com/hudl/HudlFfmpeg Yang dapat Anda baca lebih lanjut di sini: http://public.hudl.com/bits/archives/2014/08/15/announcing -hudlffmpeg-ac-framework-to-make-ffmpeg-interaksi-sederhana /

Pilihan lain, yang mungkin tidak cocok untuk banyak kasus, adalah memanggil exe langsung dari kode c # Anda: http://www.codeproject.com/Articles/774093/Another-FFmpeg-exe-Csharp-Wrapper

ickydime.dll
sumber
2

Ada satu lagi yang sederhana di sini: http://ivolo.mit.edu/post/Metamorph-Convert-Audio-Video-to-Any-Format-on-Windows-Linux-and-Mac.aspx

Ilya
sumber
1
Terima kasih untuk tautannya, tetapi sejauh yang saya lihat Anda menulis milik Anda di Java, bukan int C #.
Jacob Poul Richardt
Halo lillemanden, tautan yang saya berikan sebenarnya diimplementasikan di Java, dan jika Anda mengunduh zip di bagian bawah artikel, Anda akan melihat bahwa ada file arsip jar di dalamnya. Terima kasih, Ilya
Ilya
Tautan di jawaban tampaknya mati: "Situs ini tidak dapat dihubungi - ivolo.mit.edu terlalu lama untuk merespons."
Pang
2

Ini dia ... Sebagian besar kode ini berumur 2+ tahun jadi kehilangan banyak hal asinkron, dan menggunakan konvensi penamaan yang sudah ketinggalan zaman. Berjalan dalam lingkungan produksi untuk beberapa waktu ~ 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();
    }

// untuk proses runner, cari ProcessRunner oleh Roger Knapp

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

Wrapper ini tidak akan membiarkan metode ini berputar-putar. Coba ini, itu berhasil untuk saya.

Mrinal
sumber
1

Saya bercabang FFPMEG.net dari codeplex.

Masih aktif dikerjakan.

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

Itu tidak menggunakan dll, melainkan exe. Jadi cenderung lebih stabil.

SpoiledTechie.com
sumber
Sepertinya apa yang saya cari, tetapi bagaimana cara menerapkan ini dalam proyek mereka?
TEK
Tambahkan proyek ini ke proyek Anda, lalu pastikan FFMPEG berada di dalam proyek dengan benar. Ini masih dikerjakan.
SpoiledTechie.com
Dapatkah saya menyandikan dan mendekode bingkai sebagai byte [] menggunakan FFMPEG.net ini? misalnya, byte [] encodeh264 (byte []) dan byte [] decodeh264 (byte []).
Ahmad