android上視頻播放存在的問題
在PC上播放html5視頻,設置video.currentTime=5,視頻將跳到5s的位置,並且顯示出第5s的畫面。在安卓下,卻存在下面兩個問題:
- 在安卓上,爲了省電,在暫停的時候,改變視頻屬性不會刷新畫面,直到你再次播放的時候,這些改變纔會表現出來。所以暫停的時候改變currentTime不會更新畫面,手動改變進度條也不行。
- 在安卓上,視頻並不是準確的按currentTime播放,可能你設置 currentTime = 5,但是播放出來的內容卻是第8s的。這個問題,用手改變進度條也會出現,可以將視頻拖到60s,在拖回10s,看看播放的內容是否是第10s的。
所以,對於一些需要精確控制視頻進度的情景,比如視頻演示,這兩個問題會造成很大的困擾,因爲android下,沒有辦法很精確的控制視頻進度。
可能並不是所有移動端都存在這兩個問題,沒驗證哪些存在
解決辦法
對於第二個問題,是沒有辦法改變的,這是html5 video的實現問題。但是第一個問題,卻可以通過模擬“暫停下設置視頻進度”解決。
模擬的方式是,先播放視頻,然後將視頻設置到目標時間,當視頻加載出第一幀的時候,暫停視頻,如下:
播放視頻,監聽playing事件
觸發playing事件,說明視頻已經開始播放,此時設置currentTime等於目標時間,監聽seeked事件
觸發seeked事件,在移動端下,seeked事件觸發後,表示已經尋址到了指定時間,但是畫面還沒更新,監聽timeupdate事件
觸發timeupdate事件,在移動端下,第一次觸發這個事件表示即將更新畫面,此時設置50ms的延遲,因爲一般視頻爲24fps,也就是40ms刷新一幀,50ms的延遲爲了確保第一幀加載出來
延遲結束,暫停視頻。此時視頻暫停再目標時間,畫面也已經加載出來。
之所以要搞得這麼複雜,是因爲在android下,事件觸發並不是很準確,經觸發了playing
和timeupdate
事件,但視頻可能都還沒開始播放,但是有這麼幾個規律:
- 第一,觸發
seeked
之後的timeupdate
的時候,視頻已經很接近播放了 - 第二,觸發
playing
後,第2次觸發timeupdate
的時候一定已經播放着了,但是觸發兩次timeupdate
的間隔比較大,往往視頻已經很明顯的播放一小段。
並非放之四海皆準的規律
下面的代碼就是用這種方式實現的,能夠在android上暫停時設置currentTime,主要看setTime
方法:
/**
* Created by Administrator on 2017/1/9.
*/
export default class Video{
constructor(src){
let uid = new Date().getTime();
this.id = 'video'+uid;
this.video = $(`<video id="${this.id}"></video>`).get(0);
this.status = null; //播放狀態
}
play(){
this.status = "playing";
this.video.play();
return this;
}
pause(){
this.status = "paused";
this.video.pause();
return this;
}
/**
* 設置視頻當前的事件
* @param time 時間
* @returns {Number}
*/
setTime(time){
if(this.status == "playing"){
this.video.currentTime = time;
console.log("當前視頻時間:"+this.video.currentTime);
return time;
}
/*
目的:在移動端下加載指定時長的視頻畫面
移動端下存在的問題:在移動端下,如果不播放視頻,則視頻控件顯示黑屏,此時不可指定視頻當前時間
解決辦法:在移動端下,設置到指定時長後,播放極小的一段時間,讓視頻控件顯示出當前的畫面,然後暫停,看起來就像直接指定時間一樣
實現說明:
1、監聽playing事件,並在其中監聽seeked和timeupdate事件,兩個事件都觸發後,視頻一般接近或已經開始播放了,
然後再設置50ms的延遲,一般可保證視頻播放
2、在setTime執行的過程中,有可能外部已經更改了視頻播放的狀態(通過調用this.play()或this.pause()),
因此設置一個status字段,保存外部的操作
*/
let that = this;
that.video.play();
$(that.video).one("playing",function(){
that.video.currentTime = time;
$(that.video).one("seeked",function(){
$(that.video).one("timeupdate",function(){
clearTimeout(that.timeout);
that.timeout = setTimeout(()=>{
console.log("當前視頻時間:"+that.video.currentTime);
if(that.status == "playing"){
that.video.play();
}else{
that.video.pause();
}
},that.delay);
});
})
})
return time;
}
}