昨天公司指派給我了一個任務,是關於視頻播放後展現頁面的單頁應用,具體需求以下:html
1)用戶在進入頁面後視頻開始自動播放,期間不得操做;
2)視頻播放完成後順滑切換到主體頁。
複製代碼
看起來是否是特別簡單粗暴,乍一看好像也是就是不到一小時的工做量,卻讓我足足熬到了深夜兩點鐘,提及來都是淚~~。這期間遇到了很多問題,我都會在下面一一列舉(如下所說的瀏覽器均爲移動端瀏覽器,再也不一一標註)。html5
在我開發完基本代碼以後,push到githook上在手機上展現時,遇到了第一個問題: 衆所周知,html中video的autoplay在移動端瀏覽器上基本失效(其一,移動端要有用戶交互才能觸發事件,如click、touch;其二,ios協議蜂窩數據下不得開啓音視頻的自動播放),因此我在加載後取巧的加了一個懸浮播放圖標,引導用戶點擊開始業務流程。android
但可能由於內核不一樣,在微信瀏覽器/safari/chrome上默認展現的poster各有不一樣,chrome應用了默認行爲截取了視頻第一幀做爲顯示,微信瀏覽器和safari卻顯示空白,效果就是孤零零的播放圖放在一張白紙上。解決方案是:經過canvas截取視頻第一幀做爲默認顯示的圖片:ios
var cut = function() {
let canvas = document.createElement("canvas");//建立畫布
canvas.width = video.videoWidth * scale;
canvas.height = video.videoHeight * scale;//設定寬高比
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);//將視頻此刻幀數畫入畫布
let img = document.createElement("img");
img.src = canvas.toDataURL("image/png");
Dom.appendChild(img);//寫入到Dom
};
video.addEventListener('loadeddata',cut);//在視頻幀數已加載時執行截取
複製代碼
html文檔裏寫有,若是controls屬性不出現,則默認不顯示,但其實在實際應用中,瀏覽器通常都是調用默認播放器進行播放,再加上雙端差別,實際展現效果更是精彩紛呈。說到這裏,要寫一下目前各個瀏覽器的內核狀況:git
微信瀏覽器web
微信6.1版本以上的android用戶,都是使用的QQ瀏覽器的X5內核。 5.4-6.1之間的版本,若用戶安裝了QQ瀏覽器就是使用的X5內核,若用戶未安裝瀏覽器,使用的是系統內核。chrome
Webkit。canvas
大部分手機瀏覽器瀏覽器
Webkit。(UC的U3內核和X5內核同樣,是基於webkit修改的內核)。bash
由上可知,在移動端開發遇到的百分之九十的問題,都是系統和機型問題。
咱們回到問題自己,在使用htmlvideo標籤時,咱們會發現,點擊播放以後首先會進入播放器佔用整個屏幕,以後開始播放,再次點擊視頻會出現控制欄。
好,捋一捋思路。第一步,要解決脫離屏幕的播放問題。
<video poster="img/test.jpg" webkit-playsinline="true" playsinline>
<source src="img/movie.mp4" type="video/mp4">
<source src="img/movie.ogg" type="video/ogg">
您的瀏覽器不支持該視頻格式。
</video>
複製代碼
webkit-playsinline playsinline:這個屬性做用是讓視頻播放時局域播放(不全屏,在原有位置上播放),不脫離文檔流 。但這個屬性須要嵌入網頁的APP好比WeChat中UIwebview 的allowsInlineMediaPlayback = YES webview.allowsInlineMediaPlayback = YES,才能生效。換句話說,安卓不支持,而IOS的wechat卻支持,由於APP不支持playsinline,因此安卓是默認全屏播放的。
第二步,隱藏掉控制欄。
<video x5-video-player-type="h5" id="video">
<source src="img/movie.mp4" type="video/mp4">
<source src="img/movie.ogg" type="video/ogg">
您的瀏覽器不支持該視頻格式。
</video>
複製代碼
x5-video-player-type='h5' 啓用同層H5播放器,學名叫沉浸式播放。播放的時候除去了control和微信的導航欄,只留下"X"和"<"兩鍵。
通常來講,這種已經足夠‘沉浸’了,但項目對定製化要求比較高,要求這種也不要出現。我苦思冥想,查了好多文檔,方法卻都大同小異。直到最後靈光一閃,放棄了經過屬性或方法來限制的思路,決定用視覺遮擋來實現效果:
將video的控制欄擠出可視區域,不就至關於隱藏了控制欄嘛。
/*這是CSS*/
html,body,.main{
width: 100%;
height: 100%;
overflow: hidden;//隱藏
background: #FFF;
box-sizing:border-box;
}
.videobox{
z-index: 12;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#video{
position: absolute;
top: -2%;
width: 100%;
height: 110%;
}
<!--這是HTML-->
<div class="videobox" ontouchmove="return false;">
<video poster="img/test.jpg" webkit-playsinline="true" playsinline x5-video-player-type="h5" x-webkit-airplay="true" id="video">
<source src="img/movie.mp4" type="video/mp4">
<source src="img/movie.ogg" type="video/ogg">
您的瀏覽器不支持該視頻格式。
</video>
</div>
複製代碼
這樣就實現了播放時不得操做的需求。
這就牽扯到兩個個問題,咱們分開來講。
video標籤對視頻格式以及編碼的支持
MPEG4 = 帶有H.264視頻編碼和AAC音頻編碼的MPEG4文件
WebM = 帶有VP8視頻編碼和Vorbis音頻編碼的 WebM文件
Ogg = 帶有Theora視頻編碼和Vorbis音頻編碼的Ogg文件
如上所示,只有h264編碼的MP4視頻(MPEG-LA公司)、VP8編碼的webm格式的視頻(Google公司)和Theora編碼的ogg格式的視頻(iTouch開發)能夠支持html5的<video>
標籤。
那麼在實際代碼上咱們應該這麼佈置:
<video poster="img/test.jpg" webkit-playsinline="true" playsinline x5-video-player-type="h5" x-webkit-airplay="true" id="video">
<source src="img/movie.mp4" type="video/mp4">
<source src="img/movie.ogg" type="video/ogg">
您的瀏覽器不支持該視頻格式。
</video>
複製代碼
首先會判斷是否支持MP4,如否,判斷是否支持OGG,如否,展現文字。這也是我最後選擇的解決方式,簡單粗暴能夠早睡覺 :)。
備註:網上有文章說,用格式工廠將mp4編碼轉成H264便可,但我實際應用中發現H264在safari和chrome中居然沒法打開,具體緣由到底是我編碼錯誤仍是與文檔衝突,暫未知曉。
iOS上播放視頻,http協議中應用rang請求頭
視頻格式MP4是正確的,可是你的後臺沒有對ios的視頻播放器作適配。若是想要在iOS上播放視頻,那麼必須在http協議中應用rang請求頭。
對於有的朋友還對ios播放器http的range標記不是很懂。我再講解下。
視頻文件總長度是123456789
range是播放器要求的區間也就是客戶端發送請求的時候http會帶有這個標記,這個區間的值在http.headers.range中獲取,通常是bytes=0-1這樣的。
咱們須要作的處理是返回文件的指定區間(如上面的例子,咱們就應該返回0到1的字符),並添加Content-Range:btyes 0-一、Accept-Ranges:bytes、'Content-Length: 123456789','Content-Type: video/mp4'到http.headers中
複製代碼
具體效果由於時間關係並無親自測試,有興趣的朋友能夠研究一下。
#video{
object-fit: fill;
}
複製代碼
<video x-webkit-airplay="true"></video>
複製代碼
$("#video").get(0).addEventListener("ended", function() {
}, false);
複製代碼
document.addEventListener("WeixinJSBridgeReady", function() {
video.play()
}, false)
複製代碼
筆記到這裏就結束了,若是在文章裏有哪些紕漏和錯誤,望您不吝賜教