กระดาษห่อ FFmpeg แบบทึบสำหรับ C # /. NET


91

ฉันได้รับการค้นหาเว็บสำหรับเวลาบางส่วนสำหรับของแข็ง FFmpegเสื้อคลุมสำหรับC # /. NET แต่ฉันยังไม่ได้คิดอะไรที่เป็นประโยชน์ ฉันพบสามโปรเจ็กต์ต่อไปนี้ แต่ทั้งหมดดูเหมือนจะตายในช่วงอัลฟ่าแรก ๆ

FFmpeg.NET
ffmpeg คมชัด
FFLIB.NET

คำถามของฉันคือถ้าใครรู้โครงการเสื้อคลุมที่เป็นผู้ใหญ่กว่านี้?
ฉันไม่ได้มองหาเอ็นจิ้นการแปลงรหัสที่มีคิวงานและอื่น ๆ อีกมากมาย เป็นเพียง wrapper ธรรมดา ๆ ดังนั้นฉันจึงไม่ต้องทำการเรียกบรรทัดคำสั่งแล้วแยกวิเคราะห์เอาต์พุตคอนโซล แต่สามารถเรียกวิธีการและใช้ eventlisteners เพื่อความคืบหน้า

และโปรดอย่าลังเลที่จะพูดถึงโครงการที่กำลังดำเนินอยู่แม้ว่าจะยังคงอยู่ในช่วงแรกก็ตาม



1
มีอะไรใหม่หรือไม่? เสื้อคลุมของคุณมีความคืบหน้าหรือไม่?
Avi

3
@Lillemanden คุณเคยปล่อยหรือโอเพ่นซอร์สเสื้อคลุมของคุณหรือไม่?
Nick Benedict

น่าสนใจที่คำถามนี้มีอายุเกือบ 6 ปี แต่ OP (@JacobPoulRichardt) ไม่ยอมรับคำตอบใด ๆ
Ofer Zelig

1
ฉันลงเอยด้วยการใช้กระดาษห่อหุ้มที่ฉันทำขึ้นเองและด้วยเหตุนี้จึงไม่ได้ใช้โครงการที่แนะนำเลย เนื่องจากฉันไม่ได้ทำงานกับ ffmpeg อีกต่อไปฉันจึงไม่มีเวลากลับไปลองทำอะไรเลย แต่ให้คะแนนคำตอบส่วนใหญ่หลังจากอ่านข้ามไปแล้ว ดังนั้นฉันจึงไม่คิดว่าจะสามารถพูดได้ว่าคำตอบใด "ถูกต้อง" มากกว่าคำตอบอื่น ๆ
Jacob Poul Richardt

คำตอบ:


23

นี่คือเสื้อคลุมของฉันเอง: 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

ชุดเครื่องมือของคุณสามารถ mux / แสดงวิดีโอและคลิปเสียงที่แตกต่างกันเป็นหนึ่งในความละเอียดเอาต์พุตที่กำหนดได้หรือไม่?
Antonio Petricca

ไม่ได้ออกแบบมาเพื่อใช้สำหรับผู้ที่ไล่ตาม Conversion ง่ายๆ ที่กล่าวว่ามี v2 เร็ว ๆ นี้ซึ่งจะช่วยให้คุณสามารถทำทุกอย่างที่ FFmpeg นำเสนอได้
Aydin

ขอบคุณ Aydin โปรดแจ้งให้ฉันทราบเกี่ยวกับรุ่นใหม่นี้
Antonio Petricca

ดูดีมาก! ทำได้ดีมาก!
SpoiledTechie.com

เฮ้ไอดินนี่อัดหน้าจอได้ด้วยเหรอ?
TEK

14

หลังจากที่พยายามหลายห่อผมไปด้วยนี้FFmpeg สร้างอัตโนมัติผูกที่ไม่ปลอดภัยสำหรับ C # / NET และโมโน.

เป็นชุดของการเชื่อมโยงระหว่างกันระดับต่ำสำหรับทุกคลาสในเนมสเปซ FFmpeg อาจไม่สะดวกเท่าที่จะใช้เป็นกระดาษห่อหุ้มจริง แต่ IMO เป็นทางออกที่ดีที่สุดสำหรับการทำงานกับ FFmpeg ใน. Net หากคุณต้องการทำสิ่งที่ไม่สำคัญ

ข้อดี:

  • ผลงาน
  • น่าเชื่อถือ - ไม่มีรหัส Wrapper ของบุคคลที่สามที่จะแนะนำจุดบกพร่องโดยสมมติว่าคุณเชื่อถือ FFMpeg
  • อัปเดตเป็น FFmpeg เวอร์ชันล่าสุดอยู่เสมอ
  • แพ็คเกจนักเก็ตเดี่ยวสำหรับการผูกทั้งหมด
  • รวมเอกสาร XML แต่คุณยังสามารถใช้เอกสารFFmpegเอกสารออนไลน์ได้

จุดด้อย:

  • ระดับต่ำสุด: คุณต้องรู้วิธีการทำงานกับตัวชี้ไปยังstructs
  • ต้องทำงานบางอย่างในขั้นต้นเพื่อให้มันใช้งานได้ ฉันขอแนะนำให้เรียนรู้จากตัวอย่างเป็นทางการ

หมายเหตุ: หัวข้อนี้เป็นเรื่องเกี่ยวกับการใช้ FFmpeg API แต่สำหรับกรณีการใช้งานบางอย่างที่ดีที่สุดที่จะเพียงแค่ใช้ ffmpeg.exe ของอินเตอร์เฟซบรรทัดคำสั่ง


