Ubuntu .net core 中使用 ffmpeg

1. FfmpegHelper.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace com.uplus.ffmpeg
{
    /// <summary>
    ///   FfmpegHelper add by cfl  2022-09-14
    /// </summary>
    public  static class FfmpegHelper
    {
        private static System.Diagnostics.ProcessStartInfo cmdFfmpeg;
        private static System.Diagnostics.ProcessStartInfo cmdFfprobe;
        static FfmpegHelper()
        {

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                string ffmpegPath = "/usr/local/ffmpeg/ffmpeg";
                string ffprobePath = "/usr/local/ffmpeg/ffprobe";
                cmdFfmpeg = new System.Diagnostics.ProcessStartInfo(ffmpegPath);
                cmdFfprobe = new System.Diagnostics.ProcessStartInfo(ffprobePath);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                string ffmpegPath = AppDomain.CurrentDomain.BaseDirectory + "ffmpeg\\ffmpeg.exe";
                string ffprobePath = AppDomain.CurrentDomain.BaseDirectory + "ffmpeg\\ffprobe.exe";
                cmdFfmpeg = new System.Diagnostics.ProcessStartInfo(ffmpegPath);
                cmdFfprobe = new System.Diagnostics.ProcessStartInfo(ffprobePath);

            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                string ffmpegPath = "/usr/local/ffmpeg/ffmpeg";
                string ffprobePath = "/usr/local/ffmpeg/ffprobe";
                cmdFfmpeg = new System.Diagnostics.ProcessStartInfo(ffmpegPath);
                cmdFfprobe = new System.Diagnostics.ProcessStartInfo(ffprobePath);
            }

            cmdFfmpeg.RedirectStandardError = false; // 输出错误
            cmdFfmpeg.RedirectStandardOutput = true; //输出打印
            cmdFfmpeg.UseShellExecute = false; //使用Shell
            cmdFfmpeg.CreateNoWindow = true;  //创建黑窗

            cmdFfprobe.RedirectStandardError = false; //set false
            cmdFfprobe.RedirectStandardOutput = true;
            cmdFfprobe.UseShellExecute = false; //set true
            cmdFfprobe.CreateNoWindow = true;  //don't need the black window
        }

        /// <summary>
        /// 获取视频信息 add by cfl  2022-09-14
        /// </summary>
        /// <param name="path"></param>
        public static async Task<string> GetVideoInfo(string path)
        {
            string command = $"-i {path} -print_format json -show_format -show_streams -show_data";
            cmdFfprobe.Arguments = command;

            System.Diagnostics.Process cmd = new System.Diagnostics.Process();
            cmd.StartInfo = cmdFfprobe;
            cmd.Start();

            string InfoStr = await cmd.StandardOutput.ReadToEndAsync();
            cmd.WaitForExit();
            return InfoStr;
        }

        /// <summary>
        /// 视频截图 add by cfl  2022-09-14
        /// </summary>
        /// <param name="path"></param>
        /// <param name="outPath"></param>
        public static void VideoScreenshot(string path, string outPath)
        {
            string command = $"-i {path} -y -q:v 7 -f image2 -t 0.001 {outPath}";
            cmdFfmpeg.Arguments = command;

            System.Diagnostics.Process cmd = new System.Diagnostics.Process();
            cmd.StartInfo = cmdFfmpeg;
            cmd.Start();
            cmd.WaitForExit();
        }


        #region GetMediaTimeLenMinute (秒)
        public static int GetMediaTimeLenMinute(string path)
        {
            int duration = 0;
            string curr_duration = "00:00:00"; //视频时长,格式00:08:50
            System.Diagnostics.Process cmd = new System.Diagnostics.Process();
            cmd.StartInfo = cmdFfmpeg;
            cmd.StartInfo.Arguments = " -i " + path;
            cmd.StartInfo.RedirectStandardOutput = true;
            cmd.StartInfo.UseShellExecute = false;
            cmd.StartInfo.CreateNoWindow = true;
            cmd.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            cmd.StartInfo.RedirectStandardError = true;
            cmd.Start();
            StreamReader errorreader = cmd.StandardError;
            cmd.WaitForExit(1000);
            string result = errorreader.ReadToEnd();
            try
            {
                curr_duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00").Length);
                //do something

            }
            catch (Exception ex)
            {
                //do something
            }
            duration = Convert.ToInt32(curr_duration.Split(':')[0]) * 3600 + Convert.ToInt32(curr_duration.Split(':')[1]) * 60 + Convert.ToInt32(curr_duration.Split(':')[2]);
            return duration;
        }
        #endregion

        #region   ConvertVideo
        public static void ConvertVideo(string sourceFile, string playFile)
        {
            Process cmd = new Process();//建立外部调用线程
            cmd.StartInfo = cmdFfmpeg;

            string strArg = "-i " + sourceFile + " -y -s 640x480 " + playFile + " ";

            cmd.StartInfo.Arguments = strArg;

            cmd.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
            cmd.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
            cmd.StartInfo.CreateNoWindow = false;//不创建进程窗口
            cmd.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
            cmd.Start();//启动线程
            cmd.BeginErrorReadLine();//开始异步读取
            cmd.WaitForExit();//阻塞等待进程结束
            cmd.Close();//关闭进程
            cmd.Dispose();//释放资源
        }
        #endregion

        public static void ConvertToMp4(string webRootPath, string fileName, string fName)
        {
            string path = $"{webRootPath}{Path.DirectorySeparatorChar}Data{Path.DirectorySeparatorChar}{fileName}";
            string newPath = $"{webRootPath}{System.IO.Path.DirectorySeparatorChar}Data{System.IO.Path.DirectorySeparatorChar}{fName}.mp4";
            if (!File.Exists(newPath))
            {
                System.Diagnostics.Process cmd = new System.Diagnostics.Process();
                var startInfo = new ProcessStartInfo();
                cmd.StartInfo = cmdFfmpeg;
                //cmd.StartInfo.Arguments = $" -i {path}  -y -s 640x480 {newPath}";
                 cmd.StartInfo.Arguments = $" -i {path}  -movflags faststart -pix_fmt yuv420p {newPath}";
                // cmd.StartInfo.Arguments = $" -i {path}  -vcodec libx264 -pix_fmt yuv420p {newPath}";
                //cmd.StartInfo.Arguments = $" -i {path}   -c:v libx264 -mbd 0 -c:a aac -strict -2 -pix_fmt yuv420p -movflags faststart {newPath}";
                cmd.StartInfo.RedirectStandardOutput = true;
                cmd.StartInfo.UseShellExecute = false;
                cmd.StartInfo.CreateNoWindow = true;
                cmd.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                cmd.StartInfo.RedirectStandardError = true;
                cmd.Start();
                StreamReader errorreader = cmd.StandardError;
                cmd.WaitForExit(1000);
                string result = errorreader.ReadToEnd();
            }
        }

        #region  Output
        private static void Output(object sendProcess, DataReceivedEventArgs output)
        {
            if (!String.IsNullOrEmpty(output.Data))
            {
                //处理方法...
                //Console.WriteLine(output.Data);

                ////去获取时长
                //string partitio1 = @"Duration: \d{2}:\d{2}:\d{2}.\d{2}";
                //if (RegexHelper.IsMatch(partitio1, output.Data))
                //{
                //    string partition = @"(?<=Duration: )\d{2}:\d{2}:\d{2}.\d{2}";
                //    string timespan = RegexHelper.Matchs(output.Data, partition).FirstOrDefault();
                //    TimeSpan span;
                //    if (TimeSpan.TryParse(timespan, out span))
                //    {
                //        Console.WriteLine(span.TotalMilliseconds);
                //    }
                //}

                ////获取时刻
                //string partitio2 = @"time=\d{2}:\d{2}:\d{2}.\d{2}";
                //if (RegexHelper.IsMatch(partitio2, output.Data))
                //{
                //    string partition = @"(?<=time=)\d{2}:\d{2}:\d{2}.\d{2}";

                //    string timespan = RegexHelper.Matchs(output.Data, partition).FirstOrDefault();
                //    TimeSpan span;
                //    if (TimeSpan.TryParse(timespan, out span))
                //    {
                //        Console.WriteLine(span.TotalMilliseconds);
                //    }
                //}
            }
        }
        #endregion

    }
}


2. 调用
        [HttpGet]
        public ActionResult<ResponseData> GetVideoInfo(string fileName)
        {
            ResponseData result = new ResponseData();
            try
            {
                int duration = FfmpegHelper.GetMediaTimeLenMinute($"{ServiceBase.Get<HostingEnvironment>().WebRootPath}            {System.IO.Path.DirectorySeparatorChar}Data{System.IO.Path.DirectorySeparatorChar}{fileName}");

                result.ErrorCode = 0;
                result.Message = "操作成功";
                result.DataList = new ModelData { 
                    DataList = duration
                };
                return new JsonResult(result);
            }
            catch (Exception ex)
            {
                return this.ControllerExHandler(result, "GetVideoInfo", ex);
            }

        }

3. 效果:
{
    "ErrorCode": 0,
    "Message": "操作成功",
    "Token": null,
    "DataList": {
        "TotalPage": 0,
        "RecordCount": 0,
        "Info": null,
        "DataList": 185
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容