2018/07/30
移动端播放视频在三方浏览器下会被劫持播放器,特别安卓播放完成还有广告推送,且播放视频由于被劫持不能再理想的排版中进行播放。 故而采取首先将视频转换成图片,通过canvas绘制关键帧动画来实现一些对视频要求不高的播放需求。
关键帧构建器:
function VideoToBase64(){};
VideoToBase64.prototype = {
constructor : VideoToBase64,
setting : null,
info : null,
video : null,
canvas : null,
ctx : null,
trigger : function(setting){
var _this = this;
if(document.querySelector('#info')){
document.querySelector('#info').parentNode.removeChild(document.querySelector('#info'));
}
_this.setting = setting;
_this.loadMetaData();
},
loadMetaData : function(){
var _this = this;
_this.video = document.createElement('video');
_this.video.src = URL.createObjectURL(_this.setting.file);
_this.video.addEventListener('loadedmetadata',function(){
document.body.appendChild(_this.video);
_this.info = {
w : _this.video.clientWidth,
h : _this.video.clientHeight,
duration : _this.video.duration,
interval : _this.setting.interval,
times : _this.setting.times,
data : []
};
document.body.removeChild(_this.video);
_this.toBase64();
});
_this.video.addEventListener('error',function(){
alert('视频加载失败!');
});
},
toBase64 : function(){
var _this = this;
_this.canvas = document.createElement('canvas');
_this.canvas.width = _this.info.w;
_this.canvas.height = _this.info.h;
document.body.appendChild(_this.canvas);
_this.ctx = this.canvas.getContext("2d");
_this.video.addEventListener('canplaythrough',function(){
alert('开始获取base64,请等到视屏播放完成!');
_this.video.play();
_this.info.data.push(_this.getBase64());
var i = 0;
var interval = setInterval(function(){
if(_this.video.currentTime >= _this.info.duration){
document.body.removeChild(_this.canvas);
clearInterval(interval);
_this.toHtml();
return;
};
_this.info.data.push(_this.getBase64());
},100);
});
},
getBase64 : function(){
var _this = this;
_this.ctx.clearRect(0,0,_this.info.w,_this.info.h);
_this.ctx.drawImage(_this.video,0,0,_this.info.w,_this.info.h);
return _this.canvas.toDataURL(_this.setting.type,_this.setting.quality)
},
toHtml : function(){
var _this = this;
var textarea = document.createElement('textarea');
textarea.id = 'info';
textarea.style.width = textarea.style.height = '500px';
textarea.value = JSON.stringify(_this.info);
document.body.appendChild(textarea);
_this.setting = _this.info = _this.video = _this.canvas = _this.ctx = null;
}
};
播放器:
function Player(){};
Player.prototype = {
constructor : Player,
//初始化属性
initProperty : function(options){
var _this = this;
_this.videoUrl = options.videoUrl;
_this.audioUrl = options.audioUrl ? options.audioUrl : null;
_this.node = options.node;
_this.videoSource =
_this.audio =
_this.canvas =
_this.ctx =
_this.image =
_this.progressInterval =
_this.canvasInterval = null;
_this.loadAudioState =
_this.loadVideoState =
_this.loadErrorState = false;
//帧
_this.frame = 0;
//播放次数
_this.times = 0;
//暂停状态
_this.paused = true;
//静音状态
_this.muted = false;
//类属性做为回调数据存储
Player.videoSource = null;
},
//加载完成
loadComplete : null,
//播放一次完成
playOnceComplete : null,
//全部播放完成
playComplete : null,
//加载进度
loadProgress : null,
//触发
trigger : function(options){
var _this = this;
if(!options.videoUrl || !options.node){ return }
_this.delete();
_this.initProperty(options);
//延时执行,等待用户设置回调接口
setTimeout(function(){
_this.load();
},0);
},
//加载
load : function(){
var _this = this;
//加载视频资源
_this.loadVideo();
//加载音频资源
_this.loadAudio();
//加载进度
_this.progress();
},
//加载进度
progress : function(){
var _this = this;
if(typeof _this.loadProgress != 'function'){return}
var progress = 0;
_this.progressInterval = setInterval(function(){
if(_this.checkLoadState() || _this.loadErrorState){
_this.stopProgress();
_this.loadProgress(_this.loadErrorState ? -1 : 100);
return;
}
if(progress < 90){
progress += progress > 50 ? 1 : 5;
}
_this.loadProgress(progress);
},100);
},
//停止进度条
stopProgress : function(){
var _this = this;
if(!_this.progressInterval){ return }
clearInterval(_this.progressInterval);
_this.progressInterval = null;
},
//检测加载状态
checkLoadState : function(){
var _this = this;
var loadAudio = _this.loadAudioState || !_this.audioUrl;
//判断音频加载状态
if(_this.loadVideoState && loadAudio){
return true;
};
return false;
},
//加载完成
loaded : function(){
var _this = this;
if(_this.checkLoadState()){
//创建画布
_this.create();
if(typeof _this.loadComplete == 'function'){
_this.loadComplete();
}
}
},
//删除元素
delete : function(){
var _this = this;
if(_this.canvas){
_this.node.removeChild(_this.canvas);
}
},
//创建元素
create : function(){
var _this = this;
//创建canvas
_this.canvas = document.createElement('canvas');
_this.canvas.width = _this.videoSource.w;
_this.canvas.height = _this.videoSource.h;
_this.canvas.innerText = '请使用支持html5的浏览器!';
_this.node.innerHTML = '';
_this.node.appendChild(_this.canvas);
//创建ctx
_this.ctx = _this.canvas.getContext('2d');
//创建image
_this.image = new Image();
},
//加载视频
loadVideo : function(){
var _this = this;
var script = document.createElement('script');
script.type = "text/javascript";
script.async = true;
script.src = _this.videoUrl;
//加载完成
script.onload = function(){
if(!Player.videoSource){return}
_this.videoSource = Player.videoSource;
_this.loadVideoState = true;
document.body.removeChild(script);
script = Player.videoSource = null;
//调用加载完成
_this.loaded();
};
//加载失败
script.onerror = function(){
_this.loadErrorState = true;
document.body.removeChild(script);
script = null;
};
document.body.appendChild(script);
},
//加载音频
loadAudio : function(){
var _this = this;
if(!_this.audioUrl){
return;
}
//创建audio
_this.audio = new Audio();
_this.audio.preload = true;
_this.audio.muted = _this.muted;
_this.audio.volume = 0;
var canplaythroughEve = function(){
_this.audio.volume = 1;
_this.audio.pause();
_this.audio.currentTime = 0;
_this.loadAudioState = true;
//调用加载完成
_this.loaded();
_this.audio.removeEventListener('canplaythrough',canplaythroughEve);
document.removeEventListener('touchstart',touchstartEve);
};
_this.audio.addEventListener('canplaythrough',canplaythroughEve);
//加载失败
_this.audio.onerror = function(){
_this.loadErrorState = true;
_this.audio = null;
};
var touchstartEve = function(){
if(_this.loadAudioState){ return }
_this.audio.play();
};
//移动端音频预加载
document.addEventListener('touchstart',touchstartEve);
_this.audio.src = _this.audioUrl;
if(!_this.loadAudioState){
_this.audio.play();
}
},
//播放
play : function(){
var _this = this;
//播放状态不能重复点击
if(!_this.paused){ return }
_this.paused = false;
_this.startAudio();
_this.startCanvas();
},
//静音
mute : function(){
var _this = this;
if(!_this.audio || _this.muted){ return }
_this.audio.muted = _this.muted = true;
},
//声音
sound : function(){
var _this = this;
if(!_this.audio || !_this.muted){ return }
_this.audio.muted = _this.muted = false;
},
//暂停
pause : function(){
var _this = this;
if(_this.paused){ return }
_this.paused = true;
_this.stopAudio();
_this.stopCanvas();
},
//重置
reset : function(){
var _this = this;
_this.frame = 0;
if(_this.audio){
_this.audio.currentTime = 0;
}
},
//重播
rePlay : function(){
var _this = this;
_this.pause();
_this.reset();
_this.play();
},
//绘制
draw : function(){
var _this = this;
var w = _this.videoSource.w,
h = _this.videoSource.h;
_this.ctx.clearRect( 0, 0, w, h);
_this.ctx.drawImage(_this.image, 0, 0,w, h);
},
//开始音频
startAudio : function(){
var _this = this;
if(!_this.audio){ return };
_this.audio.play();
},
//停止音频
stopAudio : function(){
var _this = this;
if(!_this.audio){ return };
_this.audio.pause();
},
//开始画布
startCanvas : function(){
var _this = this;
var data = _this.videoSource.data,
length = data.length,
interval = Math.ceil(_this.videoSource.duration * 1000 / length);
//执行
_this.loadImg(data[_this.frame]);
//定时器
_this.canvasInterval = setInterval(function(){
if(_this.frame >= length){
//播放一次完成的回调
if(typeof _this.playOnceComplete == 'function'){
_this.playOnceComplete();
};
//循环播放
_this.loopPlay();
return;
}
_this.loadImg(data[_this.frame]);
}, interval);
},
//停止画布
stopCanvas : function(){
var _this = this;
if(!_this.canvasInterval){ return }
clearInterval(_this.canvasInterval);
_this.canvasInterval = null;
},
//循环播放
loopPlay : function(){
var _this = this;
var times = _this.videoSource.times;
_this.times ++;
//处于循环播放
if(times <1 || times > _this.times){
_this.rePlay();
return;
}
//退出循环播放
_this.pause();
_this.reset();
//播放完成
if(typeof _this.playComplete == 'function'){
_this.playComplete();
}
},
//加载图片
loadImg : function(src){
var _this = this;
//累加帧数
_this.frame ++;
//判断src
if(typeof src == 'undefined'){return}
//load-image
_this.image.src = src;
var fn = typeof fn == 'function' ? fn : function(){};
if(_this.image.complete){
_this.draw();
return;
};
_this.image.onload = function(){
_this.draw();
};
}
};