做者:傑里米
閱讀時間:5~10minjavascript
以前在騰訊視頻刷劇時,偶然看到有一個畫中畫的功能很是好用,不懂就問:什麼是「畫中畫」?提及畫中畫,就不得不提起咱們常常乾的一件事兒,咱們想在PC瀏覽器上看電視的同時逛淘寶、刷微博、玩知乎...... 只有你想不到的,沒有我玩不順的!奈何咱們只有一塊屏幕(ps: 用擴展屏的大佬打擾了),這個時候就須要一個輔助英雄——畫中畫,來提升咱們桌面利用率並提升時間效率。java
首先請容許我介紹下「畫中畫」:畫中畫(英文Picture-in-picture,縮寫PiP)是指將一個電視節目(或其餘畫面)顯示在整個畫面上,同時將另外一個或多個其餘畫面顯示在角落中,一般只播放主窗口的聲音 —— from wikigit
早在1976年蒙特利爾奧運會的電視報道中就出現了近似的畫中畫效果,其使用Quantel數字幀存儲設備在開幕式期間插入奧林匹克聖火的特寫照片。github
隨着咱們平常社交生活的豐富,咱們但願在瀏覽器上也用到畫中畫的功能。web
近兩年,瀏覽器廠商開始陸續支持畫中畫的功能,咱們先來看下瀏覽器中畫中畫的效果:chrome
下面介紹目前主流瀏覽器上畫中畫的實現狀態canvas
詳情請查看Implementation Statuspromise
早在2016年9月,Safari經過macOS Sierra中的WebKit API添加了Picture-in-Picture支持。相比chrome,safari在自帶的播放控件內加入了畫中畫模式的按鈕。瀏覽器
2017年4月,Chrome經過使用原生Android API發佈Android O,能夠自動在移動設備上播放畫中畫視頻。 2018年10月,Chrome在PC 客戶端69版本加入畫中畫的特性,但在該版本中畫中畫是默認關閉的,若是想開啓該特性,須要在瀏覽器執行如下操做:bash
chrome://flags
並按下回車鍵enable-experimental-web-platform-features
(啓用正在開發的實驗性Web平臺功能)、enable-Surfaces-for-videos
(啓用合成到Surface而不是視頻的VideoLayer)、enable-picture-in-picture
(爲video開啓畫中畫特性)並將選項值置爲Enabled
。到了70版本已默認開啓該特性,安裝chrome擴展插件可進入畫中畫,進入畫中畫後,頁面選項卡會出現一個藍色的圖標,以提醒用戶該頁面正在播放視頻。
Chrome 71中的畫中畫支持播放MediaStream對象的視頻(例如getUserMedia(),getDisplayMedia(),canvas.captureStream())。這意味着能夠顯示包含用戶網絡攝像頭視頻流的畫中畫窗口,便可以 顯示webRTC的視頻流。
目前Firefox的畫中畫功能還在測試之中,須要Firefox超前測試版Nightly才能開啓畫中畫模式,具體步驟以下:
about:config
設置頁media.videocontrols.picture-in-picture.enabled
點擊切換,讓其置爲true
須要注意的是,Chrome 與 Firefox 的畫中畫模式略有不一樣,Chrome 開啓畫中畫後,瀏覽器內的視頻將再也不播放,而 Firefox 則至關於啓用了雙屏播放,畫中畫和原標籤頁同步播放,並且目前的畫中畫功能甚至沒有關閉畫中畫視頻的選項,所以必須再次鼠標右鍵單擊才能關閉畫中畫功能。
對於開發者而言,讓用戶體驗到畫中畫模式帶來的效果是最使人興奮的,感謝瀏覽器爸爸提供了相應的API供咱們開發者調用。因爲safari實現的時間太早,而谷歌又用本身的一套API,致使API目前還沒有標準化(好消息是畫中畫Web API的規範 已經在WICG草案階段中了,大致上和chrome的API規範一致,具體可猛戳此處),我將對目前已支持的瀏覽器(chrome和safari)分別介紹其Web API:
先來看一個示例(示例中的視頻源來自騰訊):
咱們來看上述示例中用到的屬性和方法:
該屬性用來判斷當前文檔是否支持使用畫中畫所示的功能。(不能理解爲瀏覽器是否支持,由於即使瀏覽器支持的狀況下,用戶禁用畫中畫功能也會返回false)
該屬性返回當前文檔內存在的畫中畫元素對象,若是不存在返回null,不然返回video element
這個API是真正去請求視頻進入畫中畫模式的,結果會返回一個promise,在promise成功回調中拿到一個pipWindow對象,這個對象包含:
{ width, height, resize }
複製代碼
width和height分別是視頻進入畫中畫窗口的寬高,resize能夠監聽一個事件回調,在畫中畫窗口發生變化時觸發。
① 爲什麼API掛載到video上而不是document上?
由於一個頁面可能會存在多個video,因此須要指定觸發畫中畫的video元素。
② 那麼什麼狀況下API會調用失敗?
disablePictureInPicture
新屬性mouseover
、mouseenter
、mousemove
、mouseleave
、scroll
、onload
等事件都不算用戶手勢事件。當咱們想主動退出畫中畫,能夠調用這個API,其結果也會返回一個promise。
① 爲什麼API掛載到document而不是video上?
由於目前一個頁面最多僅容許一個video顯示在畫中畫窗口上。對於開發者而言,不須要退出畫中畫的是哪一個video,所以只須要掛載到document上就能夠了。
當咱們想監聽video是否真正進入/退出畫中畫時,有時候進入/退出畫中畫並非咱們經過調用requestPictureInPicture/exitPictureInPicture來觸發的,好比用戶經過chrome插件讓視頻進入畫中畫,這個時候須要監聽這兩個事件,來獲取一些有用的信息並進行上報之類的行爲。
因爲safari早在2016年就原生支持了畫中畫,所以API和chrome是徹底不一致的。在safari裏咱們能夠把「畫中畫」理解爲播放模式的概念,safari中的播放模式只有三種,分別是inline
、picture-in-picture
、fullscreen
。
咱們先來看一個簡單的示例:
從上面示例能夠看出,畫中畫相關屬性和方法都是掛載到具體的視頻元素上。
咱們來看上述示例中用到的屬性和方法:
該方法是檢測video元素所支持的「演示模式」(通常理解爲播放模式),這裏傳參mode支持三個有效值:picture-in-picture
、inline
、fullscreen
。
通常有兩種方式來判斷是否支持畫中畫。第一種就是上述示例所介紹的,第二種即:
let supportsPiP = false;
try {
supportsPiP = video.webkitSupportsPresentationMode('picture-in-picture');
} catch(e) {
supportsPiP = false;
}
複製代碼
若是webkitSupportsPresentationMode傳入無效值,會拋出error,以下所示:
這個屬性值返回的其實就是上面播放模式的三個有效值之一。能夠用該屬性判斷當前video所處的模式是否爲畫中畫。
這個方法能夠設置當前模式,當mode='picture-in-picture',就等效於chrome中的video.requestPictureInPicture()。當mode='inline',就等效於chrome中的document.exitPictureInPicture()。須要注意的是,在safari裏調用此方法進入/退出畫中畫,都沒有返回值,固然也不會報錯。
當前播放模式發生變化時能夠經過這個事件監聽,不管是進入/退出畫中畫,都會觸發此事件的監聽回調。須要注意的是這裏不會返回畫中畫窗口下的對象信息(包括窗口width、height等)
不管在safari/chrome,若是畫中畫內播放的是實時音視頻流,瀏覽器會在退出畫中畫時暫停掉視頻的播放,須要在退出畫中畫後手動觸發視頻流繼續播放。
根據目前畫中畫的支持狀況,這裏有一個畫中畫polyfill庫能夠兼容到chrome和safari
在WICG Picture-in-Picture草案中提到了自動畫中畫的特性:
「 某些頁面的video元素想要自動進入/退出畫中畫,例如,當用戶在Web應用程序與其餘應用tab之間來回切換時,視頻Web應用程序將受益於一些自動畫中畫行爲。但很遺憾,用戶手勢目前是作不到的,因此就須要Auto Picture-in-Picture了!」
咱們只須要給video元素加入一個新屬性autopictureinpicture
:
<video autopictureinpicture></video>
複製代碼
這意味着不須要開發者手動調用方法來執行畫中畫的行爲,當頁面文檔隱藏時,最近設置了autopictureinpicture屬性的video元素就會自動進入Picture-in-Picture(若是容許畫中畫的話),當頁面文檔可見時,畫中畫中的視頻元素會自動離開。
讓 Chrome 與 Firefox 實現系統級視頻畫中畫效果
developers.google.com/web/updates…
關注【IVWEB社區】公衆號獲取每週最新文章,通往人生之巔!