uniapp使用mui-player插件播放m3u8/flv視頻流示例代碼
背景
uniapp 開(kāi)發(fā)的h5項(xiàng)目,需要播放m3u8/flv后綴的視頻,網(wǎng)上有很多視頻插件,但是樣式和效果不盡如人意,博主最后選擇mui-player插件,定制化稍微強(qiáng)一點(diǎn)以及有官方文檔可以閱讀,官網(wǎng)文檔https://muiplayer.js.org/zh/guide/
tips:建議先閱讀官方文檔,再在頁(yè)面進(jìn)行引入
博主最后實(shí)現(xiàn)的效果如下,pc端和移動(dòng)端為兩種展示樣式,pc可以設(shè)置聲音、播放速度、分辨率、全屏、畫(huà)中畫(huà)等功能,具體還有其他的功能自定義可以參照官網(wǎng),官網(wǎng)的說(shuō)明很詳細(xì)以及有示例進(jìn)行參考;移動(dòng)端和pc端的功能大差不差,只是展現(xiàn)形式略有差別。
1、安裝mui-player插件
npm i mui-player --save
2、頁(yè)面引入,可選擇在需要展示視頻的頁(yè)面直接引入
也可以放入一個(gè)公共組件,這樣方便多個(gè)頁(yè)面都會(huì)使用播放器的情況,博主這里將播放器作為一個(gè)公共組件,在組件里面引入
// 播放器樣式文件 import 'mui-player/dist/mui-player.min.css' // npm安裝方式引入mui-player import MuiPlayer from 'mui-player' // 要播放m3u8的視頻就必須要引入hls.js import Hls from 'hls.js' // 要播放flv的視頻就必須要引入flv.js import Flv from 'flv.js' // 要設(shè)置pc端視頻的清晰度需要引入pc端擴(kuò)展 import MuiPlayerDesktopPlugin from 'mui-player-desktop-plugin'
3、template模板
<template> <view id="mui-player"> <!-- 可在這里添加你想要覆蓋在視頻上面的內(nèi)容,這里我加了一個(gè)關(guān)閉按鈕,層級(jí)最高,不會(huì)影響視頻的播放 --> <image v-if="showCloseIcon" src="@/sub-live/static/close.png" class="pos-a full-close" @click.stop="videoClose"> </view> </template>
4、data定一個(gè)空的mp對(duì)象
data() { return { mp: {} } },
5、需要向使用的頁(yè)面?zhèn)鬟f的參數(shù)
props: { // 視頻流地址,必傳 src: { type: String, default: '' }, // 視頻封面圖,可選 poster: { type: String, default: '' }, // 是否要展示關(guān)閉視頻圖標(biāo) showCloseIcon: { type: Boolean, default: false }, // 當(dāng)前視頻是否是直播模式 live: { type: Boolean, default: false }, // 兼容音頻m3u8(有些音頻地址也是m3u8,但是音頻不需要播放樣式,所以需要兼容) isZero: { type: Boolean, default: false }, // 設(shè)置pc/移動(dòng)端清晰度選擇 childConfig: { type: Array, default: () => [{ functions: '高清', selected: true }, { functions: '標(biāo)清' }, { functions: '流暢' }, ] } }
6、mounted生命周期初始化
mounted() { // 防止this的改變 const _this = this; // 根據(jù)視頻路徑后綴判斷當(dāng)前為m3u8還是flv的視頻流 var flieArr = _this.src.split('.'); var suffix = flieArr[flieArr.length - 1]; // m3u8格式 var a = suffix.indexOf('m3u8') !== -1 // flv格式 var b = suffix.indexOf('flv') !== -1 var c = {} // m3u8格式的視頻配置 if (a) { c = { type: 'hls', loader: Hls, config: { debug: false, } } } // flv格式的視頻配置 if (b) { c = { type: 'flv', loader: Flv, config: { cors: true }, } } // 設(shè)置寬高,兼容音頻,音頻時(shí)高度為1,必須設(shè)置高度,不然音頻沒(méi)發(fā)播放,初始化會(huì)失敗 var sWidth = uni.getSystemInfoSync().screenWidth; // 獲取屏幕寬度 var width = 1; if (!_this.isZero) { // 不為音頻 if (_this.$util.isMobile()) { // 移動(dòng)端動(dòng)態(tài)獲取 width = sWidth; } else { width = 640; // pc端固定寬度為640 } } var height = 1; if (!_this.isZero) { height = parseInt(width * 9 / 16) // 可改成你想設(shè)置的視頻的高度,博主這里設(shè)置為寬高比為16:9的視頻 } _this.mp = new MuiPlayer({ // 指定播放器容器 container: '#mui-player', // 視頻播放的資源地址 src: _this.src, // 是否自動(dòng)播放,親測(cè)在ios某些機(jī)型上自動(dòng)播放失效 autoplay: false, // 是否靜音播放 muted: false, // 初始化播放器寬度 width: width, // 初始化播放器高度 height: height, // 播放器容器是否自適應(yīng)視頻高度 autoFit: false, // 是否循環(huán)播放 loop: false, // 視頻封面的資源地址 poster: _this.poster, // 是否開(kāi)啟直播模式,直播模式默認(rèn)菜單配置不允許控制播放速度以及循環(huán)播放 live: _this.live, // 配置聲明啟用同層播放 videoAttribute: [{ attrKey: 'webkit-playsinline', attrValue: 'webkit-playsinline' }, { attrKey: 'playsinline', attrValue: 'playsinline' }, { attrKey: 'x5-video-player-type', attrValue: 'h5-page' }, ], // flv以及m3u8視頻資源的配置 parse: c, // 自定義主題顏色 themeColor: _this.$config.INFO.THEME_COLOR, // 非全屏模式下,是否顯示播放器頭部操作控件,具體可參考官方文檔 pageHead: false, plugins: [ // pc端清晰度設(shè)置 new MuiPlayerDesktopPlugin({ customSetting: _this.childConfig.length > 0 ? [{ functions: '清晰度', model: 'select', show: true, zIndex: 0, childConfig: _this.childConfig, onToggle: function(data, selected) { let onToggleLoad = function(state) { _this.mp.once('ready', function() { let _video = _this.mp.video(); let _execute = function() { _video.currentTime = state .currentTime; state.paused ? _video.pause() : _video.play(); } if (_video.readyState == 0) { _video.addEventListener( 'durationchange', function(e) { _execute(); }, { once: true }) } else { _execute(); } }) } // 選擇清晰度后重載視頻 selected(function() { let _video = _this.mp.video(); onToggleLoad({ currentTime: _video.currentTime, paused: _video.paused }); // 將當(dāng)前選擇的清晰度傳遞給父組件 _this.$emit('onToggleFn', data.functions) }); } }] : [] }) ] }); // 必須放在nextTick里面,等待dom渲染完成再監(jiān)聽(tīng)視頻的播放事件等,視頻的其他事件也可在此處進(jìn)行監(jiān)聽(tīng) _this.$nextTick(() => { // 監(jiān)聽(tīng)播放器已創(chuàng)建完成 _this.mp.on('ready', function(event) { let _video = _this.mp.video(); _video.addEventListener("play",function(e){ //播放事件 _this.$emit('onPlayFn') }); _video.addEventListener("ended",function(e){ //播放完成事件 _this.$emit('onEndedFn') }); }); // 播放發(fā)生錯(cuò)誤 _this.mp.on('error', function(event) { console.log('error', event); }); }) }
7、組件銷(xiāo)毀,視頻播放器也要銷(xiāo)毀
destroyed() { this.mp.destroy(); },
8、可在組件內(nèi)定義一些播放/暫停的事件供父組件調(diào)用(按需寫(xiě)入)
// 關(guān)閉視頻,返回上一頁(yè) videoClose() { uni.navigateBack(); }, // 播放視頻 playVideo() { let _video = this.mp.video(); // 獲取視頻示例 _video.paused ?_video.play(): _video.pause(); // 和原生video事件一致 }, // 暫停視頻 pauseVideo(){ let _video = this.mp.video(); _video.pause(); }
9、播放視頻組件完整代碼,可按需進(jìn)行增刪改
<template> <view id="mui-player"> <image v-if="showCloseIcon" src="@/sub-live/static/close.png" class="pos-a full-close" @click.stop="videoClose"> </view> </template> <script> import 'mui-player/dist/mui-player.min.css' import MuiPlayer from 'mui-player' import Hls from 'hls.js' import Flv from 'flv.js' import MuiPlayerDesktopPlugin from 'mui-player-desktop-plugin' export default { props: { src: { type: String, default: '' }, poster: { type: String, default: '' }, showCloseIcon: { type: Boolean, default: false }, live: { type: Boolean, default: false }, // 兼容音頻m3u8 isZero: { type: Boolean, default: false }, childConfig: { type: Array, default: () => [{ functions: '高清', selected: true }, { functions: '標(biāo)清' }, { functions: '流暢' }, ] } }, data() { return { mp: {} } }, watch: { src(newVal, oldVal) { this.mp.reloadUrl(newVal); } }, mounted() { const _this = this; var flieArr = _this.src.split('.'); var suffix = flieArr[flieArr.length - 1]; // m3u8格式 var a = suffix.indexOf('m3u8') !== -1 // flv格式 var b = suffix.indexOf('flv') !== -1 var c = {} if (a) { c = { type: 'hls', loader: Hls, config: { debug: false, } } } if (b) { c = { type: 'flv', loader: Flv, config: { cors: true }, } } var sWidth = uni.getSystemInfoSync().screenWidth; var width = 1; if (!_this.isZero) { if (_this.$util.isMobile()) { width = sWidth; } else { width = 640; } } var height = 1; if (!_this.isZero) { height = parseInt(width * 9 / 16) } _this.mp = new MuiPlayer({ // 指定播放器容器 container: '#mui-player', // 視頻播放的資源地址 src: _this.src, autoplay: false, muted: false, width: width, // 初始化播放器高度 height: height, // 播放器容器是否自適應(yīng)視頻高度 autoFit: false, // loop loop: false, // 視頻封面的資源地址 poster: _this.poster, // 是否開(kāi)啟直播模式,直播模式默認(rèn)菜單配置不允許控制播放速度以及循環(huán)播放 live: _this.live, // 配置聲明啟用同層播放 videoAttribute: [{ attrKey: 'webkit-playsinline', attrValue: 'webkit-playsinline' }, { attrKey: 'playsinline', attrValue: 'playsinline' }, { attrKey: 'x5-video-player-type', attrValue: 'h5-page' }, ], parse: c, // 自定義主題顏色 themeColor: _this.$config.INFO.THEME_COLOR, // 非全屏模式下,是否顯示播放器頭部操作控件 pageHead: false, plugins: [ new MuiPlayerDesktopPlugin({ customSetting: _this.childConfig.length > 0 ? [{ functions: '清晰度', model: 'select', show: true, zIndex: 0, childConfig: _this.childConfig, onToggle: function(data, selected) { let onToggleLoad = function(state) { _this.mp.once('ready', function() { let _video = _this.mp.video(); let _execute = function() { _video.currentTime = state .currentTime; state.paused ? _video.pause() : _video.play(); } if (_video.readyState == 0) { _video.addEventListener( 'durationchange', function(e) { _execute(); }, { once: true }) } else { _execute(); } }) } selected(function() { let _video = _this.mp.video(); onToggleLoad({ currentTime: _video.currentTime, paused: _video.paused }); _this.$emit('onToggleFn', data.functions) }); } }] : [] }) ] }); _this.$nextTick(() => { // 監(jiān)聽(tīng)播放器已創(chuàng)建完成 _this.mp.on('ready', function(event) { let _video = _this.mp.video(); _video.addEventListener("play",function(e){ //播放事件 _this.$emit('onPlayFn') }); _video.addEventListener("ended",function(e){ //播放完成事件 _this.$emit('onEndedFn') }); }); // 播放發(fā)生錯(cuò)誤 _this.mp.on('error', function(event) { console.log('error', event); }); }) }, destroyed() { console.log('destroyed'); this.mp.destroy(); }, methods: { videoClose() { uni.navigateBack(); }, playVideo() { let _video = this.mp.video(); _video.paused ?_video.play(): _video.pause(); }, pauseVideo(){ let _video = this.mp.video(); _video.pause(); } }, } </script> <style lang="scss" scoped> #mui-player{ z-index: 2; } .full-close { top: 22rpx; right: 22rpx; width: 44rpx; height: 44rpx; cursor: pointer; z-index: 8; } </style>
10、父組件調(diào)用播放器,按需進(jìn)行修改
<!-- #ifdef H5 --> <common-player ref="muiplayer" :showCloseIcon="true" :poster="liveDetailInfo.thumb" :live="liveDetailInfo.start_time <= nowTime && nowTime <= liveDetailInfo.end_time ? true : false" :src="liveDetailInfo.rewriteVideoUrl" :childConfig="liveDetailInfo.qxdConfig" @onToggleFn="qxdToggle" @onEndedFn="ended" @onPlayFn="playFn"> </common-player> <!-- #endif -->
總結(jié):
此播放器還是使用了開(kāi)源的mui-player,所以盡量先去看文檔,文檔寫(xiě)的很詳細(xì),只是需要大面積的增刪改操作,最后定制為自已想要的樣子。
到此這篇關(guān)于uniapp使用mui-player插件播放m3u8/flv視頻流的文章就介紹到這了,更多相關(guān)uniapp播放m3u8/flv視頻流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js獲取當(dāng)前日期昨天、今天、明天日期的不同方法總結(jié)
JS中處理日期時(shí)間常用Date對(duì)象,下面這篇文章主要給大家介紹了關(guān)于利用js獲取當(dāng)前日期昨天、今天、明天日期的不同方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11JS函數(shù)的call和apply的實(shí)現(xiàn)方法區(qū)別分析
這篇文章主要為大家介紹了JS函數(shù)的call和apply的實(shí)現(xiàn)方法區(qū)別分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10硬盤(pán)瀏覽程序,保存成網(wǎng)頁(yè)格式便可使用
硬盤(pán)瀏覽程序,保存成網(wǎng)頁(yè)格式便可使用...2006-12-12詳解JavaScript節(jié)流函數(shù)中的Throttle
函數(shù)節(jié)流,就是對(duì)會(huì)頻繁觸發(fā)的函數(shù)事件做一些限制,讓這些函數(shù)可以在每隔一定的時(shí)間或者每次滿(mǎn)足一定的條件下再觸發(fā)。一般我們會(huì)給他起一個(gè)名字throttle。也就是節(jié)流的意思。一般這樣的函數(shù)有 resize事件、ontouchmove事件等。2016-07-07JS實(shí)現(xiàn)的tab切換并顯示相應(yīng)內(nèi)容模塊功能示例
這篇文章主要介紹了JS實(shí)現(xiàn)的tab切換并顯示相應(yīng)內(nèi)容模塊功能,結(jié)合實(shí)例形式分析了JavaScript基于事件響應(yīng)、元素遍歷實(shí)現(xiàn)頁(yè)面tab切換功能相關(guān)操作技巧,需要的朋友可以參考下2019-08-08使用js原生實(shí)現(xiàn)年份輪播選擇效果實(shí)例
這篇文章主要給大家介紹了關(guān)于如何使用js原生實(shí)現(xiàn)年份輪播選擇效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01理解JavaScript設(shè)計(jì)模式中的建造者模式
這篇文章主要介紹了理解JavaScript設(shè)計(jì)模式中的建造者模式,文章基于JavaScript的相關(guān)資料展開(kāi)箱子內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-04-04原生JS實(shí)現(xiàn)天氣預(yù)報(bào)
這篇文章主要為大家詳細(xì)介紹了原生JS實(shí)現(xiàn)天氣預(yù)報(bào),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06