FormatConverter.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.ComponentModel;
  3. using System.IO;
  4. namespace GxPress.Common.Tools
  5. {
  6. public static class FormatConverter
  7. {
  8. //FFmpeg配置信息
  9. private static string ffmpegpath = Path.Combine(Directory.GetCurrentDirectory()) + "\\wwwroot\\FFmpeg\\ffmpeg.exe";//FFmpeg的服务器路径
  10. private static string imgsize = "400*300"; //视频截图大小
  11. private static string videosize = "480*360"; //视频大小
  12. #region 也可将信息添加到配置文件中
  13. //public static string ffmpegpath = ConfigurationManager.AppSettings["ffmpeg"];
  14. //public static string imgsize = ConfigurationManager.AppSettings["imgsize"];
  15. //public static string videosize = ConfigurationManager.AppSettings["videoize"];
  16. #endregion
  17. private static string destVideo = "";
  18. /// <summary>
  19. /// 视频路径
  20. /// </summary>
  21. public static string DestVideo
  22. {
  23. get { return destVideo; }
  24. set { destVideo = value; }
  25. }
  26. private static string destImage = "";
  27. /// <summary>
  28. /// 图片路径
  29. /// </summary>
  30. public static string DestImage
  31. {
  32. get { return destImage; }
  33. set { destImage = value; }
  34. }
  35. /// <summary>
  36. /// 视频长度
  37. /// </summary>
  38. public static string VideoLength { get; set; }
  39. //文件类型
  40. public enum VideoType
  41. {
  42. [Description(".avi")]
  43. AVI,
  44. [Description(".mov")]
  45. MOV,
  46. [Description(".mpg")]
  47. MPG,
  48. [Description(".mp4")]
  49. MP4,
  50. [Description(".flv")]
  51. FLV
  52. }
  53. /// <summary>
  54. /// 返回枚举类型的描述信息
  55. /// </summary>
  56. /// <param name="myEnum"></param>
  57. /// <returns></returns>
  58. private static string GetDiscription(System.Enum myEnum)
  59. {
  60. System.Reflection.FieldInfo fieldInfo = myEnum.GetType().GetField(myEnum.ToString());
  61. object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
  62. if (attrs != null && attrs.Length > 0)
  63. {
  64. DescriptionAttribute desc = attrs[0] as DescriptionAttribute;
  65. if (desc != null)
  66. {
  67. return desc.Description.ToLower();
  68. }
  69. }
  70. return myEnum.ToString();
  71. }
  72. //将GetDesCription定义为扩展方法,需.net3.5
  73. //public static string Description(this Enum myEnum)
  74. //{
  75. // return GetDiscription(myEnum);
  76. //}
  77. //构造函数
  78. //创建目录
  79. // public FormatConverter()
  80. // {
  81. // }
  82. #region 使用FFmpeg进行格式转换
  83. /// <summary>
  84. /// 运行格式转换
  85. /// </summary>
  86. /// <param name="sourceFile">要转换文件绝对路径</param>
  87. /// <param name="destPath">转换结果存储的相对路径</param>
  88. /// <param name="videotype">要转换成的文件类型</param>
  89. /// <param name="createImage">是否生成截图</param>
  90. /// <returns>
  91. /// 执行成功返回空,否则返回错误信息
  92. /// </returns>
  93. public static string Convert(string sourceFile, string destPath, string uniquename, VideoType videotype, bool createImage, bool getDuration)
  94. {
  95. //取得ffmpeg.exe的物理路径
  96. // string ffmpeg = System.Web.HttpContext.Current.Server.MapPath(ffmpegpath);
  97. string ffmpeg = ffmpegpath;
  98. if (!File.Exists(ffmpeg))
  99. {
  100. return "找不到格式转换程序!";
  101. }
  102. if (!File.Exists(sourceFile))
  103. {
  104. return "找不到源文件!";
  105. }
  106. //string uniquename = FileHelper.GetUniqueFileName();
  107. string filename = uniquename + GetDiscription(videotype);
  108. //string destFile = HttpContext.Current.Server.MapPath(destPath + filename);
  109. string destFile = destPath + filename;
  110. //if (Path.GetExtension(sourceFile).ToLower() != GetDiscription(videotype).ToLower())
  111. //{
  112. System.Diagnostics.ProcessStartInfo FilestartInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg);
  113. FilestartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
  114. /*ffmpeg参数说明
  115. * -i 1.avi 输入文件
  116. * -ab/-ac <比特率> 设定声音比特率,前面-ac设为立体声时要以一半比特率来设置,比如192kbps的就设成96,转换
  117. 均默认比特率都较小,要听到较高品质声音的话建议设到160kbps(80)以上
  118. * -ar <采样率> 设定声音采样率,PSP只认24000
  119. * -b <比特率> 指定压缩比特率,似乎ffmpeg是自动VBR的,指定了就大概是平均比特率,比如768,1500这样的 --加了以后转换不正常
  120. * -r 29.97 桢速率(可以改,确认非标准桢率会导致音画不同步,所以只能设定为15或者29.97)
  121. * s 320x240 指定分辨率
  122. * 最后的路径为目标文件
  123. */
  124. FilestartInfo.Arguments = " -i " + sourceFile + " -ab 80 -ar 22050 -r 29.97 -s " + videosize + " " + destFile;
  125. //FilestartInfo.Arguments = "-y -i " + sourceFile + " -s 320x240 -vcodec h264 -qscale 4 -ar 24000 -f psp -muxvb 768 " + destFile;
  126. try
  127. {
  128. //转换
  129. System.Diagnostics.Process.Start(FilestartInfo);
  130. destVideo = destPath + filename;
  131. }
  132. catch
  133. {
  134. return "格式转换失败!";
  135. }
  136. //}
  137. //格式不需要转换则直接复制文件到目录
  138. //else
  139. //{
  140. // File.Copy(sourceFile, destFile,true);
  141. // destVideo = destPath + filename;
  142. //}
  143. //提取视频长度
  144. if (getDuration)
  145. {
  146. VideoLength = GetVideoDuration(sourceFile);
  147. }
  148. //提取图片
  149. if (createImage)
  150. {
  151. //截大图
  152. string imgpath = destPath + uniquename + ".jpg";// FileHelper.GetUniqueFileName(".jpg");
  153. ConvertImage(sourceFile, imgpath, imgsize,VideoLength);
  154. //截小图
  155. imgpath = destPath + uniquename + "_thumb.jpg";
  156. DestImage = ConvertImage(sourceFile, imgpath, "80*80",VideoLength);
  157. }
  158. return "";
  159. }
  160. /// <summary>
  161. /// 获取视频图片
  162. /// </summary>
  163. /// <param name="sourceFile">视频地址</param>
  164. /// <param name="imgpath">图片地址</param>
  165. /// <param name="imgsize">大小</param>
  166. /// <param name="videoLength">视频长度</param>
  167. /// <returns></returns>
  168. public static string ConvertImage(string sourceFile, string imgpath, string imgsize, string videoLength)
  169. {
  170. //定义进程
  171. System.Diagnostics.ProcessStartInfo ImgstartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegpath);
  172. ImgstartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
  173. /*参数设置
  174. * -y(覆盖输出文件,即如果生成的文件(flv_img)已经存在的话,不经提示就覆盖掉了)
  175. * -i 1.avi 输入文件
  176. * -f image2 指定输出格式
  177. * -ss 8 后跟的单位为秒,从指定时间点开始转换任务
  178. * -vframes
  179. * -s 指定分辨率
  180. */
  181. //duration: 00:00:00.00
  182. string[] time = videoLength.Split(':');
  183. int seconds = int.Parse(time[0]) * 60 * 60 + int.Parse(time[1]) * 60 + int.Parse(time[2]);
  184. int ss = seconds > 5 ? 5 : seconds - 1;
  185. //ImgstartInfo.Arguments = " -i " + sourceFile + " -y -f image2 -ss " + ss.ToString() + " -vframes 1 -s " + imgsize + " " + HttpContext.Current.Server.MapPath(imgpath);
  186. ImgstartInfo.Arguments = " -i " + sourceFile + " -y -f image2 -ss " + ss.ToString() + " -vframes 1 -s " + imgsize + " " + imgpath;
  187. try
  188. {
  189. System.Diagnostics.Process.Start(ImgstartInfo);
  190. return imgpath;
  191. }
  192. catch
  193. {
  194. return "";
  195. }
  196. }
  197. /// <summary>
  198. /// 获取视频长度
  199. /// </summary>
  200. /// <param name="ffmpegfile"></param>
  201. /// <param name="sourceFile"></param>
  202. /// <returns></returns>
  203. public static string GetVideoDuration(string sourceFile)
  204. {
  205. var ffmpegfile = ffmpegpath;
  206. using (System.Diagnostics.Process ffmpeg = new System.Diagnostics.Process())
  207. {
  208. String duration; // soon will hold our video's duration in the form "HH:MM:SS.UU"
  209. String result; // temp variable holding a string representation of our video's duration
  210. StreamReader errorreader; // StringWriter to hold output from ffmpeg
  211. // we want to execute the process without opening a shell
  212. ffmpeg.StartInfo.UseShellExecute = false;
  213. //ffmpeg.StartInfo.ErrorDialog = false;
  214. ffmpeg.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
  215. // redirect StandardError so we can parse it
  216. // for some reason the output comes through over StandardError
  217. ffmpeg.StartInfo.RedirectStandardError = true;
  218. // set the file name of our process, including the full path
  219. // (as well as quotes, as if you were calling it from the command-line)
  220. ffmpeg.StartInfo.FileName = ffmpegfile;
  221. // set the command-line arguments of our process, including full paths of any files
  222. // (as well as quotes, as if you were passing these arguments on the command-line)
  223. ffmpeg.StartInfo.Arguments = "-i " + sourceFile;
  224. // start the process
  225. ffmpeg.Start();
  226. // now that the process is started, we can redirect output to the StreamReader we defined
  227. errorreader = ffmpeg.StandardError;
  228. // wait until ffmpeg comes back
  229. ffmpeg.WaitForExit();
  230. // read the output from ffmpeg, which for some reason is found in Process.StandardError
  231. result = errorreader.ReadToEnd();
  232. // a little convoluded, this string manipulation...
  233. // working from the inside out, it:
  234. // takes a substring of result, starting from the end of the "Duration: " label contained within,
  235. // (execute "ffmpeg.exe -i somevideofile" on the command-line to verify for yourself that it is there)
  236. // and going the full length of the timestamp
  237. duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00").Length);
  238. return duration;
  239. }
  240. }
  241. #endregion
  242. }
  243. }