คุณจัดการเพื่อใช้งานจากโครงการที่กำหนดเป้าหมายสำหรับ. Net Framework (ไม่ใช่แกนหลัก) หรือไม่? ฉันไม่แน่ใจว่าฉันพลาดอะไรที่นี่
Yoav Feuerstein

@YoavFeuerstein ค่ะ
orca

10

ลองดูสิฉันคิดว่าฉันอาจจะเขียนสิ่งที่คุณสามารถใช้สำหรับกระดาษห่อธรรมดา

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


ขอบคุณ แต่ฉันเริ่มเขียนของตัวเอง แต่ฉันจะเลือกไอเดียบางอย่างไม่ได้
Jacob Poul Richardt

10

ฉันใช้ FFmpeg จากแอปพลิเคชัน ASP.NET / Windows service (.NET) แต่ฉันลงเอยด้วยการใช้บรรทัดคำสั่งโดยไม่แยกวิเคราะห์คอนโซล ด้วยการใช้สิ่งนี้ - ฉันมีวิธีง่ายๆในการควบคุม - อัปเดต FFmpeg และเรียกใช้การแปลงหลายรายการในหลายคอร์


โอเคฉันเริ่มจากสิ่งที่คล้ายกัน แต่ฉันหวังว่าใครบางคนจะมีทางออกที่ดีกว่า
Jacob Poul Richardt

4

คุณสามารถใช้แพ็คเกจ nuget นี้:

ฉันรู้ว่าคุณถามเกี่ยวกับโปรเจ็กต์สำหรับผู้ใหญ่แต่ฉันไม่เห็นโปรเจ็กต์ใดที่ตอบสนองความคาดหวังของฉันได้เต็มที่ดังนั้นฉันจึงตัดสินใจทำด้วยตัวเอง คุณสามารถจัดคิวการแปลงได้อย่างง่ายดายและเรียกใช้แบบขนานวิธีการแปลงสื่อเป็นรูปแบบต่างๆส่งอาร์กิวเมนต์ของคุณเองไปยัง ffmpeg และแยกวิเคราะห์เอาต์พุตจาก ffmpeg + event listener พร้อมความคืบหน้าในปัจจุบัน

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 เท่านั้น ฉันสามารถทำได้โดยใช้กระดาษห่อหุ้มนี้หรือไม่? ฉันทำสิ่งนี้โดยใช้เซิร์ฟเวอร์ nodejs โดยใช้ socketio ใน Linux ในแพลตฟอร์มนั้นฉันส่งสตรีมไบนารีผ่าน stdin และรับสถานะการแปลงใน stderr ฉันสามารถใช้กระดาษห่อ Xabe ได้หรือไม่?
jstuardo

3

ฉันกำลังเล่นกับไลบรารีกระดาษห่อ ffmpeg ชื่อ MediaHandler Pro จาก

http://www.mediasoftpro.com

ดูเหมือนว่าจะมีแนวโน้มที่ดี


วิธีนี้ได้ผลสำหรับคุณ? นอกจากนี้การMediaHandlerวางไข่ffmpeg.exeเป็นกระบวนการในการทำงานหรือมีไลบรารี P / Invoke จริงหรือไม่?
Glenn Slayden

ฉันใช้มันในสองสามโครงการ ทำงานได้ดีในสภาพแวดล้อมการผลิตภายใต้ภาระหนัก เป็นเวลานานแล้วที่ฉันใช้มัน แต่จากสิ่งที่ฉันจำได้ใช่มันวางไข่ ffmpeg.exe เป็นกระบวนการ
Christophe Chang

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 อยู่ข้างใน ขอบคุณ Ilya
Ilya

ดูเหมือนว่าลิงก์ในคำตอบจะไม่สมบูรณ์: "ไม่สามารถเข้าถึงไซต์นี้ได้ - ivolo.mit.edu ใช้เวลาตอบกลับนานเกินไป"
ปาง

2

เอาล่ะ ... รหัสนี้ส่วนใหญ่มีอายุ 2 ปีขึ้นไปจึงขาดข้อมูลแบบอะซิงโครนัสจำนวนมากและใช้หลักการตั้งชื่อที่ล้าสมัย ทำงานในสภาพแวดล้อมการผลิตมาระยะหนึ่งแล้ว ~ จขกท

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 โดย 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;

เครื่องห่อนี้จะไม่ปล่อยให้วิธีการตกอยู่ในวง ลองนี้มันได้ผลสำหรับฉัน


1

ฉันแยก FFPMEG.net จาก codeplex

ยังคงทำงานอย่างแข็งขัน

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

มันไม่ได้ใช้ dlls แต่เป็น exe ดังนั้นจึงมีแนวโน้มที่จะมีเสถียรภาพมากขึ้น


ดูเหมือนว่าฉันกำลังตามหา แต่จะนำสิ่งนี้ไปใช้ในโครงการได้อย่างไร
TEK

เพิ่มโปรเจ็กต์นี้ในโปรเจ็กต์ของคุณจากนั้นตรวจสอบว่า FFMPEG นั่งอยู่ภายในโปรเจ็กต์อย่างถูกต้อง มันยังคงทำงานอยู่
SpoiledTechie.com

ฉันสามารถเข้ารหัสและถอดรหัสเฟรมเป็นไบต์ [] โดยใช้ FFMPEG.net นี้ได้หรือไม่ ตัวอย่างเช่น byte [] encodeh264 (byte []) และ byte [] decodeh264 (byte [])
Ahmad

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.