二、实践与视频解决方案

摘要:
“);Console.ReadKey();}staticvoidRunMyProcess{varp=newProcess();p.StartInfo.FileName=FFmpegPath;p.StartInfo。Arguments=参数;//是否使用操作系统shell启动p.StartInfo.UseShellExecute=false;//不显示程序窗口p.StartInfo.CreateNoWindow=true;p.start();Console.WriteLine;p.WaitForExit();p.Close(),p.Dispose();//释放资源}}}exe文件被导入,但由于ffmpeg视频转码,程序被卡住,在转码完成后没有收到退出消息,因为ffmpeg是StandardError流,需要读取StandardError而不是StandardOutput。使用系统;使用System.Collections.Generic;使用System.Diagnostics;使用System.Linq;使用System.Text;使用System.Threading.Tasks;Namespaceffmpeg{classProgram{staticstringFFmpegPath=@“C:UsersBrucesourceepossffmpegffmpeginDebugfffmmpeg-20190820-74e6800-win64-static inflmpeg.exe”;staticvoidMain{stringvideoUrl=@“D:videoWildlife.mp4”;stringtargetUrl=“D:videoewFile2。mp4“;//视频转码stringpara=string.Format;RunMyProcess;Console.WriteLine(“转码结束时间:”+DateTime.Now.ToString(“yyyy-MM-ddhh:MM:ss”)+“完成!

一、视频解决方案

说明:

公司下户拍摄视频,上传存储一直用的优酷云(视频压缩、解码、播放)当然还支持水印。二、实践与视频解决方案第1张

现在场景,我们公司内部买服务器,下户拍摄视频上传到我们自己服务内,需要解决的问题,下户拍摄视频很大,需要解决的问题:

1、(下户视频过大)需要压缩处理、

2、(视频格式、播放帧处理)解码格式

3、(提供url)提供接口让内部人员可以播放

 解决方案1、亲测

使用官网:ffmpeg 、GitHub:https://github.com/FFmpeg/FFmpeg

二、实践与视频解决方案第2张

 二、实践与视频解决方案第3张

 二、实践与视频解决方案第4张

在下载页面上,我们可以看到,对于32位和64位版本,分别提供了三种不同的模式:static、shared和dev

  • static: 该版本提供了静态版本的FFmpeg工具,将依赖的库生成在了最终的可执行文件中;作为工具而言此版本就可以满足我们的需求;
  • share: 该版本的工具包括可执行文件和dll,程序运行过程必须依赖于提供的dll文件;
  • dev: 提供了库的头文件和dll的引导库;

 二、实践与视频解决方案第5张

这里下载的是static版本,将其下载解压到项目目录下:

C#代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ffmpeg
{
    class Program
    {
        static string FFmpegPath = @"C:UsersBrucesource
eposffmpegffmpeginDebugffmpeg-20190820-74e6800-win64-staticinffmpeg.exe";
        static void Main(string[] args)
        {
            string videoUrl = @"D:videoWildlife.wmv";
            string targetUrl = @"D:video
ewFile.mp4";

            //视频转码
            string para = string.Format("-i {0} -b 1024k -acodec copy -f mp4 {1}", videoUrl, targetUrl);
            RunMyProcess(para);
            Console.WriteLine("完成!");
            Console.ReadKey();

        }
        static void RunMyProcess(string Parameters)
        {
            var p = new Process();
            p.StartInfo.FileName = FFmpegPath;
            p.StartInfo.Arguments = Parameters;
            //是否使用操作系统shell启动
            p.StartInfo.UseShellExecute = false;
            //不显示程序窗口
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            Console.WriteLine("
开始转码...
");
            p.WaitForExit();
            p.Close();
            p.Dispose();//释放资源
        }

    }
}

引入exe文件

二、实践与视频解决方案第6张

但是由于ffmpeg视频转码,转码完成后程序一直卡死且一直未收到exit消息,

原因是ffmpeg是StandardError流,要读取StandardError而不是StandardOutput。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ffmpeg
{
    class Program
    {
        static string FFmpegPath = @"C:UsersBrucesource
eposffmpegffmpeginDebugffmpeg-20190820-74e6800-win64-staticinffmpeg.exe";
        static void Main(string[] args)
        {
            string videoUrl = @"D:videoWildlife.mp4";
            string targetUrl = @"D:video
ewFile2.mp4";
            //视频转码
            string para = string.Format("-i {0} -r 10 -b:a 32k {1}", videoUrl, targetUrl);
            RunMyProcess(para);
            Console.WriteLine("转码结束时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "
完成!");
            Console.ReadKey();
        }
        static void RunMyProcess(string Parameters)
        {
            var p = new Process();
            p.StartInfo.FileName = FFmpegPath;
            p.StartInfo.Arguments = Parameters;
            //是否使用操作系统shell启动
            p.StartInfo.UseShellExecute = false;
            //不显示程序窗口
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
            p.Start();
            p.BeginErrorReadLine();//开始异步读取
            Console.WriteLine("转码开始时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "
开始转码...
");
            p.WaitForExit();//阻塞等待进程结束
            p.Close();//关闭进程
            p.Dispose();//释放资源
        }
        private static void Output(object sendProcess, DataReceivedEventArgs output)
        {
            if (!String.IsNullOrEmpty(output.Data))
            {
                //处理方法...
                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")+":" +output.Data);
            }
        }

    }
}

二、实践与视频解决方案第7张

2、视频大小信息

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ffmpeg
{
    class Program
    {
        static string FFmpegPath = @"C:UsersBrucesource
eposffmpegffmpeginDebugffmpeg-20190820-74e6800-win64-staticinffmpeg.exe";
        static void Main(string[] args)
        {
            string videoUrl = @"D:videoWildlife.MP4";
            //视频转码
            int time = GetVideoDuration(FFmpegPath, videoUrl);
            Console.WriteLine("视频时间:" + time + "");
            Console.ReadKey();
        }

        private static int GetVideoDuration(string ffmpegfile, string sourceFile)
        {
            try
            {
                using (System.Diagnostics.Process ffmpeg = new System.Diagnostics.Process())
                {
                    String duration;  // soon will hold our video‘s duration in the form "HH:MM:SS.UU"  
                    String result;  // temp variable holding a string representation of our video‘s duration  
                    StreamReader errorreader;  // StringWriter to hold output from ffmpeg  
                    // we want to execute the process without opening a shell  
                    ffmpeg.StartInfo.UseShellExecute = false;
                    //ffmpeg.StartInfo.ErrorDialog = false;  
                    ffmpeg.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                    // redirect StandardError so we can parse it  
                    // for some reason the output comes through over StandardError  
                    ffmpeg.StartInfo.RedirectStandardError = true;
                    // set the file name of our process, including the full path  
                    // (as well as quotes, as if you were calling it from the command-line)  
                    ffmpeg.StartInfo.FileName = ffmpegfile;
                    // set the command-line arguments of our process, including full paths of any files  
                    // (as well as quotes, as if you were passing these arguments on the command-line)  
                    ffmpeg.StartInfo.Arguments = "-i " + sourceFile;
                    // start the process  
                    ffmpeg.Start();
                    // now that the process is started, we can redirect output to the StreamReader we defined  
                    errorreader = ffmpeg.StandardError;
                    // wait until ffmpeg comes back  
                    ffmpeg.WaitForExit();
                    // read the output from ffmpeg, which for some reason is found in Process.StandardError  
                    result = errorreader.ReadToEnd();
                    // a little convoluded, this string manipulation...  
                    // working from the inside out, it:  
                    // takes a substring of result, starting from the end of the "Duration: " label contained within,  
                    // (execute "ffmpeg.exe -i somevideofile" on the command-line to verify for yourself that it is there)  
                    // and going the full length of the timestamp  
                    duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00").Length);
                    string[] ss = duration.Split(':');
                    int h = int.Parse(ss[0]);
                    int m = int.Parse(ss[1]);
                    int s = int.Parse(ss[2]);
                    return h * 3600 + m * 60 + s;
                }
            }
            catch (System.Exception ex)
            {
                return 60;
            }
        }
    }
}

二、实践与视频解决方案第8张

 二、实践与视频解决方案第9张

3、视频进度百分比

 二、实践与视频解决方案第10张

 二、实践与视频解决方案第11张

 二、实践与视频解决方案第12张

 代码  转码进度公式=当前时间/总时间*100

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ffmpeg
{
    class Program
    {
        static void Main(string[] args)
        {
            FFmpeg.Execute();
            Console.ReadKey();
        }
    }
    public class FFmpeg
    {
        static int timeCount;
        public static void Execute()
        {
            string ffmpegPath = @"C:UsersBrucesource
eposffmpegffmpeginDebugffmpeg-20190820-74e6800-win64-staticinffmpeg.exe";
            Process p = new Process();
            p.StartInfo.FileName = ffmpegPath;
            p.StartInfo.UseShellExecute = false;
            string videoUrl = @"D:video\_Wildlife.mp4";
            string targetUrl = @"D:video
ewFile15.mp4";
            //视频转码
            string para = string.Format("-i {0} -r 10 -b:a 32k {1}", videoUrl, targetUrl);
            p.StartInfo.Arguments = para;  //执行参数
            //-i D:/vts-collector/test/swap/7a3c9800-2e2f-42fe-ba39-56b25f972e06.mov -y -ab 56 -ar 22050 -b 800 -r 29.97 -s 420x340 D:/vts-collector/test/swap/7a3c9800-2e2f-42fe-ba39-56b25f972e06_mov_stream.mp4
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中
            p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
            p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
            using (p)
            {
                p.Start();
                p.BeginErrorReadLine();//开始异步读取
                p.WaitForExit();//阻塞等待进程结束
                p.Close();//关闭进程
            }
        }

        private static void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            var output = e.Data;
            if (output != null)
            {
                if (output.Contains("Duration"))
                {
                    Int32 indexOfDuration = output.IndexOf("Duration");
                    Int32 indexOfBegin = output.IndexOf(":", indexOfDuration);
                    Int32 indexOfEnd = output.IndexOf(",", indexOfBegin);
                    var duration = output.Substring(indexOfBegin + 1, indexOfEnd - indexOfBegin - 1);
                    timeCount = ConvertStringtoSecond(duration);
                }
                if (output.Contains("time="))
                {
                    Int32 indexOfTime = output.IndexOf("time=");
                    Int32 indexOfBegin = output.IndexOf("=", indexOfTime);
                    Int32 indexOfEnd = output.IndexOf("bitrate", indexOfBegin);
                    string timeStr = output.Substring(indexOfBegin + 1, indexOfEnd - indexOfBegin - 1);
                    //
                    var time = Convert.ToDouble(ConvertStringtoSecond(timeStr));
                    //
                    var process = time / timeCount * 100;  //当前毫秒单位
                    process = Math.Round(process);
                    Console.Write("{0}% ", process);
                }
                //Console.WriteLine(e.Data);
            }
        }

        private static int ConvertStringtoSecond(string timeStr)
        {
            int totalSecond = 0;
            try
            {
                DateTime dateTime = Convert.ToDateTime(timeStr);
                totalSecond = dateTime.Hour * 3600000 + dateTime.Minute * 60000 + dateTime.Second * 1000 + dateTime.Millisecond;
            }
            catch (System.Exception ex)
            {
                Console.Write(ex.Message);
            }
            return totalSecond;
        }

        private static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            Console.WriteLine(e.Data);
        }
    }

}

 二、实践与视频解决方案第13张

4、视频转码其他指令

string para = string.Format("-i {0} -b:v 400k -s 1920*1080 {1}", videoUrl, targetUrl);   //模糊不清楚,1920*1080 完全行不通 很模糊
string para = string.Format("-i {0}  {1}", videoUrl, targetUrl);   //3.67G转换后1.06G  简单压缩方式

截图

ffmpeg.exe -i D:videoWildlife.MP4 -ss 5 -vframes 1 D:videoimg.jpg  //截图

二、实践与视频解决方案第14张

把视频的前30帧转换成一个Animated Gif

ffmpeg.exe -i D:video\_Wildlife.MP4 -vframes 30 -y -f gif D:video.gif

二、实践与视频解决方案第15张

 水印

//加水印:
ffmpeg -i D:video
ewFile2.mp4 -i D:videoimg.jpg -filter_complex overlay D:video\__Wildlife.MP4

二、实践与视频解决方案第16张

 参数

说明:LogoName为图片名,overlay=100:100意义为overlay=x:y,在(x,y)坐标处開始加入水印。

         左上角:overlay=10:10 

         右上角:overlay=main_w-overlay_w-10:10

         左下角:overlay=10:main_h-overlay_h-10 

         右下角:overlay=main_w-overlay_w-10:main_h-overlay_h-10

//gif图到左下角视频中,经常看视频,类似那些视频广告gif 
ffmpeg -y -i D:video
ewFile2.mp4 -ignore_loop 0 -i D:video	img.gif  -filter_complex overlay=0:H-h D:video\__Wildlife.MP4

4、论坛说明

http://bbs.chinaffmpeg.com

这里下载的是dev版本,将其下载解压到项目目录下:

不是很方便调用,就采用 

FFmpeg.AutoGen

二、实践与视频解决方案第17张

 一、项目搭建nuget添加ffmpeg.autogen引用。

二、实践与视频解决方案第18张

 二、实践与视频解决方案第19张

 二、实践与视频解决方案第20张

免责声明:文章转载自《二、实践与视频解决方案》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇sql Server插不进数据,以及Id自增的教程及注意事项Linux平台用C++实现事件对象,同步线程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ActiveMQ---知识点整理

本文来自于csdn,文章通过介绍ActiveMQ的安装,使用,搭建等等,简单整理了ActiveMQ。 本文转自:http://www.uml.org.cn/zjjs/201802111.asp 一.背景介绍 1.1 java消息服务: 不同系统之间的信息交换,是我们开发中比较常见的场景,比如系统A要把数据发送给系统B,这个问题我们应该如何去处理? 1999...

各种数据库与.NET Framework类型对照

本文记录各种数据库与.NET类型的对照,包括Oracle,SQL Server,MySQL,SQLite 首先是Oracle的 序号 Oracle数据类型 .NET类型 1 BFILE byte[] 2 BLOB byte[] 3 CHAR string 4 CLOB string 5 DATE DateTime 6 FLO...

wangEditor编辑器的使用

使用场景wangEditor  x-admin前端框架 文档手册地址:https://www.wangeditor.com/ 第一步:在html 页面引入需要的js(最好把这些js 下载下来,本地引入) <script type="text/javascript" src="https://unpkg.com/wangeditor/dist/wang...

web优化之js动态合并 动态压缩 去掉js重复引用 js缓存 js延迟加载

做web前段也有一段时间了,对于web中js文件的加载有些体会想跟大家一起分享一下。 1.首先说说js文件的合并和压缩吧 为了便于集中式管理js的合并和压缩我们创建一个Js.ashx文件来专门处理合并压缩,这里我们借用Yahoo.Yui.Compressor工具来压缩我们的js文件 代码如下: public classJs : IHttpHandler...

Java 设计模式--策略模式,枚举+工厂方法实现

项目中的一个页面跳转功能存在10个以上的if else判断,想要做一下整改 一、什么是策略模式 策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重If判断问题。 1.环境(Context)角色:持有一个Strategy的引用。 2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象...

Java解决关键路径问题

参考: https://www.cnblogs.com/lishanlei/p/10707808.html https://blog.csdn.net/wang379275614/article/details/13990163  关键路径问题来源于实际的生产活动,是项目管理的经典问题。 在一个复杂的项目中,整体项目的完成依赖与各个子项目的完成,而子项目...