Тверда обгортка FFmpeg для C # /. NET


91

Я шукав в Інтернеті певний час надійну обгортку FFmpeg для C # /. NET . Але я ще не придумав чогось корисного. Я виявив наступні три проекти, але всі вони виявляються мертвими на ранній альфа-стадії.

FFmpeg.NET
ffmpeg-різкий
FFLIB.NET

Тож моє запитання: чи хтось знає про проект обгортки, який є більш зрілим?
Я не шукаю повного механізму перекодування з чергами на роботу та іншим. Просто проста обгортка, тому мені не потрібно робити виклик командного рядка, а потім аналізувати висновок консолі, але я можу здійснювати виклики методів і використовувати прогресивники подій.

І, будь ласка, не соромтеся згадувати будь-які активні проекти, навіть якщо вони ще непогашені на початкових стадіях.



1
Щось нове з цим? Чи досяг ваш обгортка якийсь прогрес?
Аві

3
@Lillemanden, ви коли-небудь випускали або відкривали свою обгортку?
Нік Бенедикт,

Цікаво, що питанню майже 6 років, але ОП (@JacobPoulRichardt) не прийняв жодної відповіді.
Ofer Zelig

1
У підсумку я використав обгортку, яку зробив сам, і як такий не використав жодного із запропонованих проектів. Оскільки я більше не працюю з ffmpeg, у мене не було часу повернутися і спробувати будь-який з них. Але підтримали більшість відповідей після їх обробки. Тож я не дуже думаю, що можу сказати, що будь-яка з відповідей є більш "правильною", ніж інші.
Jacob Poul Richardt

Відповіді:


24

Це моя обгортка: https://github.com/AydinAdn/MediaToolkit

MediaToolkit може:

  • Перетворюйте відеофайли в різні інші відеоформати.
  • Виконуйте завдання з перекодування відео.
    • Варіанти конфігурації: Bit rate, Frame rate, Resolution / size, Aspect ratio,Duration of video
  • Виконуйте завдання з перекодування звуку.
    • Параметри, які можна налаштувати: Audio sample rate
  • Перетворюйте відео у фізичний формат, використовуючи телевізійні стандарти FILM, PAL або NTSC
    • Медіуми включають в себе: DVD, DV, DV50, VCD,SVCD

Я оновлюю його в міру подальшого використання, і ви можете використовувати його, ви також можете встановити його за допомогою консолі диспетчера пакетів.

PM> Install-Package MediaToolkit

Чи може ваш набір інструментів мультиплексувати / відтворювати різні відео- та аудіокліпи в одній із заданих вихідних дозволів?
Антоніо Петрічка,

Ні, він був розроблений для використання людьми, які переслідували прості перетворення. Тим не менш, найближчим часом виходить v2, який дозволить вам зробити все, що пропонує FFmpeg.
Айдин

Дякую Айдин, будь ласка, повідомте мене про цей новий випуск.
Антоніо Петрікка

Виглядає казково! Поки що гарна робота!
SpoiledTechie.com

Ей Айдіне, чи може це також записати екран?
ТЕК

14

Спробувавши кілька обгортків, я пішов із цим: FFmpeg автоматично генерував небезпечні прив'язки для C # /. NET та Mono .

Це набір прив'язок низького рівня взаємодії для кожного класу у просторі імен FFmpeg. Можливо, не такий зручний у використанні, як справжня обгортка, але IMO - це найкраще рішення для роботи з FFmpeg у .Net, якщо ви хочете робити нетривіальні речі.

Плюси:

  • Працює
  • Надійний - немає стороннього коду обгортки для введення помилок, якщо ви довіряєте самому FFMpeg.
  • Він завжди оновлюється до останньої версії FFmpeg
  • Єдиний самородний пакет для всіх прив'язок
  • Документація XML включена, але ви все ще можете користуватися документацією FFmpeg в режимі онлайн .

Мінуси:

  • Низький рівень: Ви повинні знати, як працювати з покажчиками на конструкції .
  • Спочатку потрібна певна робота, щоб вона працювала. Пропоную почерпнути на офіційних прикладах .

