最近作一个小项目,要在线播放录制的 MP4 视频,想开源的 flash player 或 html 5 能够播放。可,虽然 MP4 是 H.264 编码,但就是播放不了。多是封装方式(PS 方式)不同吧。因为录制用的第三方设备,不能修改参数,只能本身使用工具转码了。css
FFmpeghtml
网上一搜索,就找到了大名鼎鼎的 FFmpeg ,好像 google 的 youtube 后台也是用的这个转码,国内的不少视频播放器核心也是这个。有了这个实现起来就很是简单了。FFmpeg 转码时占用 CPU 很高,能够到 100%,也不知道该怎么解决此问题。转码只要一条指令就好了:前端
ffmpeg.exe -i source.mp4 -c:v libx264 -crf 24 destination.flv
这是最简单的设置,更多能够去官网看详细的参数,其中 -crf 很重要,是控制转码后视频的质量,质量越高,文件也就越大。git
The range of the quantizer scale is 0-51: where 0 is lossless, 23 is default, and 51 is worst possible. A lower value is a higher quality and a subjectively sane range is 18-28. Consider 18 to be visually lossless or nearly so: it should look the same or nearly the same as the input but it isn't technically lossless.github
官网的解释(翻译):浏览器
此值的范围是 0 到 51:0 表示高清无损;23 是默认值(若是没有指定此参数);51 虽然文件最小,但效果是最差的。less
值越小,质量越高,但文件也越大,建议的值范围是 18 到 28。而值 18 是视觉上看起来无损或接近无损的,固然不表明是数据(技术上)的转码无损。ide
Coding:工具
实现起来也是很简单,只要使用 Processs 后台转码就行,请看 FfmpegHelper :google
1 using System; 2 using System.Configuration; 3 using System.IO; 4 // reference https://github.com/LeafDuan/WebPrint/tree/master/WebPrint.Framework 5 using WebPrint.Framework; 6 // reference https://github.com/LeafDuan/WebPrint/tree/master/WebPrint.Logging 7 using WebPrint.Logging; 8 9 namespace WebPrint.CameraServer.Helper 10 { 11 public class FfmpegHelper 12 { 13 private static readonly ILogger Logger = LoggerHelper.GetLogger(typeof (FfmpegHelper)); 14 15 private static string Ffmpeg 16 { 17 get { return ConfigurationManager.AppSettings["ffmepg"]; } 18 } 19 20 private static string Args 21 { 22 get { return ConfigurationManager.AppSettings["args"]; } 23 } 24 25 private static string FlvPath 26 { 27 get { return ConfigurationManager.AppSettings["flv"]; } 28 } 29 30 public static string DecodeMp4ToFlv(string mp4, int timeout = 0) 31 { 32 var ffmpeg = "\"{0}\"".Formatting(Ffmpeg); 33 var flv = Path.Combine(FlvPath, (Path.GetFileNameWithoutExtension(mp4) ?? string.Empty) + ".flv"); 34 var args = Args.Formatting("\"{0}\"".Formatting(mp4), "\"{0}\"".Formatting(flv)); 35 string output, error; 36 if (timeout <= 0) 37 timeout = 5*60*1000; // timeout = 5 minutes 38 ProcessHelper.Process(ffmpeg, args, timeout, out output, out error); 39 if (!error.IsNullOrEmpty()) 40 { 41 Logger.Error("{0}{1} : {2}{0}".Formatting(Environment.NewLine, "FFmpeg", error)); 42 } 43 44 return flv; 45 } 46 } 47 }
却是其中 Process 的实现须要技巧,尤为是针对 output、error 和 timeout 的处理。若是不使用 AutoResetEvent ,process 很容易卡死在 error output 上(IO blocked)。其中针对超时,作了一个处理,就是 kill 掉 process ,省得引发资源霸占和泄露(过多 ffmpeg 进程)。
附:Flash 推荐
能够转码成 html 5 支持的 H.264,也能够其余格式,如 flv。为了兼容 IE6 及以上浏览器,只能使用 flash 播放的方式了。使用的是开源的 vcastr22.swf,可能因为开源,项目如今没有人维护了。
最后吐槽一句:盼 IE9 如下的版本早日寿终正寝。为了随窗口以 16:9 的尺寸自动缩放,兼容 IE六、7 的 css 和 js 是写得累死了。由于非专业前端,找资料都累死了。
感谢
感谢 @eflay 的解决思路,“经过转封装的方式,以复制的效率实现MP4转FLV”。本人不是很懂这些视频的编码,所以没有想到这么好的解决方式。
同时也找到了一篇很好的解决这个问题的文章 h264格式的flv和mkv无损转换成mp4的方法