原文: https://juejin.cn/post/6844903683105226759
昨天公司指派給我了一個任務,是關於視頻播放后展示頁面的單頁應用,具體需求如下:
1)用戶在進入頁面后視頻開始自動播放,期間不得操作; 2)視頻播放完成后順滑切換到主體頁。
看起來是不是特別簡單粗暴,乍一看好像也是就是不到一小時的工作量,卻讓我足足熬到了深夜兩點鍾,說起來都是淚~~。這期間遇到了不少問題,我都會在下面一一列舉(以下所說的瀏覽器均為移動端瀏覽器,不再一一標注)。
一、video的默認顯示
在我開發完基本代碼之后,push到githook上在手機上展示時,遇到了第一個問題: 眾所周知,html中video的autoplay在移動端瀏覽器上基本失效(其一,移動端要有用戶交互才能觸發事件,如click、touch;其二,ios協議蜂窩數據下不得開啟音視頻的自動播放),所以我在加載后取巧的加了一個懸浮播放圖標,引導用戶點擊開始業務流程。
但可能因為內核不同,在微信瀏覽器/safari/chrome上默認展示的poster各有不同,chrome應用了默認行為截取了視頻第一幀作為顯示,微信瀏覽器和safari卻顯示空白,效果就是孤零零的播放圖放在一張白紙上。解決方案是:通過canvas截取視頻第一幀作為默認顯示的圖片:
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);//在視頻幀數已加載時執行截取
二、video控制欄的隱藏
html文檔里寫有,如果controls屬性不出現,則默認不顯示,但其實在實際應用中,瀏覽器一般都是調用默認播放器進行播放,再加上雙端差異,實際展示效果更是精彩紛呈。說到這里,要寫一下目前各個瀏覽器的內核情況:
微信瀏覽器
- 安卓
微信6.1版本以上的android用戶,都是使用的QQ瀏覽器的X5內核。 5.4-6.1之間的版本,若用戶安裝了QQ瀏覽器就是使用的X5內核,若用戶未安裝瀏覽器,使用的是系統內核。
- IOS
Webkit。
大部分手機瀏覽器
Webkit。(UC的U3內核和X5內核一樣,是基於webkit修改的內核)。
由上可知,在移動端開發遇到的百分之九十的問題,都是系統和機型問題。
我們回到問題本身,在使用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>
這樣就實現了播放時不得操作的需求。
三、IOS當視頻被打開在safari瀏覽器時播放白屏。
這就牽扯到兩個個問題,我們分開來說。
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-1、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)