接上一篇h265web.js 同時播放多個視頻,修改官方example 中player.js并重新編譯,這里使用vue2.x封裝最新版本h265web.js v20220916 tag 【注意: 后面有新版本了酷麦,tag v20220916之前的版本內存溢出我只想到定時刷新頁面來解決矿卑,之后的版本未曾嘗試過,自行測試】
也就是這個:
其實h265web.js作者在demo中提供了vue demo的沃饶,如下:
分別是Vue Cli 和 Vite創(chuàng)建的母廷,這都不是重點,重點是demo里面的播放器很簡陋糊肤,可以看到里面都是簡單的播放暫停琴昆,而且沒有樣式。
這樣對于初學者來說不夠友好馆揉,有沒有一個能用的哦业舍,我只想復制粘貼。升酣。舷暮。
來來來,各位看官看這里噩茄,拿走不謝脚牍,也希望大家多多分享自己的學習心得,讓后來的同學們少走彎路巢墅。
這里提一下啊诸狭,大家寫文章的時候要確保正確而且要結合自己的感悟,有時候看別人的博客寫得沒頭沒尾的君纫,而且有的相互copy驯遇,點開都是一樣的內容,有的代碼拿來也跑不起來蓄髓,各種報錯叉庐。。会喝。真的很浪費時間啊喂陡叠。
扯遠了玩郊,本文這里其實是結合上篇文章【見文章開頭】的v20211204 tag 中的example,簡單將html和css拿過來包裝修改枉阵,改成vue中的版本译红,并帶上視頻底部controller。最后頁面效果如下:
代碼如下:
1.首先去官網(wǎng)下載最新h265web.js v20220916 tag 兴溜,下載后解壓將dist目錄中的文件復制到自己的項目中侦厚。
在index.html中引入missile.js
開始封裝,這是我的文件目錄:
2.組件封裝代碼如下拙徽,這里使用了elementui@2.7.2刨沦,vue@2.5.2:
index.vue
<!--h265webjs 播放器,當前是下載官網(wǎng)的tag v20220916 版本膘怕,修改example中play.js后的版本
只是修改了dom盒子的獲取想诅,源碼是直接取的id定位,這樣不能渲染多個視頻盒子岛心,因此把這部分代碼改了
-->
<template>
<div v-loading="loading"
element-loading-text=""
element-loading-spinner="el-icon-loading"
element-loading-background="transparent"
:class="['player-container',videoBoxClass]">
<!-- video dom-->
<div :id="config.player" class="glplayer"></div>
<!-- controller-->
<div class="controller">
<!-- 插件視頻時長獲取錯誤来破,導致計算的進度條有問題,這里隱藏-->
<div class="progress-common progress-contaniner" style="display: none;">
<div class="progress-common cachePts"></div>
<div class="progress-common progressPts"></div>
</div>
<div class="operate-container">
<li class="playBtn">
<a href="javascript:void(0)" title="start">Start</a>
</li>
<span class="ptsLabel">00:00:00/00:00:00</span>
<div class="voice-div">
<span>
<a class="muteBtn" href="javascript:void(0)">
<svg class="icon"
style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;"
viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="488">
<path
d="M153.6 665.6V358.4h204.8V256H153.6c-56.32 0-102.4 46.08-102.4 102.4v307.2c0 56.32 46.08 102.4 102.4 102.4h204.8v-102.4H153.6zM358.4 256v102.4l204.8-128v563.2L358.4 665.6v102.4l307.2 204.8V51.2zM768 261.12v107.52c61.44 20.48 102.4 76.8 102.4 143.36s-40.96 122.88-102.4 143.36v107.52c117.76-25.6 204.8-128 204.8-250.88s-87.04-225.28-204.8-250.88z"
p-id="489">
</path>
</svg>
</a>
</span>
<progress class="progressVoice" value="50" max="100"></progress>
</div>
<a class="fullScreenBtn" href="javascript:void(0)">
<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;"
viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="403">
<path
d="M167.8 903.1c-11.5 0-22.9-4.4-31.7-13.1-17.5-17.5-17.5-45.8 0-63.3l221.1-221.1c17.5-17.5 45.9-17.5 63.3 0 17.5 17.5 17.5 45.8 0 63.3L199.4 890c-8.7 8.7-20.2 13.1-31.6 13.1zM638.5 432.4c-11.5 0-22.9-4.4-31.7-13.1-17.5-17.5-17.5-45.8 0-63.3l221.7-221.7c17.5-17.5 45.8-17.5 63.3 0s17.5 45.8 0 63.3L670.1 419.3c-8.7 8.7-20.2 13.1-31.6 13.1zM859.7 903.8c-11.5 0-23-4.4-31.7-13.1L606.7 668.8c-17.5-17.5-17.4-45.9 0.1-63.4s45.9-17.4 63.3 0.1l221.4 221.9c17.5 17.5 17.4 45.9-0.1 63.4-8.8 8.7-20.2 13-31.7 13zM389 432.1c-11.5 0-23-4.4-31.7-13.1L136.1 197.2c-17.5-17.5-17.4-45.9 0.1-63.4s45.9-17.4 63.3 0.1l221.2 221.7c17.5 17.5 17.4 45.9-0.1 63.4-8.7 8.7-20.2 13.1-31.6 13.1z"
fill="#ffffff" p-id="404">
</path>
<path
d="M145 370c-24.7 0-44.8-20.1-44.8-44.8V221.8C100.2 153.5 155.7 98 224 98h103.4c24.7 0 44.8 20.1 44.8 44.8s-20.1 44.8-44.8 44.8H224c-18.9 0-34.2 15.3-34.2 34.2v103.4c0 24.7-20.1 44.8-44.8 44.8zM883.3 370c-24.7 0-44.8-20.1-44.8-44.8V221.8c0-18.9-15.3-34.2-34.2-34.2H700.8c-24.7 0-44.8-20.1-44.8-44.8S676.1 98 700.8 98h103.5c68.2 0 123.8 55.5 123.8 123.8v103.5c0 24.7-20.1 44.7-44.8 44.7zM327.5 926.6H224c-68.2 0-123.8-55.5-123.8-123.8V699.4c0-24.7 20.1-44.8 44.8-44.8s44.8 20.1 44.8 44.8v103.5c0 18.9 15.3 34.2 34.2 34.2h103.5c24.7 0 44.8 20.1 44.8 44.8s-20.1 44.7-44.8 44.7zM804.3 926.6H700.8c-24.7 0-44.8-20.1-44.8-44.8s20.1-44.8 44.8-44.8h103.5c18.9 0 34.2-15.4 34.2-34.2V699.4c0-24.7 20.1-44.8 44.8-44.8 24.7 0 44.8 20.1 44.8 44.8v103.5c0 68.2-55.6 123.7-123.8 123.7z"
fill="#ffffff" p-id="405">
</path>
</svg>
</a>
<span class="showLabel" style="display: none;"></span>
</div>
</div>
</div>
</template>
<script>
// import {makeH265webjs} from './player'
import {makeH265webjs} from './player20220916'
const token = "base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1"
export default {
name: 'h265webjs',
props: {
videoBoxClass: { // 播放器外部盒子class
type: String,
default: ''
},
config: {
type: Object,
default() {
return {
player: "glplayer", // video id
width: 960,
height: 540,
token: token,
extInfo: {
moovStartFlag: true,
coreProbePart: 0.1,
ignoreAudio: 1, // 忽略音頻播放(只對H265視頻生效)
// cacheLength: 25,
// probeSize: 8192,
// autoPlay: true
},
// 視頻播放源
url: '', // 獨立參數(shù)
}
}
}
},
data() {
return {
player: null,
resizeTimer: null, // resize 定時器
// 優(yōu)化
loading: false,
loadingTimer:null,
}
},
// watch: {
// 'config.url': {
// deep: true,
// handler(val) {
// this.initVideo()
// }
// }
// },
mounted() {
this.initVideo()
},
beforeDestroy() {
this.resizeTimer && clearTimeout(this.resizeTimer)
this.loadingTimer && clearTimeout(this.loadingTimer)
this.destoryVideo()
},
methods: {
initVideo() {
this.loading = true
this.destoryVideo()
this.player = makeH265webjs(this.config.url, {
token,
width: this.$el.clientWidth || 300,
height: this.$el.clientHeight || 400,
...this.config,
event:{
onLoadFinish:()=>{
this.loading = false
}
}
}, `.${this.videoBoxClass}`); // 修改了打包后的源碼的
window.addEventListener('resize', this.resizeFn)
},
// 釋放資源
destoryVideo() {
window.removeEventListener('resize', this.resizeFn)
this.player && this.player.release && this.player.release();
this.player = null
let playerDom = document.getElementById(this.config.player)
if (playerDom) { // 清空
playerDom.innerHTML = ''
}
},
getWH() {
return {
width: this.config.width || this.$el.clientWidth || 300,
height: this.config.height || this.$el.clientHeight || 400,
}
},
resizeFn() {
if (this.resizeTimer) clearTimeout(this.resizeTimer)
this.resizeTimer = setTimeout(() => { // 有的版本沒有resize方法....
let {width, height} = this.getWH()
// console.log(this.player.resize,this.player.resize, width, height, 1111)
this.player.resize && this.player.resize(width, height)
}, 200)
}
}
}
</script>
<style scoped lang="less">
//button.css
.controller li {
position: relative;
float: left;
border: 15px solid #404040;
color: #404040;
height: 0;
width: 0;
-webkit-border-radius: 100%;
-moz-border-radius: 100%;
-o-border-radius: 100%;
border-radius: 100%;
margin: 0 5px;
}
.controller li a {
border-style: solid;
text-indent: -9999px;
position: absolute;
top: -8px;
left: -5px;
}
.playBtn a {
border-color: transparent transparent transparent #fff;
border-width: 8px 0 8px 12px;
width: 0;
height: 0;
}
.pauseBtn a {
border-color: transparent white;
border-width: 0 3px;
height: 15px;
width: 6px;
left: -6px;
}
.stopBtn a {
border: 7px solid #fff;
height: 0;
width: 0;
left: -7px;
top: -7px;
}
.forwardBtn a {
border-left-width: 8px;
left: 1px;
}
.forwardBtn a:first-child {
margin-left: -7px;
}
.rewindBtn a {
border-width: 8px 8px 8px 0;
border-color: transparent #fff transparent transparent;
width: 0;
height: 0;
}
.rewindBtn a:first-child {
margin-left: -7px;
}
.ejectBtn a.arrow {
border-width: 0 8px 8px 8px;
border-color: transparent transparent #fff transparent;
top: -26px;
left: -8px;
}
.ejectBtn a.dash {
border-width: 0 0 4px;
border-color: transparent transparent #fff;
height: 0;
width: 16px;
left: -8px;
top: 4px;
}
//index.css
.player-container {
position: relative;
/*width: 960px;
height: 540px;*/
/*overflow: hidden;*/
}
.bottom-container {
margin-top: 600px;
}
.controller {
background-color: black;
/*background-image: linear-gradient(
to right, red 50px, yellow, blue, green);*/
/*background-position: 100% 50%;*/
width: 100%;
min-height: 50px;
position: absolute;
/*float: bottom;*/
z-index: 99999;
left: 0;
bottom: 0;
}
/*.controller:hover {
background-color: white;
}*/
.operate-container {
min-height: 20px;
padding: 3px;
/*position: relative;
top: 50%;
transform: translateY(-50%);*/
}
.muteBtn {
color: white;
}
.progressVoice {
float: left;
width: 50%;
margin-top: 0.2rem;
/*border: 10px solid rgba(255,255,255,0);*/
color: #d9d9d9;
height: 10px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: none;
}
.progressVoice::-moz-progress-bar {
background-color: #d9d9d9;
}
.progressVoice::-webkit-progress-value {
background-color: #d9d9d9;
}
.coverLayer {
width: 100%;
height: 100%;
padding-top: 300px;
z-index: 10000;
position: absolute;
top: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0.5);
}
.coverLayerBtn {
width: 20%;
height: 200px;
border-radius: 50px;
}
.ptsLabel {
font-size: 15px;
color: white;
background: rgb(0, 0, 0);
/*border: 1px solid white;*/
float: left;
/*border-radius: 7px;*/
padding: 1px;
margin-top: 4px;
margin-left: 5px;
}
.voice-div {
color: white;
/*background: rgb(0, 0, 0);
border: 2px solid white;
border-radius: 7px;
padding-left: 20px;*/
width: 18%;
float: left;
margin-top: 3px;
margin-left: 10px;
/*position: relative;*/
/*margin-top: 50%;*/
/*transform: translateY(-50%);*/
}
.voice-div > span {
/*font-size: 15px;*/
float: left;
color: white;
margin-right: 5px;
}
.voice-div > progress {
margin-top: 8px;
}
.fullScreenBtn {
/*font-size: 10px;*/
float: right;
margin-top: 3px;
margin-right: 5px;
color: white;
/*background: #ffffff;*/
/*border: 2px solid white;*/
/*text-align: center;*/
/*line-height: 20px;*/
height: 24px;
/*font-weight: bold;*/
/*border-radius: 7px;*/
}
.showLabel {
height: 18px;
font-size: 8px;
color: white;
background: rgb(0, 0, 0);
border-bottom: 1px solid #666666;
/*border-radius: 7px;*/
padding-top: 1px;
padding-left: 5px;
padding-right: 5px;
float: right;
margin-top: 5px;
margin-right: 5px;
}
//progress.css
.progress-common {
height: 10px; /** same as progress-contaniner **/
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: none;
margin-bottom: 2px;
}
.progress-contaniner {
z-index: 1000;
width: 100%;
background-color: #666666;
}
.cachePts {
position: absolute;
z-index: 1001;
width: 0px;
/*margin-top: 0.125rem;*/
background-color: #d9d9d9;
}
/*.cachePts::-moz-progress-bar {
background-color: #e9e9e9;
}
.cachePts::-webkit-progress-value {
background-color: #e9e9e9;
}*/
.progressPts {
position: absolute;
z-index: 1002;
width: 0px;
/*margin-top: 0.125rem;*/
background-color: rgba(246, 79, 30, 255);
}
/*.progressPts::-moz-progress-bar {
background-color: yellow;
}
.progressPts::-webkit-progress-value {
background-color: yellow;
}*/
</style>
<style scoped lang="less">
// 自定義樣式
.player-container {
background: black;
/deep/ .el-loading-spinner {
margin-top: 0;
transform: translateY(-50%);
i {
font-size: 10em;
color: #ffffff;
font-weight: bold;
}
}
}
</style>
player20220916.js
import H265webjsModule from '../../../../static/h265webjs/index'
const SHOW_LOADING = "加載中...";
const SHOW_DONE = "已就緒";
function durationFormatSubVal(val) {
let valStr = val.toString();
if (valStr.length < 2) {
return '0' + valStr;
}
return valStr;
}
function durationText(duration) {
if (duration < 0) {
return "Play";
}
let durationSecInt = Math.round(duration);
return durationFormatSubVal(Math.floor(durationSecInt / 3600))
+ ":" + durationFormatSubVal(Math.floor((durationSecInt % 3600) / 60))
+ ":" + durationFormatSubVal(Math.floor(durationSecInt % 60));
}
const getMsTime = () => {
return new Date().getTime();
};
/***************************************************
*
*
*
* 1. H.265/HEVC MP4/FLV/HLS/TS
* Demo for create player(MP4/FLV/HLS/TS)
* 點播/直播播放器創(chuàng)建Demo(MP4/FLV/HLS/TS)
*
*
*
***************************************************/
// clear cache count
H265webjsModule.clear();
export function makeH265webjs(videoURL, config, wrapBox) {
let configEventCallback = config.event // 官網(wǎng)事件回調
let playerId = config.player;
let playerObj = H265webjsModule.createPlayer(videoURL, config);
let playerDom = document.querySelector('#' + playerId);
let playerCont = document.querySelector(wrapBox);
let controllerCont = document.querySelector(wrapBox + ' .controller');
let progressCont = document.querySelector(wrapBox + ' .progress-contaniner');
let progressContW = progressCont.offsetWidth;
let cachePts = progressCont.querySelector(wrapBox + ' .cachePts');
let progressPts = progressCont.querySelector(wrapBox + ' .progressPts');
let progressVoice = document.querySelector(wrapBox + ' .progressVoice');
let playBar = document.querySelector(wrapBox + ' .playBtn');
let playBtn = playBar.getElementsByTagName('a')[0];
let showLabel = document.querySelector(wrapBox + ' .showLabel');
let ptsLabel = document.querySelector(wrapBox + ' .ptsLabel');
// let coverToast = document.querySelector(wrapBox + ' .coverLayer');
// let coverBtn = document.querySelector(wrapBox + ' .coverLayerBtn');
let muteBtn = document.querySelector(wrapBox + ' .muteBtn');
// let debugYUVBtn = document.querySelector('#debugYUVBtn');
// let debugYUVATag = document.querySelector('#debugYUVUrl');
let fullScreenBtn = document.querySelector(wrapBox + ' .fullScreenBtn');
let mediaInfo = null;
playBtn.disabled = true;
// playBar.textContent = '>';
showLabel.textContent = SHOW_LOADING;
playerCont.style.width = config.width + 'px';
playerCont.style.height = config.height + 'px';
controllerCont.style.width = config.width + 'px';
let muteState = false;
// controllerCont.style.left = playerContainer.clientLeft;
// controllerCont.style.bottom = playerContainer.clientBottom;
// alert(playerContainer.clientLeft);
let playAction = () => {
console.log("is playing:", playerObj.isPlaying());
if (playerObj.isPlaying()) {
console.log("bar pause============>");
// playBar.textContent = '>';
playBar.setAttribute('class', 'playBtn');
playerObj.pause();
} else {
// playBar.textContent = '||';
playBar.setAttribute('class', 'pauseBtn');
playerObj.play();
}
};
playerCont.onmouseover = function () {
controllerCont.hidden = false;
};
playerCont.onmouseout = function () {
controllerCont.hidden = true;
};
playerDom.onmouseup = function () {
playAction();
};
playBtn.onclick = () => {
playAction();
};
// 喇叭點擊
muteBtn.onclick = () => {
// console.log(playerObj.getVolume());
if (muteState === true) {
playerObj.setVoice(1.0);
progressVoice.value = 100;
} else {
playerObj.setVoice(0.0);
progressVoice.value = 0;
}
muteState = !muteState;
};
fullScreenBtn.onclick = () => {
playerObj.fullScreen();
// setTimeout(() => {
// playerObj.closeFullScreen();
// }, 2000);
};
// 進度條點擊
// progressCont.addEventListener('click', (e) => {
// showLabel.textContent = SHOW_LOADING;
// let x = e.pageX - progressCont.getBoundingClientRect().left; // or e.offsetX (less support, though)
// let y = e.pageY - progressCont.getBoundingClientRect().top; // or e.offsetY
// let clickedValue = x * progressCont.max / progressCont.offsetWidth;
// // alert(clickedValue);
// playerObj.seek(clickedValue);
// });
// 聲音進度條點擊
progressVoice.addEventListener('click', (e) => {
let x = e.pageX - progressVoice.getBoundingClientRect().left; // or e.offsetX (less support, though)
let y = e.pageY - progressVoice.getBoundingClientRect().top; // or e.offsetY
let clickedValue = x * progressVoice.max / progressVoice.offsetWidth;
progressVoice.value = clickedValue;
let volume = clickedValue / 100;
// alert(volume);
// console.log(
// progressVoice.offsetLeft, // 209
// x, y, // 324 584
// progressVoice.max, progressVoice.offsetWidth);
playerObj.setVoice(volume);
});
playerObj.onSeekStart = (pts) => {
showLabel.textContent = SHOW_LOADING + " seek to:" + parseInt(pts);
};
playerObj.onSeekFinish = () => {
showLabel.textContent = SHOW_DONE;
};
playerObj.onPlayFinish = () => {
console.log("============= FINISHED ===============");
// playBar.textContent = '>';
playBar.setAttribute('class', 'playBtn');
// playerObj.release();
// console.log("=========> release ok");
};
playerObj.onRender = (width, height, imageBufferY, imageBufferB, imageBufferR) => {
console.log("on render");
};
playerObj.onOpenFullScreen = () => {
console.log("onOpenFullScreen");
};
playerObj.onCloseFullScreen = () => {
console.log("onCloseFullScreen");
};
// Seek完成
playerObj.onSeekFinish = () => {
showLabel.textContent = SHOW_DONE;
};
// 當前正在緩存幀數(shù)據(jù)
playerObj.onLoadCache = () => {
showLabel.textContent = "Caching...";
};
// 幀數(shù)據(jù)緩存完成
playerObj.onLoadCacheFinshed = () => {
showLabel.textContent = SHOW_DONE;
};
// 播放器封面圖加載完成
playerObj.onReadyShowDone = () => {
console.log("onReadyShowDone");
showLabel.textContent = "Cover Img OK";
};
// 媒體文件當前加載成功鹉梨,可以進行播放
playerObj.onLoadFinish = () => {
if(configEventCallback && configEventCallback.onLoadFinish){
configEventCallback.onLoadFinish()
}
playerObj.setVoice(1.0);
mediaInfo = playerObj.mediaInfo();
console.log("mediaInfo===========>", mediaInfo);
/*
meta:
durationMs: 144400
fps: 25
sampleRate: 44100
size: {
width: 864,
height: 480
},
audioNone : false
videoType: "vod"
*/
if (mediaInfo.meta.isHEVC === false) {
console.log("is not HEVC/H.265 media!");
//coverToast.removeAttribute('hidden');
//coverBtn.style.width = '100%';
//coverBtn.style.fontSize = '50px';
//coverBtn.innerHTML = 'is not HEVC/H.265 media!';
//return;
}
//console.log("is HEVC/H.265 media.");
playBtn.disabled = false;
if (mediaInfo.meta.audioNone) {
progressVoice.value = 0;
progressVoice.style.display = 'none';
} else {
playerObj.setVoice(0.5);
}
if (mediaInfo.videoType == "vod") {
cachePts.max = mediaInfo.meta.durationMs / 1000;
progressCont.max = mediaInfo.meta.durationMs / 1000;
ptsLabel.textContent = durationText(0) + '/' + durationText(progressCont.max);
} else {
cachePts.hidden = true;
progressCont.hidden = true;
ptsLabel.textContent = 'LIVE';
if (mediaInfo.meta.audioNone === true) {
// playBar.textContent = '||';
// playerObj.play();
} else {
// coverToast.removeAttribute('hidden');
// coverBtn.onclick = () => {
// // playBar.textContent = '||';
// playAction();
// coverToast.setAttribute('hidden', 'hidden');
// };
}
}
showLabel.textContent = SHOW_DONE;
};
// 播放器緩沖進度回調 -- no
playerObj.onCacheProcess = (cPts) => {
// 追幀設置
// if(playerObj.isPlaying()){
// // setInterval(()=>{
// // playerObj.seek(cPts);
// // }, 1000)
// }
// console.log("onCacheProcess => ", cPts, playerObj.mediaInfo().meta.durationMs);
try {
// cachePts.value = cPts;
let precent = cPts / progressCont.max;
let cacheWidth = precent * progressContW;
// console.log(precent, precent * progressCont.offsetWidth);
cachePts.style.width = cacheWidth + 'px';
} catch (err) {
console.log(err);
}
};
// 播放器當前播放PTS時刻更新
playerObj.onPlayTime = (videoPTS) => {
// console.log(videoPTS, playerObj.mediaInfo().meta.durationMs, 111)
if (mediaInfo.videoType == "vod") {
// progressPts.value = videoPTS;
let precent = videoPTS / progressCont.max;
let progWidth = precent * progressContW;
// console.log(precent, precent * progressCont.offsetWidth);
progressPts.style.width = progWidth + 'px';
ptsLabel.textContent = durationText(videoPTS) + '/' + durationText(progressCont.max);
} else {
// ptsLabel.textContent = durationText(videoPTS) + '/LIVE';
ptsLabel.textContent = '/LIVE';
}
};
playerObj.do();
return playerObj;
};
// export function exposeAll(){
// H265webjsModule.clear();
// }
注意這個路徑改成你本地的:
3.使用:
h265webjs.vue
<template>
<div class="wrap">
<div class="box-top">
<div style="margin-top: 20px;margin-bottom: 20px;">
<template v-for="(item,index) in configArr">
切換視頻源{{ index + 1 }}:
<el-select :value="item.url" placeholder="請選擇" :key="`select-${index}`" @change="(val)=>changeSrc(item,val)">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
<div class="flex-box">
<template v-for="(item,index) in configArr">
<h265webjs :key="index"
v-if="item.canShow"
:videoBoxClass="item.videoBoxClass"
:config="item"
:style="index===1?'margin-left: 20px;':''"/>
</template>
</div>
</div>
</template>
<script>
import h265webjs from './h265webjs/index'
export default {
name: 'videoPlay3',
components: {
h265webjs
},
data() {
let options = this.$videoTestSrcOption()
return {
options: options,
configArr: [
{
player: "glplayer1",
// width: 960,
// height: 540,
extInfo: {
moovStartFlag: true,
coreProbePart: 0.1,
ignoreAudio: 0,
},
url: options[0].value,
// url: './static/video/HEVC(H.265).m3u8',
// url: './static/video/AVC(H.264).m3u8'
// url: './static/video/test.mp4'
// url: this.$host() + '/videoSrc/obj/media-fe/xgplayer_doc_video/hls/xgplayer-demo.m3u8',
videoBoxClass: 'h265web-box1',
canShow: true // 視頻源更改后讳癌,強制刷新播放器
},
{
player: "glplayer2",
extInfo: {
moovStartFlag: true,
coreProbePart: 0.1,
ignoreAudio: 0,
},
url: options[0].value,
videoBoxClass: 'h265web-box2',
canShow: true // 視頻源更改后穿稳,強制刷新播放器
}
],
}
},
mounted() {
},
beforeDestroy() {
// destoryPlayerServer(this.playerObject)
},
methods: {
changeSrc(item, newUrl) {
if (item.url !== newUrl) {
item.url = newUrl
// 視頻源更改后存皂,v-if強制刷新播放器
item.canShow = false
this.$nextTick(() => {
item.canShow = true
})
}
},
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.flex-box {
display: flex;
justify-content: space-between;
align-items: flex-start;
> div {
width: 100%;
flex: auto;
}
}
.wrap{
padding: 20px;
text-align: left;
.box-top{
background: #7cb1cc;
padding: 20px;
line-height: 30px;
}
}
</style>
這個option的地址改成你的測試視頻源地址即可:
這里還有個注意點,切換視頻源是用的v-if + $nextTick的方式逢艘,為了避免不必要的報錯旦袋,其實我一開始是組件內部監(jiān)聽的方式,但后面因為報錯還是改成了這種它改。
4.參數(shù)說明:
附github demo 地址
因為不止一個小伙伴私下里找我了疤孕,這里還是貼上源碼,可以直接運行方便看到效果央拖。里面有兩個版本祭阀,如果遇到最新版播放卡頓或內存溢出問題可暫時切換為低版本【內存溢出依舊存在,作者后續(xù)看到issue并提交了一版鲜戒,但我還沒有機會驗證】专控,該版本全屏報錯問題已在代碼中修復。
啰嗦一句
我提供的demo中內存溢出問題依舊存在遏餐,只是低版本會好很多伦腐。當時我用的已經(jīng)是最新版本tag v20220916了,最后我的解決方式選擇低版本并“定時刷新頁面”釋放內存失都。然后我給作者提了issue柏蘑,不想定時刷新的小伙伴可以試下tag v20220916后面的版本幸冻,若問題依舊存在可在github上向 h265web.js作者闡明問題(我這邊因為項目結束原因沒機會再測試了)
若對你有幫助,請點個贊吧咳焚,謝謝支持洽损!
本文地址:http://www.reibang.com/p/1f98a9b5e316,轉載請注明出處黔攒,謝謝趁啸。