前端視訊直播技術總結及video.js在h5頁面中的應用
全手打原創,轉載請標明出處:https://www.cnblogs.com/dreamsqin/p/12557070.html,多謝,=。=~
(如果對你有幫助的話請幫我點個贊啦)
目前有一個需求是在移動端上內嵌h5實現點位的視訊直播,直播專案採用Vue編寫,後端主要輸出 RTMP 和 HLS 協議的直播流,本文主要總結一下整體開發的技術選型以及開發過程中的思考與學習總結。
流媒體傳輸
我的困惑: 什麼是流媒體,以及其傳輸方式是怎樣的?
流媒體
流媒體是指採用流式傳輸方式在 Internet 上播放的媒體格式,例如音訊、視訊等多媒體檔案。
流式傳輸方式
流式傳輸方式是將多媒體檔案經過特殊壓縮後分成一個個壓縮包,再由伺服器向客戶端連續、實時傳送。使用者不必像非流式傳輸那樣等待整個檔案全部下載完畢後才能播放,而是隻需要經過幾秒鐘或幾十秒的啟動延時即可對壓縮的音視訊檔案進行播放,剩餘的部分將繼續下載,直至播放完畢。
流媒體傳輸協議
常用的流媒體傳輸協議主要有
HTTP漸進式下載
和實時流媒體協議
兩類。
HTTP漸進式下載
:僅能傳輸完整的音視訊檔案,在給定時刻,使用者只能觀看已下載的那部分,而不能跳到還未下載的部分。HTTP邊下載邊播放,嚴格意義上講,不是直播協議。他的原理是先下載檔案的基本資訊,音訊視訊的時間戳,再下載音視訊資料,以播放mp4為例,先下載檔案頭,根據檔案頭指引下載檔案尾,然後再下載檔案的音視訊資料。
實時流媒體協議
:可用於實況直播,也可傳輸完整的音視訊檔案。例如RTSP/RTP、RTMP、HLS、HTTP-FLV。RTSP協議
既可以基於UDP傳輸也可以基於TCP傳輸,是純粹的傳輸控制協議,它本身與它負載的媒體資料不相關,RTSP協議需要自定義客戶端向伺服器傳送RTSP命令。其視訊資料由RTP傳輸,視訊質量由RTCP控制,視訊控制(如播放、暫停等)由RTSP提供。
常用直播流協議
我的困惑: 哪些流媒體傳輸協議用於直播,不同型別之間又有什麼區別?
RTMP(Real Time Messaging Protocol)
協議比較全能,既可以用來推送,又可以用來直播。其核心理念是將大塊的視訊幀和音訊幀“剁碎”,然後以小資料包的形式在網際網路上進行傳輸,且支援加密,因此隱私性相對比較理想,但拆包組包的過程比較複雜,所以在海量併發時容易出現一些不可預期的穩定性問題。
HLS(HTTP Live Streaming)
蘋果推出的解決方案,將視訊分成 5-10 秒的視訊小分片,然後用 M3U8 索引表進行管理。由於客戶端下載到的視訊都是 5-10 秒的完整資料,故視訊的流暢性很好,但也同樣引入了很大的延遲(HLS 的一般延遲在 10-30s 左右)。相比於 FLV,HLS 在iPhone 和大部分 Android 手機瀏覽器上的支援非常給力,所以常用於 QQ 和微信朋友圈的 URL 分享。
HTTP-FLV(Flash Video)
由 Adobe 公司主推,格式極其簡單,只是在大塊的視訊幀和音視訊頭部加入一些標記頭資訊,由於這種極致的簡潔,在延遲表現和大規模併發方面都很成熟。唯一的不足就是在手機瀏覽器上的支援非常有限,但是用作手機端 APP 直播協議卻異常合適。
RTMP、HLS、HTTP-FLV 協議對比如下圖所示:
直播原理
我的困惑: 想要實現直播,需要經歷怎樣的過程?
如果用一句話描述整體過程,其實就是直播時,主播端將直播流推向伺服器,使用者端發起請求從伺服器拉視訊流過來解碼播放,流程如下圖所示:
第一部分就是視訊主播端的操作:視訊採集處理後推流到流媒體伺服器。
- 首先從前端採集裝置中獲得原始的音訊、視訊資料;
- 為了增強額外效果,對音訊進行混音、降噪等處理,可為視訊打上時間戳、新增Logo水印或增加濾鏡;
- 隨後對音訊、視訊進行編碼,通過編碼壓縮滿足其在網際網路上實時傳輸的需求;
- 編碼後就可以把各種多媒體內容(視訊、音訊、字幕等)盛放在同一個容器裡,也就是所謂的封裝,使得不同多媒體內容可同步播放,與此同時還提供了索引;
- 最後就是通過流傳輸協議將封裝好的內容推送到流媒體伺服器上;
第二部分就是流媒體伺服器:負責把從第一部分接收到的流進行處理並分發給使用者。
流媒體伺服器的主要功能是對流媒體內容進行採集(接收推流)、快取、排程和傳輸播放(以流式協議實現使用者分發)。
典型的流媒體伺服器:
- 微軟的Windows Media Service(WMS):它採用MMS協議接收、傳輸視訊,採用Windows Media Player(WMP)作為前端播放器;
- RealNetworks公司的Helix Server:採用RTSP/RTP協議接收、傳輸視訊,採用Real Player作為播放前端播放器;
- Adobe公司的Flash Media Server:採用RTMP(RTMPT/RTMPE/RTMPS)協議接收、傳輸視訊,採用Flash Player作為前端播放器;
第三部分就是使用者:只需要擁有支援對應流媒體傳輸協議的播放器即可。
這一部分其實就是我們前端需要實現的,如何在移動端的內嵌h5頁面中實現直播流的播放。所以我們只需要關注後端是通過什麼協議給我們返回直播流以及我們如何有效的播放就可以了~
客戶端直播外掛
我的困惑: 除了採用h5原生的<video></<video>
標籤,我們還能用什麼外掛實現視訊直播,不同外掛之間有什麼區別?
經過我暴風式搜尋後找到三款常用並且支援實時流媒體播放的客戶端外掛(hls.js、video.js、vue-video-player),下面我們一個個道來。
hls.js
hls.js是一個可以實現HTTP實時流媒體客戶端的js庫,主要依賴於<video></<video>
標籤和Media Source Extensions
API。它的工作原理是將MPEG2傳輸流和AAC/MP3流轉換成ISO BMFF (MP4)片段。由於hls.js是基於標準的<video></<video>
標籤實現播放,所以它不需要額外的播放器。
優點: 包比較小,很純淨,UI可以根據自己的業務自行擴充套件,功能可以根據需求進行封裝,比較靈活,而且專業直播HLS協議流。
缺點: 對於常規的通用性播放器沒有封裝好的UI,功能上也需要自己調API實現,協議單一,只支援HLS。
video.js
video.js是一個基於h5的網路視訊播放器,支援h5視訊、現代流媒體格式(MP4、WebM、HLS、DASH等)以及YouTube、Vimeo,甚至連flash也支援(通過外掛實現,後面會詳細說明),可在桌面端或移動端實現視訊播放。
優點: 支援多種格式的流媒體播放,瀏覽器不支援時可實現優雅降級;專門有一套針對直播流的UI;外掛機制強大,目前社群已有數百個面板和外掛供下載;相容性好,幾乎支援所有桌面及移動端的瀏覽器。
缺點: 包比較大,實現hls直播的時候其實是內嵌了hls.js的程式碼,由於封裝好UI和功能,使其不夠靈活,修改UI時需要通過外掛實現。
vue-video-player
vue-video-player其實就是將video.js整合到了Vue中,在Vue專案中使用起來會更方便。
移動端內嵌h5實現視訊直播
1、技術選型:
- 傳輸協議——由於後端支援同時返回HLS協議和RTMP協議的直播流,結合考慮HLS協議的高延時問題和RTMP協議的相容性問題,本專案決定採用向下相容的方式實現,預設使用RTMP協議直播,當瀏覽器不支援時降級使用HLS協議播放。
- 直播外掛——本專案基於Vue實現,並且業務邏輯為常規直播操作,無特殊需求,從開發效率、穩定性及相容性出發,決定採用vue-video-player外掛實現。
2、vue-video-player安裝與引入:
- CDN:
<link rel="stylesheet" href="path/to/video.js/dist/video-js.css"/>
<script type="text/javascript" src="path/to/video.min.js"></script>
<script type="text/javascript" src="path/to/vue.min.js"></script>
<script type="text/javascript" src="path/to/dist/vue-video-player.js"></script>
<script type="text/javascript">
Vue.use(window.VueVideoPlayer)
</script>
- NPM(支援全域性/按需引入):
npm install vue-video-player --save
全域性引入
import Vue from 'vue'
import VueVideoPlayer from 'vue-video-player'
// 引入videojs樣式
import 'video.js/dist/video-js.css'
// 自定義樣式引入,併為<video-player>新增對應類名即可,例如vjs-custom-skin
// import 'vue-video-player/src/custom-theme.css'
Vue.use(VueVideoPlayer, /* {
options: 全域性預設配置,
events: 全域性videojs事件
} */)
按需引入
// 引入videojs樣式
import 'video.js/dist/video-js.css'
import { videoPlayer } from 'vue-video-player'
export default {
components: {
videoPlayer
}
}
3、video.js外掛擴充套件: 當已有外掛(video.js外掛集合:https://videojs.com/plugins/)無法滿足需求時可對已有外掛進行擴充套件或自行開發video.js外掛
import videojs from 'video.js'
// videojs plugin
const Plugin = videojs.getPlugin('plugin')
class ExamplePlugin extends Plugin {
// something...
}
videojs.registerPlugin('examplePlugin', ExamplePlugin)
// videojs language
videojs.addLanguage('es', {
Pause: 'Pausa',
// something...
})
// more videojs api...
// vue component...
具體實現方式可參見:https://github.com/videojs/video.js/blob/master/docs/guides/plugins.md
4、視訊直播關鍵程式碼:
options
:video.js options
playsinline
:設定播放器在移動裝置上不全屏[ Boolean, default: false ]
customEventName
:自定義狀態變更時的事件名[ String, default: 'statechanged' ]
<template>
<video-player
class="video-player-box"
ref="videoPlayer"
:options="playerOptions"
:playsinline="true"
customEventName="customstatechangedeventname"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
@ended="onPlayerEnded($event)"
@waiting="onPlayerWaiting($event)"
@playing="onPlayerPlaying($event)"
@loadeddata="onPlayerLoadeddata($event)"
@timeupdate="onPlayerTimeupdate($event)"
@canplay="onPlayerCanplay($event)"
@canplaythrough="onPlayerCanplaythrough($event)"
@statechanged="playerStateChanged($event)"
@ready="playerReadied">
</video-player>
</template>
export default {
data() {
return {
playerOptions: {
// 是否關閉音訊
muted: true,
// 初始語言,預設為英語,code參見:https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
language: 'zh-CN',
// 播放速度,指定後Video.js將顯示一個控制元件(vjs-playback-rate類的控制元件),允許使用者從選項陣列中選擇播放速度
playbackRates: [0.5, 1.0, 1.5, 2.0],
// 將播放器置於流暢模式,並在計算播放器的動態大小時使用該值,表示長寬比例
aspectRatio: '4:3',
// 等同於原生<video>標籤中的一組<source>子標籤,可實現優雅降級;type 屬性規定媒體資源的 MIME 型別,標準型別可參見:https://www.iana.org/assignments/media-types/media-types.xhtml;
sources: [{
type: "rtmp/flv",
src: "rtmp://58.200.131.2:1935/livetv/hunantv"
}, {
type: "application/x-mpegURL",
src: "http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8"
}],
// 相容順序,預設值是['html5'],這意味著html5技術是首選,其他已註冊的技術將按其註冊的順序在該技術之後新增。
techOrder: ['flash'],
// 在視訊開始播放之前顯示的影象的URL(封面),這通常是一個視訊幀或自定義標題螢幕,一旦使用者點選“播放”,影象就會消失。
poster: require('../assets/test.jpg'),
}
}
},
mounted() {
console.log('this is current player instance object', this.player)
},
computed: {
player() {
return this.$refs.videoPlayer.player
}
},
methods: {
// 各個事件監聽
onPlayerPlay(player) {
// console.log('播放器播放!', player)
},
onPlayerPause(player) {
// console.log('播放器暫停!', player)
},
// ...(此處省略多個事件監聽函式)
// 狀態監聽
playerStateChanged(playerCurrentState) {
// console.log('播放器當前狀態更新', playerCurrentState)
},
// 監聽播放器是否就緒
playerReadied(player) {
console.log('播放器已就緒', player)
// 就緒後就可以呼叫播放器的一些方法
}
}
}
踩坑小tips:
播放 HLS 協議流,需要videojs-contrib-hls
外掛,但是直接引用即可,因為在安裝vue-video-player
外掛時,videojs-contrib-hls
是一併安裝的;如果需要播放RTMP協議流,需要videojs-flash
外掛,也是直接引用就可以了(flash外掛需要在hls之前引用)
import 'videojs-flash'
import 'videojs-contrib-hls'
5、效果展示:
封面
rtmp
- hls
總結
本文首先闡述了流媒體
、流媒體傳輸方式
、流媒體傳輸協議
以及RTSP協議
的概念;接著基於專案直播需求引出三種常用直播流協議RTMP
、HLS
、HTTP-FLV
,並對三種協議進行了對比分析,為後續技術選型提供參考;然後根據通用直播原理描述了整個直播流資料傳輸的過程,從採集
、處理
、編碼
、封裝
到推流
、分發
與播放
,表明前端的重點工作在最後一步即流媒體播放;隨後對常用的三款客戶端直播外掛hls.js
、video.js
、vue-video-player
進行說明,並分析了各自的優缺點;最後詳細總結了移動端內嵌h5實現視訊直播的編碼過程,包括技術選型
、外掛的安裝與引入
、外掛擴充套件
、視訊直播關鍵程式碼
及最終的效果展示
。
本專案中視訊直播方式的實現大大提高了前端的開發效率,並且保證了桌面端與移動端的相容性,同時增強了使用者體驗,比傳統只使用一種協議的播放源更靈活,為通用直播需求提供解決方案。
參考資料
1、直播流播放協議:https://help.aliyun.com/knowledge_detail/49785.html
2、流媒體伺服器:https://baike.baidu.com/item/%E6%B5%81%E5%AA%92%E4%BD%93%E6%9C%8D%E5%8A%A1%E5%99%A8/9711212?fr=aladdin
3、hls.js:https://github.com/video-dev/hls.js
4、video.js: https://github.com/videojs/video.js
5、vue-video-player:https://github.com/surmon-china/vue-video-player