<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          記錄一次有挑戰(zhàn)的經(jīng)歷:使用xgplayer拉流端直播

          共 9425字,需瀏覽 19分鐘

           ·

          2024-04-15 09:53

          一、背景介紹

          為了強(qiáng)化官方驗(yàn)的心智,平臺要做一版新的質(zhì)檢直播間,將我們的質(zhì)檢車間全方位透明的展現(xiàn)給用戶。按照產(chǎn)品的設(shè)計(jì)來實(shí)現(xiàn)的話,其實(shí)就是將各個鏡頭的內(nèi)容同時在一個頁面內(nèi)進(jìn)行播放,除了工作時間的直播,還有休息時間的錄播播放。不過直播和錄播的生成都是在后端實(shí)現(xiàn),前端只負(fù)責(zé)視頻資源的播放。

          二、前期調(diào)研

          對于簡單的直播場景,我們需要關(guān)注的主要是「編解碼格式」「直播協(xié)議」,因?yàn)檫@兩點(diǎn)直接決定直播能否播放。

          「編解碼格式:」視頻的編碼方式?jīng)Q定了視頻的壓縮方式,同樣的需要對應(yīng)的解碼格式才能正常播放視頻。但視頻編碼這個過程是在推流端做的,通常會采用H.264,目前基本上所有的播放器和瀏覽器都支持該解碼方式,其兼容性基本不用考慮;所以雖然視頻的編解碼格式很重要,但只要沒有特殊的場景如4k,一般無需過多考慮。

          「拉流端直播協(xié)議:」不同的直播協(xié)議,其兼容性和直播效果有一些差異,而前端對兼容性的差異是敏感的,所以對于Web端,盡量選擇兼容性最佳的HLS。

          以下是我了解到的不同直播協(xié)議的特點(diǎn)及他們的優(yōu)劣勢:

          「RTMP」

          特點(diǎn)/優(yōu)點(diǎn):

          1.基于TCP長連接,不需要多次建連,延時低,通常只有1~3s;2.技術(shù)成熟,配套完善。

          缺點(diǎn):

          1.兼容性差,需要依賴flash,因此無法在移動端使用。2.容易被防火墻攔截。

          「HLS」

          特點(diǎn)/優(yōu)點(diǎn):

          1.其工作原理是切片式傳輸,把直播流切成無數(shù)片,用戶在觀看視頻時,每次客戶端可以只下載一部分;2.基于 HTTP協(xié)議,所以接入CDN較為容易,很少被防火墻攔下;3.自帶多碼率自適應(yīng);4.幾乎支持所有設(shè)備;

          缺點(diǎn):

          1.延時較大,通常不低于10s;2.大量的TS片文件,會造成服務(wù)器存儲和請求的壓力;

          「HTTP-FLV」

          特點(diǎn)/優(yōu)點(diǎn):

          1.把音視頻數(shù)據(jù)封裝成FLV,然后通過HTTP連接傳輸,與RTMP相比只是傳輸協(xié)議變了,能有效避免防火墻和代理的影響;2.低延時,整體效果與RTMP非常接近;

          缺點(diǎn):

          1.它的傳輸特性會讓流媒體資源緩存在本地客戶端,保密性較差;2.不支持IOS;

          三、為什么使用xgPlayer

          在確定了我所需要使用的直播協(xié)議后,我調(diào)研了一些社區(qū)推薦的播放器:tcplayer.js、xgplayer、DPlayer、plyr、ArtPlayer.js、Video.js。

          其實(shí)以上的播放器在功能上都可以滿足我的需求,并且也都支持H.264編碼格式;在直播能力的支持上也都會在底層依賴hls.js,flv.js,不過像tcplayer和xgplayer還單獨(dú)包了一層,使得直播的實(shí)現(xiàn)更加的符合播放器的體系;

          在我所調(diào)研的播放器里xgPlayer的文檔是最清晰和完善的,并且xgPlayer使用插件機(jī)制,所有功能均可插拔,而且支持自定義擴(kuò)展能力,十分方便,所以在開發(fā)體驗(yàn)上我認(rèn)為更勝一籌。

          四、基本使用

          1.初始化
          import Player from 'xgplayer'
          import FlvPlugin from 'xgplayer-flv'
          import "xgplayer/dist/index.min.css"

          new Player({
              id:'dom-id'// 播放器實(shí)例化所需的dom
             url'test.flv'// 視頻源
              width'100%',
             height'100%'
          })
          2.多實(shí)例

          初始化時可以使用選擇器id或容器el。但對于同時實(shí)例化多個播放器的場景,使用Id很容易導(dǎo)致最終只實(shí)例化成功一個,雖然你可以通過ID+索引的方式避免,但使用容器el還是更為簡潔的。

          <div ref="playerRef"></div>

          const playerRef = ref()

          new Player({
          el: playerRef.value,
          ...
          })
          3.常用屬性
          new Player({
             poster // 封面
            autoplay // 自動播放,基本上不支持有聲自動播放;
            autoplayMuted // 自動靜音播放,需要自動播放可使用改屬性
            playsinline // 對于移動 Safari 瀏覽器來說是必需的,它允許視頻播放時不強(qiáng)制全屏模式
            loop // 循環(huán)播放
            fitVideoSize // 根據(jù)視頻內(nèi)容調(diào)整容器寬高
            videoFillMode // 視頻畫面填充模式
            controls // 是否展示進(jìn)度條
            videoAttributes // 透傳給video標(biāo)簽的屬性 
          })

          關(guān)于自動播放的限制還是很多的,所以把預(yù)期降低到大部分設(shè)備可以靜音播放即可... 關(guān)于自動播放

          4.直播能力

          「FLV協(xié)議:」使用xgplayer-flv,可用于PC、安卓。

          import FlvPlugin from 'xgplayer-flv'
          if (FlvPlugin.isSupported()) { // 第一步,檢測當(dāng)前環(huán)境是否支持
              const player = new Player({
                  id'dom-id',
                  url'test.flv'// flv 流地址
                  isLivetrue,
                  plugins: [FlvPlugin] // 第二步
              })
          }

          「HLS協(xié)議:」使用xgplayer-hls,可用于PC、安卓、IOS(ios&部分andr不需要插件,原生支持)。

          在原生支持hls的情況下盡可能不使用xgplayer-hls,IOS瀏覽器原生即支持hls格式播放,但是缺少xgplayer-hls運(yùn)行所需的Media Source Extensions。

          import Player from 'xgplayer'
          import HlsPlugin from 'xgplayer-hls'

          let player
          if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
              // 原生支持 hls 播放
              player = new Player({
                  eldocument.querySelector('.player'),
                  url'test.m3u8'
              })
          else if (HlsPlugin.isSupported()) { // 第一步,檢測當(dāng)前環(huán)境是否支持
              player = new Player({
                  eldocument.querySelector('.player'),
                  isLivetrue,
                  url'test.m3u8'// hls 流地址
                  plugins: [HlsPlugin] // 第二步
              })
          }
          5.樣式自定義

          xgplayer提供了十分便捷的方式去配置icon。

          const playerConfig = {
            icons: {
              // 1.通過function方式 返回一個dom
              play() => {
                const dom = Util.createDom('div''<img src="./start"/>', {}, 'customclass')
                return dom
              },
              // 2.直接html代碼
              pause`<div class='customclass'><img src="./start"/></div>`,
              // 3.直接一張圖片鏈接
              startPlay''
            }
          }

          但是很多地方的icon大小尺寸是固定死的,如果想要修改還是要去覆蓋xgplayer默認(rèn)的樣式

          image-20231123163802551
          6.自定義插件

          xgplayer支持插件的擴(kuò)展機(jī)制,無論是簡單的功能按鈕還是復(fù)雜的播放邏輯都可以通過插件的形式來實(shí)現(xiàn)。

          這里實(shí)現(xiàn)一個簡單的插件,結(jié)合我們的通用組件庫,用于在視頻暫停時,展示一些提示。

          // demoPlugin.js
          import Vue from 'vue'
          import { Events, Plugin } from 'xgplayer'
          import Demo from './demoPlugin.vue'
          const { POSITIONS } = Plugin

          export default class DemoPlugin extends Plugin {
            // 插件的名稱,將作為插件實(shí)例的唯一key值
            static get pluginName() {
              return 'demoPlugin'
            }
            static get defaultConfig() {
              return {
                // 掛載在播放器最上方
                position: POSITIONS.ROOT_TOP
              }
            }
            constructor(args) {
              super(args)
              this.vm = null
            }
            // 插件實(shí)例化之后
            afterCreate() {
             // 使用vue組件
              const Component = Vue.extend(Demo)
              this.vm = new Component().$mount('.demo-plugin')
            // 視頻播放時
              this.on(Events.PLAY, () => {
                this.vm.hide()
              })
            // 視頻暫停時
              this.on([Events.PAUSE], () => {
                this.vm.show()
              })
            }
            destroy() {
              // 播放器銷毀的時候一些邏輯
            }
            render() {
              return '<div class="demo-plugin"></div>'
            }
          }
          // demoPlugin.vue
          <template>
          <NoticeBar v-show="visible" swipe>
          <span style="padding-right: 50px;">我一定會回來的~我一定會回來的~我一定會回來的~</span>
          </NoticeBar>
          </template>
          <script setup lang="ts">
          import { ref, defineExpose } from 'vue'
          import { NoticeBar } from '@zz-common/zz-ui';

          const visible = ref(true)

          const show = () => {
          visible.value = true
          }
          const hide = () => {
          visible.value = false
          }
          defineExpose({
          show,
          hide
          })
          </script>
          // 使用
          import DemoPlugin from './demoPlugin.js'
          ...
          new Player({
            ...,
            plugins: [DemoPlugin]
          })
          image

          五、遇到的問題

          1.事件監(jiān)聽相關(guān)

          在播放器的事件中有兩個與播放操作相關(guān)的事件——play、canplay

          「play」表示播放已開始。

          「canplay」表示瀏覽器可以播放媒體文件了,但估計(jì)沒有足夠的數(shù)據(jù)來支撐播放到結(jié)束,不必停下來進(jìn)一步緩沖內(nèi)容。

          簡單區(qū)分下這兩個事件:play可以具象的理解為點(diǎn)擊播放按鈕或者自動播放成功,canplay則表示視頻資源已經(jīng)開始加載并緩沖了一部分?jǐn)?shù)據(jù)達(dá)到了啟播的條件。

          這兩個事件的先后順序不固定——如果沒有設(shè)置自動播放、也沒有設(shè)置預(yù)加載,那應(yīng)該是play、canplay。如果設(shè)置了預(yù)加載,但沒有設(shè)置自動播放,則應(yīng)該是canplay、play,到目前按照事件的定義來看,還是能抓住一些規(guī)律的。但是呢經(jīng)過我測試發(fā)現(xiàn),同樣的設(shè)置,在原生video標(biāo)簽和xgplayer上執(zhí)行順序不同。另外在不同的操作系統(tǒng)上也會導(dǎo)致執(zhí)行順序不同,比如 ios Safari 從不預(yù)加載導(dǎo)致無法在未播放時觸發(fā)canplay事件。所以十分不建議根據(jù)這兩個事件的執(zhí)行時機(jī)來做一些事(不過目前也想不到這種場景,只是無意中發(fā)現(xiàn)的)

          2.跨域問題

          問題的起因是當(dāng)時的直播流內(nèi)容總是會間隔性的黑屏,而且后端無法監(jiān)控到并調(diào)整視頻源。于是需要前端通過截取畫面并分析截圖的像素點(diǎn)來判斷是否黑屏,以實(shí)現(xiàn)黑屏自動切換視頻源的能力。

          但是當(dāng)通過canvas獲取圖片數(shù)據(jù)時getImageData報(bào)了一個SecurityError異常。

          經(jīng)查閱發(fā)現(xiàn)這是瀏覽器的安全策略,不通過CORS使用其他來源的資源,會污染畫布。

          在"被污染"的 canvas 中調(diào)用以下方法將會拋出安全錯誤:

          • canvas 的上下文上調(diào)用getImageData()
          • canvas元素本身調(diào)用toBlob()toDataURL()captureStream()

          所以如果要對視頻內(nèi)容進(jìn)行截圖或者對視頻畫面做一些操作處理,需要給video標(biāo)簽設(shè)置crossOrigin屬性,在xgplayer中可以通過videoAttributes屬性傳入。

          const player = new Player({
            ...,
            videoAttributes: {
              crossOrigin'anonymous'
            }
          })
          3.內(nèi)存溢出

          當(dāng)不需要播放器時,記得及時銷毀,否則可能會導(dǎo)致內(nèi)存溢出。(尤其是多實(shí)例、切換播放的場景)

          player.destroy() // 銷毀播放器
          player = null // 將實(shí)例引用置空

          「無需單獨(dú)銷毀插件實(shí)例,xgplayer自動會幫我們執(zhí)行該操作。」—— xgplayer將所有注冊的插件維護(hù)在pluginGroup對象中,當(dāng)我們調(diào)用播放器的destroy方法時,遍歷所有插件并依次執(zhí)行插件的銷毀方法。

          image
          image
          image
          4.兼容性問題???

          在測試的時候發(fā)現(xiàn),iPhone 14Pro機(jī)型,直播播放的時候,如果跳轉(zhuǎn)到其他頁面,再返回到直播頁,會導(dǎo)致視頻播放錯誤;該問題暫時沒有思路,不清楚原因...

          目前的解決辦法是,在頁面不可見時,記錄并銷毀該播放器,在頁面展現(xiàn)時再重新實(shí)例化之前的播放器。

          六、最終效果

          目前線上正常運(yùn)行,暫時沒有發(fā)現(xiàn)其他問題。

          七、參考資料

          1.允許圖片和 canvas 跨源使用(https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image)

          2.西瓜播放器(https://h5player.bytedance.com/guide/)

          3.Safari HTML5 Audio and Video Guide(https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/AudioandVideoTagBasics/AudioandVideoTagBasics.html)


          瀏覽 257
          10點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          10點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜芽成人在线 | 99精品全国免费观看 | 国内毛片毛片毛片毛片毛片毛片毛片毛片 | 人妻色色色| 久久抽插视频 |