Примітка: цей потік стосується використання API FFmpeg, але для деяких випадків використання найкраще просто використовувати інтерфейс командного рядка ffmpeg.exe .


Чи вдалося вам використати його з проекту, призначеного для .Net Framework (не основного)? Я не впевнений, чого мені тут не вистачає
Йоав

@YoavFeuerstein Так.
orca


10

Я використовував FFmpeg із програми ASP.NET / Windows (.NET). Але в підсумку я використав командний рядок, не розбираючи консоль. Використовуючи це - у мене був простий спосіб контролю - оновлення FFmpeg та запуск декількох перетворень на декількох ядрах.


Добре, я розпочав щось подібне. Але я все ще сподіваюся, що хтось має краще рішення.
Jacob Poul Richardt

4

Ви можете використовувати цей 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. У мене є масив байтів у моїй програмі winform на C #. Мені потрібно лише перекодувати та відправити на сервер RTMP. Чи можу я це зробити, використовуючи цю обгортку? Я зробив це за допомогою сервера nodejs, використовуючи socketio в Linux. На цій платформі я надсилаю двійковий потік через stdin і отримую статус перетворення в stderr. Чи можу я це зробити за допомогою обгортки Xabe?
jstuardo

3

Я граюся з бібліотекою обгортки ffmpeg під назвою MediaHandler Pro від

http://www.mediasoftpro.com

поки що здається перспективним.


Як це у вас вийшло? Крім того, MediaHandlerнерест ffmpeg.exe- це процес виконання своєї роботи, чи існує справжня бібліотека P / Invoke?
Гленн Слейден,

У підсумку я використав його у кількох проектах. Він добре працював у виробничих умовах під великим навантаженням. минув деякий час, як я його використовував, але, наскільки я пам’ятаю, так, він породжує ffmpeg.exe як процес.
Крістоф Чанг

3

Я досліджував те саме, і спочатку використовував MediaToolKit (згаданий в іншій відповіді), який чудово працював для конверсій, але зараз мені потрібно щось більш надійне.

Одним із варіантів, який здається зрілим і все ще активним, є: https://github.com/hudl/HudlFfmpeg, про який ви можете прочитати більше тут: http://public.hudl.com/bits/archives/2014/08/15/announcing -hudlffmpeg-ac-framework-to-make-ffmpeg-interaction-simple /

Іншим варіантом, який може не підходити для багатьох випадків, є виклик exe безпосередньо з коду вашого c #: http://www.codeproject.com/Articles/774093/Another-FFmpeg-exe-Csharp-Wrapper


2

1
Дякую за посилання, але наскільки я бачу, ви написали своє на Java, а не на int C #.
Jacob Poul Richardt

Привіт, lillemanden, посилання, яке я дав, насправді реалізовано в Java, і якщо ви завантажите zip внизу статті, то побачите, що в ньому є файл архіву jar. Дякую, Ілля
Ілля

Посилання у відповіді здається мертвим: "Цей веб-сайт недоступний - ivolo.mit.edu відповів занадто довго".
Pang

2

Ось так ... Більшій частині цього коду 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();
    }

// для матеріалу про бігу процесів шукайте ProcessRunner від Роджера Кнаппа


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;

Ця обгортка не дозволить методу потрапити в цикл. Спробуйте це, мені це вдалося.


1

Я розгалужив FFPMEG.net від codeplex.

Досі активно працює над цим.

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

Він використовує не dll, а швидше exe. Тож він має тенденцію бути більш стабільним.


Схоже на те, що я шукаю, але як це реалізувати у своєму проекті?
ТЕК

Додайте цей проект до свого проекту, а потім переконайтеся, що FFMPEG правильно сидить усередині проекту. Над цим ще працюють.
SpoiledTechie.com

Чи можу я кодувати та декодувати кадр як байт [] за допомогою цього FFMPEG.net? наприклад, байт [] encodeh264 (байт []) і байт [] decodeh264 (байт []).
Ахмад,

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.