vue使用mpegts.js實(shí)現(xiàn)播放flv的直播視頻流
第一步:引入mpegts.js
npm install --save mpegts.js
第二步:在vue文件中引入mpegts.js的依賴
第三步:編寫展示視頻的盒子
我這里是使用循環(huán)遍歷的方式創(chuàng)建video標(biāo)簽,這樣方便后面隨機(jī)展示視頻使用
<template> <div> <el-row> <el-col :span="24"> <div class="play-video-box"> <input id="tag" v-model="tag" /> <el-button @click="load">重新加載</el-button> <el-button @click="start">開始播放</el-button> <el-button @click="pause">暫停</el-button> <el-button @click="destory">全部銷毀</el-button> </div> </el-col> </el-row> <el-row> <el-col :span="12" v-for="item in 4" :key="item"> <div class="grid-content"> <video class="video" :id="getDivClassName(item)" autoplay="true" muted="false" controls="false" @click="saveMap(item)"> {{ item }} </video> </div> </el-col> </el-row> </div> </template>
第四步:編寫播放視頻和銷毀視頻的方式
<script setup lang="ts"> import mpegts from 'mpegts.js'; import { ref, onUnmounted } from 'vue'; const flvPlayer: any = ref(); const tag = ref(null); const videoMap = new Map(); /** * 創(chuàng)建 mpegts 實(shí)例 */ const initFlv = (ops: { URL: string; elementId: string }) => { if (tag.value != null && mpegts.isSupported()) { // 根據(jù)id名稱創(chuàng)建對(duì)應(yīng)的video const ele = document.getElementById(ops.elementId); flvPlayer.value = mpegts.createPlayer( { type: 'flv', // 指定媒體類型 isLive: true, // 開啟直播(是否為實(shí)時(shí)流) hasAudio: false, // 關(guān)閉聲音(如果拉過來的視頻流中沒有音頻一定要把這里設(shè)置為fasle,否則無法播放) cors: true, // 開啟跨域訪問 url: ops.URL // 指定流鏈接(這里是傳遞過過來的視頻流的地址) }, { enableWorker: false, //啟用分離的線程進(jìn)行轉(zhuǎn)換(如果不想看到控制臺(tái)頻繁報(bào)錯(cuò)把它設(shè)置為false,官方的回答是這個(gè)屬性還不穩(wěn)定,所以要測(cè)試實(shí)時(shí)視頻流的話設(shè)置為true控制臺(tái)經(jīng)常報(bào)錯(cuò)) enableStashBuffer: false, //關(guān)閉IO隱藏緩沖區(qū)(如果需要最小延遲,則設(shè)置為false,此項(xiàng)設(shè)置針對(duì)直播視頻流) stashInitialSize: 128, //減少首幀等待時(shí)長(針對(duì)實(shí)時(shí)視頻流) lazyLoad: false, //關(guān)閉懶加載模式(針對(duì)實(shí)時(shí)視頻流) lazyLoadMaxDuration: 0.2, //懶加載的最大時(shí)長。單位:秒。建議針對(duì)直播:調(diào)整為200毫秒 deferLoadAfterSourceOpen: false, //在MediaSource sourceopen事件觸發(fā)后加載。在Chrome上,在后臺(tái)打開的標(biāo)簽頁可能不會(huì)觸發(fā)sourceopen事件,除非切換到該標(biāo)簽頁。 liveBufferLatencyChasing: true, //追蹤內(nèi)部緩沖區(qū)導(dǎo)致的實(shí)時(shí)流延遲 liveBufferLatencyMaxLatency: 1.5, //HTMLMediaElement 中可接受的最大緩沖區(qū)延遲(以秒為單位)之前使用flv.js發(fā)現(xiàn)延時(shí)嚴(yán)重,還有延時(shí)累加的問題,而mpegts.js對(duì)此做了優(yōu)化,不需要我們自己設(shè)置快進(jìn)追幀了 liveBufferLatencyMinRemain: 0.3 //HTMLMediaElement 中可接受的最小緩沖區(qū)延遲(以秒為單位) } ); // mpegts flvPlayer.value.attachMediaElement(ele); videoMap.set(ops.elementId, flvPlayer.value); play(flvPlayer.value); flvEvent(); } }; const play = (flv: any) => { flv.load(); flv.play(); }; // mpegts const flvEvent = () => { // 視頻錯(cuò)誤信息回調(diào) flvPlayer.value.on(mpegts.Events.ERROR, (errorType: any, errorDetail: any, errorInfo: any) => { console.log( '類型:' + JSON.stringify(errorType), '報(bào)錯(cuò)內(nèi)容' + errorDetail, '報(bào)錯(cuò)信息' + errorInfo ); }); //【重要事件監(jiān)聽】http 請(qǐng)求建立好后,該事件會(huì)一直監(jiān)聽 mpegts 實(shí)例 flvPlayer.value.on(mpegts.Events.STATISTICS_INFO, () => { const end = flvPlayer.value.buffered.end(0); //獲取當(dāng)前buffered值(緩沖區(qū)末尾) const differTime = end - flvPlayer.value.currentTime; //獲取bufferend與當(dāng)前播放位置的差值 console.log('差值為:' + differTime); }); }; /** * 重新加載視頻 */ const load = () => { for (let index = 1; index < 5; index++) { if (!videoMap.has('video-contianer-' + index)) { initFlv({ URL: 'http://localhost:1010/video/' + tag.value,//這里改成自己要拉流的視頻地址,我這里放的是自己后端推送的1078視頻的flv實(shí)時(shí)視頻流 elementId: 'video-contianer-' + index }); break; } } }; /** * 播放 */ const start = () => flvPlayer.value.play(); /** * 暫停 */ const pause = () => flvPlayer.value.pause(); /** * 銷毀 */ const destory = () => { if (videoMap.size > 0) { for (let [key, flv] of videoMap) { flv.pause; flv.unload(); flv.detachMediaElement(); flv.destroy(); flv = null; videoMap.delete(key); console.log('銷毀掉視頻:' + key); } } else { console.log('沒有要銷毀的視頻'); } }; const getDivClassName = (index: any) => { return 'video-contianer-' + index; }; const saveMap = (index: any) => { test001.value = '-' + index; videoMap.set(index, test001.value); }; onUnmounted(() => { destory(); }); </script>
第五步:設(shè)置展示樣式
<style scoped lang="less"> .play-video-box { height: 45px; margin-top: 10px; margin-left: 200px; } .grid-content { height: 315.5px; margin-top: 5px; margin-left: 5px; } #tag { width: 280px; height: 30px; } //所有控件 video::-webkit-media-controls-enclosure { display: none; } .video { width: 100%; height: 100%; object-fit: cover; } </style>
第六步:效果圖
(我的是在輸入框中輸入想要拉取的設(shè)備和通道號(hào)點(diǎn)擊重新加載即可,多次點(diǎn)擊會(huì)將四個(gè)窗格都展示同樣的視頻)
以上就是vue使用mpegts.js實(shí)現(xiàn)播放flv的直播視頻流的詳細(xì)內(nèi)容,更多關(guān)于vue播放flv的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue增加強(qiáng)緩存和版本號(hào)的實(shí)現(xiàn)方法
這篇文章主要介紹了vue增加強(qiáng)緩存和版本號(hào)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05vue3獲取ref實(shí)例結(jié)合ts的InstanceType問題
這篇文章主要介紹了vue3獲取ref實(shí)例結(jié)合ts的InstanceType問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03vue3 ts組合式API異常onMounted is called when&
這篇文章主要為大家介紹了vue3 ts組合式API異常onMounted is called when there is no active component問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Vue3?路由頁面切換動(dòng)畫?animate.css效果
這篇文章主要介紹了Vue3路由頁面切換動(dòng)畫animate.css效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09van-picker組件default-index屬性設(shè)置不生效踩坑及解決
這篇文章主要介紹了van-picker組件default-index屬性設(shè)置不生效踩坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01vue項(xiàng)目中Eslint校驗(yàn)代碼報(bào)錯(cuò)的解決方案
這篇文章主要介紹了vue項(xiàng)目中Eslint校驗(yàn)代碼報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04