123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- using System;
- using System.ComponentModel;
- using System.IO;
- namespace GxPress.Common.Tools
- {
- public static class FormatConverter
- {
- //FFmpeg配置信息
- private static string ffmpegpath = Path.Combine(Directory.GetCurrentDirectory()) + "\\wwwroot\\FFmpeg\\ffmpeg.exe";//FFmpeg的服务器路径
- private static string imgsize = "400*300"; //视频截图大小
- private static string videosize = "480*360"; //视频大小
- #region 也可将信息添加到配置文件中
- //public static string ffmpegpath = ConfigurationManager.AppSettings["ffmpeg"];
- //public static string imgsize = ConfigurationManager.AppSettings["imgsize"];
- //public static string videosize = ConfigurationManager.AppSettings["videoize"];
- #endregion
- private static string destVideo = "";
- /// <summary>
- /// 视频路径
- /// </summary>
- public static string DestVideo
- {
- get { return destVideo; }
- set { destVideo = value; }
- }
- private static string destImage = "";
- /// <summary>
- /// 图片路径
- /// </summary>
- public static string DestImage
- {
- get { return destImage; }
- set { destImage = value; }
- }
- /// <summary>
- /// 视频长度
- /// </summary>
- public static string VideoLength { get; set; }
- //文件类型
- public enum VideoType
- {
- [Description(".avi")]
- AVI,
- [Description(".mov")]
- MOV,
- [Description(".mpg")]
- MPG,
- [Description(".mp4")]
- MP4,
- [Description(".flv")]
- FLV
- }
- /// <summary>
- /// 返回枚举类型的描述信息
- /// </summary>
- /// <param name="myEnum"></param>
- /// <returns></returns>
- private static string GetDiscription(System.Enum myEnum)
- {
- System.Reflection.FieldInfo fieldInfo = myEnum.GetType().GetField(myEnum.ToString());
- object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
- if (attrs != null && attrs.Length > 0)
- {
- DescriptionAttribute desc = attrs[0] as DescriptionAttribute;
- if (desc != null)
- {
- return desc.Description.ToLower();
- }
- }
- return myEnum.ToString();
- }
- //将GetDesCription定义为扩展方法,需.net3.5
- //public static string Description(this Enum myEnum)
- //{
- // return GetDiscription(myEnum);
- //}
- //构造函数
- //创建目录
- // public FormatConverter()
- // {
- // }
- #region 使用FFmpeg进行格式转换
- /// <summary>
- /// 运行格式转换
- /// </summary>
- /// <param name="sourceFile">要转换文件绝对路径</param>
- /// <param name="destPath">转换结果存储的相对路径</param>
- /// <param name="videotype">要转换成的文件类型</param>
- /// <param name="createImage">是否生成截图</param>
- /// <returns>
- /// 执行成功返回空,否则返回错误信息
- /// </returns>
- public static string Convert(string sourceFile, string destPath, string uniquename, VideoType videotype, bool createImage, bool getDuration)
- {
- //取得ffmpeg.exe的物理路径
- // string ffmpeg = System.Web.HttpContext.Current.Server.MapPath(ffmpegpath);
- string ffmpeg = ffmpegpath;
- if (!File.Exists(ffmpeg))
- {
- return "找不到格式转换程序!";
- }
- if (!File.Exists(sourceFile))
- {
- return "找不到源文件!";
- }
- //string uniquename = FileHelper.GetUniqueFileName();
- string filename = uniquename + GetDiscription(videotype);
- //string destFile = HttpContext.Current.Server.MapPath(destPath + filename);
- string destFile = destPath + filename;
- //if (Path.GetExtension(sourceFile).ToLower() != GetDiscription(videotype).ToLower())
- //{
- System.Diagnostics.ProcessStartInfo FilestartInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg);
- FilestartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
- /*ffmpeg参数说明
- * -i 1.avi 输入文件
- * -ab/-ac <比特率> 设定声音比特率,前面-ac设为立体声时要以一半比特率来设置,比如192kbps的就设成96,转换
- 均默认比特率都较小,要听到较高品质声音的话建议设到160kbps(80)以上
- * -ar <采样率> 设定声音采样率,PSP只认24000
- * -b <比特率> 指定压缩比特率,似乎ffmpeg是自动VBR的,指定了就大概是平均比特率,比如768,1500这样的 --加了以后转换不正常
- * -r 29.97 桢速率(可以改,确认非标准桢率会导致音画不同步,所以只能设定为15或者29.97)
- * s 320x240 指定分辨率
- * 最后的路径为目标文件
- */
- FilestartInfo.Arguments = " -i " + sourceFile + " -ab 80 -ar 22050 -r 29.97 -s " + videosize + " " + destFile;
- //FilestartInfo.Arguments = "-y -i " + sourceFile + " -s 320x240 -vcodec h264 -qscale 4 -ar 24000 -f psp -muxvb 768 " + destFile;
- try
- {
- //转换
- System.Diagnostics.Process.Start(FilestartInfo);
- destVideo = destPath + filename;
- }
- catch
- {
- return "格式转换失败!";
- }
- //}
- //格式不需要转换则直接复制文件到目录
- //else
- //{
- // File.Copy(sourceFile, destFile,true);
- // destVideo = destPath + filename;
- //}
- //提取视频长度
- if (getDuration)
- {
- VideoLength = GetVideoDuration(sourceFile);
- }
- //提取图片
- if (createImage)
- {
- //截大图
- string imgpath = destPath + uniquename + ".jpg";// FileHelper.GetUniqueFileName(".jpg");
- ConvertImage(sourceFile, imgpath, imgsize,VideoLength);
- //截小图
- imgpath = destPath + uniquename + "_thumb.jpg";
- DestImage = ConvertImage(sourceFile, imgpath, "80*80",VideoLength);
- }
- return "";
- }
- /// <summary>
- /// 获取视频图片
- /// </summary>
- /// <param name="sourceFile">视频地址</param>
- /// <param name="imgpath">图片地址</param>
- /// <param name="imgsize">大小</param>
- /// <param name="videoLength">视频长度</param>
- /// <returns></returns>
- public static string ConvertImage(string sourceFile, string imgpath, string imgsize, string videoLength)
- {
- //定义进程
- System.Diagnostics.ProcessStartInfo ImgstartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegpath);
- ImgstartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
- /*参数设置
- * -y(覆盖输出文件,即如果生成的文件(flv_img)已经存在的话,不经提示就覆盖掉了)
- * -i 1.avi 输入文件
- * -f image2 指定输出格式
- * -ss 8 后跟的单位为秒,从指定时间点开始转换任务
- * -vframes
- * -s 指定分辨率
- */
- //duration: 00:00:00.00
- string[] time = videoLength.Split(':');
- int seconds = int.Parse(time[0]) * 60 * 60 + int.Parse(time[1]) * 60 + int.Parse(time[2]);
- int ss = seconds > 5 ? 5 : seconds - 1;
- //ImgstartInfo.Arguments = " -i " + sourceFile + " -y -f image2 -ss " + ss.ToString() + " -vframes 1 -s " + imgsize + " " + HttpContext.Current.Server.MapPath(imgpath);
- ImgstartInfo.Arguments = " -i " + sourceFile + " -y -f image2 -ss " + ss.ToString() + " -vframes 1 -s " + imgsize + " " + imgpath;
- try
- {
- System.Diagnostics.Process.Start(ImgstartInfo);
- return imgpath;
- }
- catch
- {
- return "";
- }
- }
- /// <summary>
- /// 获取视频长度
- /// </summary>
- /// <param name="ffmpegfile"></param>
- /// <param name="sourceFile"></param>
- /// <returns></returns>
- public static string GetVideoDuration(string sourceFile)
- {
- var ffmpegfile = ffmpegpath;
- 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);
- return duration;
- }
- }
- #endregion
- }
- }
|