使用canvas检测HTML5视频解码错误
乍一看这标题,有点吊炸天的赶脚,canvas跟<video>能有什么联系?不过请放心我不是标题党。事情是这样的:
HTML5的<video>标签所支持的视频格式确实有限,mp4文件必须是H264编码的才行,若不是H264编码,在chrome下会只有声音没有画面,在FireFox下直接连声音也没有,而且控制台会显示警告:
因为浏览器使用的解码器也是H264的。如果用户在本地可以观看的mp4视频上传后却无法正常播放,这种体验是相当糟糕的。
我尝试在文件上传阶段进行检测,然而HTML5的FILE API能力也是有限的,只能获取文件名称、大小、MIME类型,对于视频的编码却无法检测到。
既然无法从上传阶段阻止用户,那么退一步讲,在视频无法播放的时候,我们希望可以检测到,并且给用户一个提示“视频解码错误”,这样他就不会有疑惑“我的视频为什么无法播放呢?”。
首先想到的是video的API,video有onerror事件,但是此事件只能在src地址错误或其他原因加载不到视频资源时触发,当加载到视频发生解码错误时,并不会触发。略蛋疼。这么看来按照标准的东西是无法检测到了,所以必须另辟蹊径了。答案就是:
canvas读取图片像素点的能力
前些天看了前端手记的这篇文章印象颇深,http://www.cssha.com/video2txt-canvas。利用canvas读取图片像素点,进而转化为文本图片。更厉害的是canvas的drawImage方法还可以传入视频,获取到视频某一帧的像素点。于是一个想法在脑中萦绕,解码错误的视频是没有画面的黑屏,我可以用canvas绘制视频,根据所绘制的内容来判断画面是不是在动,遂想到如下思路:
- 在视频开始播放时,每隔一定时间用canvas绘制一次视频画面
- 对每次canvas绘制的图片进行像素点采样,存入数组
- 扫描几次后,比较每次采样的像素点rgb值是否相同,即检测画面是否变化了
- 根据画面是否在“运动”来检测是否解码成功了
这种办法当然也有局限,下面是几个注意事项:
- canvas绘制视频画面的次数控制。绘制图片并采样获取像素点是消耗性能的,所以这个扫描过程不应该伴随视频播放的整个时间段。只需在开始播放的几秒内进行检测即可。
- 若恰巧有某个视频,开始的几秒内就是一个静止的画面,那检测就出错了。
局限归局限,先把想法写成代码试试,于是有如下代码:
//比较两个长度相等类型相同的数组是否相等
function arrayEq(a1,a2){
for(var i=0,len=a1.length;i<len;i++){
if(a1[i]!=a2[i]){
return false;
}
}
return true;
}
//比较采样得到的数组是否相等
function arrayAllEq(array){
for(var i=0,len=array.length;i<len;i++){
if(!arrayEq(array[i],array[i+1])){
return false;
}
}
return true;
} var can = $('<canvas id="canvas" style="display:none"></canvas>').appendTo('body');
var canvas = can.get(0);
var width = $('#vi').width();
var height = $('#vi').height();
var ctxt = canvas.getContext('2d');
var media = document.getElementById('vi');
var resultArray = [];
var stopScan = false;
var scanImg = function(){
if(stopScan)return false;
try{
ctxt.drawImage(media, 0, 0,width,height);
var data = ctxt.getImageData(0, 0, width,height).data;
var array = [];
for(var i =0,len = data.length; i<len;i+=4*100){
var red = data[i],
green = data[i+1],
blue = data[i+2],
alpha = data[i+3];
array.push(red,green,blue,alpha);
}
resultArray.push(array);
return true;
}
catch(e){
alert('视频解码错误,请使用H264编码的mp4文件!');
stopScan = true;
}
}
$('video').on('play',function(){
//每隔一定时间扫描一次画面
scanImg();
setTimeout(scanImg,1000);
setTimeout(scanImg,2000);
setTimeout(scanImg,3000);
setTimeout(scanImg,5000);
setTimeout(function(){
if(scanImg()){
if(arrayAllEq(resultArray)){
alert('视频解码错误,请使用H264编码的mp4文件!');
}
else{
alert('监测结束,视频正常');
}
}
},8000);
});
$('video').on('pause',function(){
stopScan = true;
});
当我怀着激动的心情开始测试时,发现事实真不是想象的那样。Chrome下,当一个视频无法解码时,drawImage方法直接无法执行,会报错。完了,美好的想法泡汤了。。。
不过转而一想,视频解码错误,drawImage方法就报错,如果写在try catch语句中,不就可以捕捉到了吗?看来还没到死路,这样连像素点采样都省了,可以直接检测到了。于是乎代码就简化成了下面这样:
//检测视频是否解码错误
function checkVideoParseError(){
var videos = $('video');
if(videos.length>0){
var can = $('<canvas id="canvas" style="display:none"></canvas>').appendTo('body');
var canvas = can.get(0);
var ctxt = canvas.getContext('2d');
var scanImg = function(video){
try{
ctxt.drawImage(video, 0, 0);
}
catch(e){
alert('视频解码错误,请使用H264编码的mp4文件!');
}
} videos.on('play',function(){
var _this = this;
scanImg(_this);
setTimeout(function(){scanImg(_this);},1000);
})
}
}
在1秒后的绘制图片动作会捕捉到异常。没想到,竟然这样成功了!
该方法纯属个人想出来的,还有诸多不完善之处,遇到同样问题的同学可以试试这个思路~
使用canvas检测HTML5视频解码错误的更多相关文章
- 绘制SVG内容到Canvas的HTML5应用
SVG与Canvas是HTML5上绘制图形应用的两种完全不同模式的技术,两种绘制图形方式各有优缺点,但两者并非水火不容,尤其是SVG内容可直接绘制在Canvas上的功能,使得两者可以完美的融合在一起, ...
- make: 警告:检测到时钟错误。您的创建可能是不完整的。
问题: make: 警告:检测到时钟错误.您的创建可能是不完整的. 原因:1. 文件时间不一致.(或者修改了系统时间) 如何解决:你touch *一下,然后重新编译 touch * touch命令有两 ...
- 7个华丽的基于Canvas的HTML5动画
说起HTML5,可能让你印象更深的是其基于Canvas的动画特效,虽然Canvas在HTML5中的应用并不全都是动画制作,但其动画效果确实让人震惊.本文收集了7个最让人难忘的HTML5 Canvas动 ...
- sql server 驱动程序在 \Device\RaidPort0 上检测到控制器错误。
sql server 驱动程序在 \Device\RaidPort0 上检测到控制器错误. 错误情况,如下图: 原因分析:硬盘故障 解决办法:进行迁移
- [LINUX]警告:检测到时钟错误。您的创建可能是不完整的。
[LINUX]警告:检测到时钟错误.您的创建可能是不完整的. 原因: 如果上一次编译时为20071001,你把系统时间改成20070901后再编译就会报这样的错误. 解决: 把时间 ...
- canvas与html5实现视频截图功能
这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...
- 避免HTML5六种错误用法
一.不要使用section作为div的替代品 人们在标签使用中最常见到的错误之一就是随意将HTML5的<section>等价于<div>--具体地说,就是直接用作替代品(用于样 ...
- 检测 HTML5\CSS3\JAVASCRIPT 在浏览器的适应情况
CSS3 Selectors Test : 这是CSS3.INFO网站提供的css选择器测试页面,它能够详细显示当前浏览器对所有CSS3选择器的支持情况.启动测试,浏览器会自动测验,并已列表的方式显示 ...
- 浏览器 canvas下载图片 网络错误
在使用html2canvas截取页面的时候发现图片死活保存不到本地,chrome一直报“网络错误”, 主要出现这个问题是canvas保存图片到本地时各个浏览器像素的限制不同, 所以将图片数据转换成Bl ...
随机推荐
- 不容错过!2016年度优秀UI/UX设计文章
本文整理了一些2016年度最受欢迎的文章,例如有关UI / UX设计的理论知识,书籍和工具,如何做出更好的设计的方法和建议,以及新的设计趋势. 1. 2017年用户体验设计趋势 我们期待着2017年用 ...
- sublime配置react
http://www.cnblogs.com/terrylin/p/4942332.html
- Servlet知识
1.Servlet概述 2.编写Servlet的开发步骤a.建立标准的JavaWeb应用目录FirstAppWEB-INFclasseslibweb.xmlb.编写一个类,实现javax.servle ...
- Nodejs 高并发长链接TCP链接的服务器设计问题
最近有个项目比较棘手,nodejs的tcp服务,目前的服务器支持3W左右的客户端连接,但是客户希望能够支持30W左右,原先的模型是让客户端请求一个地址分发服务器,然后再tcp链接到不同的地址上实现高并 ...
- jsp:软件包 javax.servlet 不存在
jdk里面有javax.servlet和javax.servlet.http这两个包吗? JavaServlet程序运行还需要安装JDK以外的包吗...? why?我运行JavaServlet程序的时 ...
- 深入浅出UML类图(一)
在UML 2.0的13种图形中,类图是使用频率最高的UML图之一.Martin Fowler在其著作<UML Distilled: A Brief Guide to the Standard O ...
- python 使用字符串名调用类以及调用类方法名
在python中,有时调用者仅知道类名和类方法,不负责实际的函数调用,而是将要调用的类名和类方法告诉一个中间函数,由中间函数负责实际调用函数.中间函数需以被告知的字符串调用类和类方法. ...
- zabbix3.0 微信告警
首先需要申请一个企业号,其实公众号也可以,不过脚本不一样.而且公众号任何人都可以关注,有泄密的风险.企业号只有指定的人可以关注,安全性较高.申请企业号,需要一个绑定你本人开户银行卡的微信号. 申请网址 ...
- android/ios js 启动apk
1.在移动设备访问某个连接时时,如果本地安装了其应用客户端,则浏览器会调用本地客户端,没有安装则会跳转到下载页面,提示安装.刚好有这样的需求,网上参考了其他人的实现,大部分都是关于APK和本地js交互 ...
- emmet插件快捷键:
概念:emmet插件是用在编辑器里面的一个可以快速编写代码的插件,比如sublime text中,就可以用它来快速创建代码,本文主要是在sublime text的编辑器中做的测试代码. 一.html ...