feat(liveView): 添加视频播放器控件并优化媒体流处理
- 新增video元素用于统一播放音视频流 - 合并音频和视频轨道到单一媒体流 - 优化播放器控件设置和样式 - 移除冗余代码并简化DOM操作
This commit is contained in:
parent
2103d3fcc1
commit
51da660509
@ -4,64 +4,34 @@
|
|||||||
<div id="liveContent" class="liveContent" ref="liveContent">
|
<div id="liveContent" class="liveContent" ref="liveContent">
|
||||||
<div id="screenAudio" style="display: none" ref="screenAudio"></div>
|
<div id="screenAudio" style="display: none" ref="screenAudio"></div>
|
||||||
<div class="live-status" v-show="liveStatus == 'scheduled'">
|
<div class="live-status" v-show="liveStatus == 'scheduled'">
|
||||||
<svg
|
<svg t="1733991622296" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
t="1733991622296"
|
p-id="7587" width="38" height="38" data-spm-anchor-id="a313x.search_index.0.i3.59a33a81UKNXHQ">
|
||||||
class="icon"
|
|
||||||
viewBox="0 0 1024 1024"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
p-id="7587"
|
|
||||||
width="38"
|
|
||||||
height="38"
|
|
||||||
data-spm-anchor-id="a313x.search_index.0.i3.59a33a81UKNXHQ"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M526.933333 288c-23.466667 0-42.666667 19.2-42.666666 42.666667v213.333333c0 23.466667 19.2 42.666667 42.666666 42.666667s42.666667-19.2 42.666667-42.666667v-213.333333c0-23.466667-17.066667-42.666667-42.666667-42.666667zM526.933333 629.333333c-12.8 0-21.333333 4.266667-29.866666 12.8-8.533333 8.533333-12.8 17.066667-12.8 29.866667 0 12.8 4.266667 23.466667 12.8 29.866667 8.533333 8.533333 19.2 12.8 29.866666 12.8 12.8 0 21.333333-4.266667 29.866667-12.8s12.8-19.2 12.8-32-4.266667-23.466667-12.8-29.866667c-6.4-6.4-17.066667-10.666667-29.866667-10.666667z"
|
d="M526.933333 288c-23.466667 0-42.666667 19.2-42.666666 42.666667v213.333333c0 23.466667 19.2 42.666667 42.666666 42.666667s42.666667-19.2 42.666667-42.666667v-213.333333c0-23.466667-17.066667-42.666667-42.666667-42.666667zM526.933333 629.333333c-12.8 0-21.333333 4.266667-29.866666 12.8-8.533333 8.533333-12.8 17.066667-12.8 29.866667 0 12.8 4.266667 23.466667 12.8 29.866667 8.533333 8.533333 19.2 12.8 29.866666 12.8 12.8 0 21.333333-4.266667 29.866667-12.8s12.8-19.2 12.8-32-4.266667-23.466667-12.8-29.866667c-6.4-6.4-17.066667-10.666667-29.866667-10.666667z"
|
||||||
p-id="7588"
|
p-id="7588" fill="#ffffff"></path>
|
||||||
fill="#ffffff"
|
|
||||||
></path>
|
|
||||||
<path
|
<path
|
||||||
d="M526.933333 74.666667c-234.666667 0-426.666667 192-426.666666 426.666666s192 426.666667 426.666666 426.666667 426.666667-192 426.666667-426.666667-189.866667-426.666667-426.666667-426.666666z m0 768c-187.733333 0-341.333333-153.6-341.333333-341.333334s153.6-341.333333 341.333333-341.333333 341.333333 153.6 341.333334 341.333333-151.466667 341.333333-341.333334 341.333334z"
|
d="M526.933333 74.666667c-234.666667 0-426.666667 192-426.666666 426.666666s192 426.666667 426.666666 426.666667 426.666667-192 426.666667-426.666667-189.866667-426.666667-426.666667-426.666666z m0 768c-187.733333 0-341.333333-153.6-341.333333-341.333334s153.6-341.333333 341.333333-341.333333 341.333333 153.6 341.333334 341.333333-151.466667 341.333333-341.333334 341.333334z"
|
||||||
p-id="7589"
|
p-id="7589" fill="#ffffff"></path>
|
||||||
fill="#ffffff"
|
|
||||||
></path>
|
|
||||||
</svg>
|
</svg>
|
||||||
オンライン授業未开始
|
オンライン授業未开始
|
||||||
</div>
|
</div>
|
||||||
<div class="live-status" v-show="liveStatus == 'finished'">
|
<div class="live-status" v-show="liveStatus == 'finished'">
|
||||||
<svg
|
<svg t="1733991622296" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
t="1733991622296"
|
p-id="7587" width="38" height="38" data-spm-anchor-id="a313x.search_index.0.i3.59a33a81UKNXHQ">
|
||||||
class="icon"
|
|
||||||
viewBox="0 0 1024 1024"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
p-id="7587"
|
|
||||||
width="38"
|
|
||||||
height="38"
|
|
||||||
data-spm-anchor-id="a313x.search_index.0.i3.59a33a81UKNXHQ"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M526.933333 288c-23.466667 0-42.666667 19.2-42.666666 42.666667v213.333333c0 23.466667 19.2 42.666667 42.666666 42.666667s42.666667-19.2 42.666667-42.666667v-213.333333c0-23.466667-17.066667-42.666667-42.666667-42.666667zM526.933333 629.333333c-12.8 0-21.333333 4.266667-29.866666 12.8-8.533333 8.533333-12.8 17.066667-12.8 29.866667 0 12.8 4.266667 23.466667 12.8 29.866667 8.533333 8.533333 19.2 12.8 29.866666 12.8 12.8 0 21.333333-4.266667 29.866667-12.8s12.8-19.2 12.8-32-4.266667-23.466667-12.8-29.866667c-6.4-6.4-17.066667-10.666667-29.866667-10.666667z"
|
d="M526.933333 288c-23.466667 0-42.666667 19.2-42.666666 42.666667v213.333333c0 23.466667 19.2 42.666667 42.666666 42.666667s42.666667-19.2 42.666667-42.666667v-213.333333c0-23.466667-17.066667-42.666667-42.666667-42.666667zM526.933333 629.333333c-12.8 0-21.333333 4.266667-29.866666 12.8-8.533333 8.533333-12.8 17.066667-12.8 29.866667 0 12.8 4.266667 23.466667 12.8 29.866667 8.533333 8.533333 19.2 12.8 29.866666 12.8 12.8 0 21.333333-4.266667 29.866667-12.8s12.8-19.2 12.8-32-4.266667-23.466667-12.8-29.866667c-6.4-6.4-17.066667-10.666667-29.866667-10.666667z"
|
||||||
p-id="7588"
|
p-id="7588" fill="#ffffff"></path>
|
||||||
fill="#ffffff"
|
|
||||||
></path>
|
|
||||||
<path
|
<path
|
||||||
d="M526.933333 74.666667c-234.666667 0-426.666667 192-426.666666 426.666666s192 426.666667 426.666666 426.666667 426.666667-192 426.666667-426.666667-189.866667-426.666667-426.666667-426.666666z m0 768c-187.733333 0-341.333333-153.6-341.333333-341.333334s153.6-341.333333 341.333333-341.333333 341.333333 153.6 341.333334 341.333333-151.466667 341.333333-341.333334 341.333334z"
|
d="M526.933333 74.666667c-234.666667 0-426.666667 192-426.666666 426.666666s192 426.666667 426.666666 426.666667 426.666667-192 426.666667-426.666667-189.866667-426.666667-426.666667-426.666666z m0 768c-187.733333 0-341.333333-153.6-341.333333-341.333334s153.6-341.333333 341.333333-341.333333 341.333333 153.6 341.333334 341.333333-151.466667 341.333333-341.333334 341.333334z"
|
||||||
p-id="7589"
|
p-id="7589" fill="#ffffff"></path>
|
||||||
fill="#ffffff"
|
|
||||||
></path>
|
|
||||||
</svg>
|
</svg>
|
||||||
オンライン授業が終わる
|
オンライン授業が終わる
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="watermark-container" v-if="isVisible" @animationend="onAnimationEnd" :key="animationKey">
|
||||||
class="watermark-container"
|
|
||||||
v-if="isVisible"
|
|
||||||
@animationend="onAnimationEnd"
|
|
||||||
:key="animationKey"
|
|
||||||
>
|
|
||||||
{{ loginInfo.member_realname }}_{{ loginInfo.member_passport }}
|
{{ loginInfo.member_realname }}_{{ loginInfo.member_passport }}
|
||||||
</div>
|
</div>
|
||||||
<div id="teacherCamera" class="teacherCamera" ref="teacherCamera"></div>
|
<div id="teacherCamera" class="teacherCamera" ref="teacherCamera"></div>
|
||||||
|
<video ref="player" controls style="width: 100%; height: 100%;"></video>
|
||||||
<!-- <div class="custom-controls" v-show="showControlBar">
|
<!-- <div class="custom-controls" v-show="showControlBar">
|
||||||
<div class="teacherAudioList" v-show="teacherAudioList.length > 0">
|
<div class="teacherAudioList" v-show="teacherAudioList.length > 0">
|
||||||
<div v-for="(teacherAudio, index) in teacherAudioList" class="teacherAudio">
|
<div v-for="(teacherAudio, index) in teacherAudioList" class="teacherAudio">
|
||||||
@ -212,13 +182,8 @@
|
|||||||
<img :src="message.avatar" alt="avatar" class="avatar" />
|
<img :src="message.avatar" alt="avatar" class="avatar" />
|
||||||
<div class="message-body">
|
<div class="message-body">
|
||||||
<div class="message-header">
|
<div class="message-header">
|
||||||
<span class="message-sender"
|
<span class="message-sender"><span class="teacher-tag"
|
||||||
><span
|
v-if="message.sender.slice(0, 7) === 'teacher'">講師</span>{{ message.sender }}</span>
|
||||||
class="teacher-tag"
|
|
||||||
v-if="message.sender.slice(0, 7) === 'teacher'"
|
|
||||||
>講師</span
|
|
||||||
>{{ message.sender }}</span
|
|
||||||
>
|
|
||||||
<span class="message-time">{{
|
<span class="message-time">{{
|
||||||
"\u00A0\u00A0\u00A0" + formatTimestamp(message.time)
|
"\u00A0\u00A0\u00A0" + formatTimestamp(message.time)
|
||||||
}}</span>
|
}}</span>
|
||||||
@ -231,11 +196,7 @@
|
|||||||
<div ref="scrollAnchor"></div>
|
<div ref="scrollAnchor"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-input">
|
<div class="message-input">
|
||||||
<input
|
<input v-model="newMessage" @keyup.enter="sendMessage" placeholder="メッセージを入力..." />
|
||||||
v-model="newMessage"
|
|
||||||
@keyup.enter="sendMessage"
|
|
||||||
placeholder="メッセージを入力..."
|
|
||||||
/>
|
|
||||||
<button @click="sendMessage">送信</button>
|
<button @click="sendMessage">送信</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -252,46 +213,27 @@
|
|||||||
<div class="info-content-item-title">開始時間</div>
|
<div class="info-content-item-title">開始時間</div>
|
||||||
<div class="info-content-item-value">{{ liveInfo.start_time }}</div>
|
<div class="info-content-item-value">{{ liveInfo.start_time }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="info-content-item" v-show="liveInfo.end_time != '' && liveInfo.end_time != null">
|
||||||
class="info-content-item"
|
|
||||||
v-show="liveInfo.end_time != '' && liveInfo.end_time != null"
|
|
||||||
>
|
|
||||||
<div class="info-content-item-title">終了時間</div>
|
<div class="info-content-item-title">終了時間</div>
|
||||||
<div class="info-content-item-value">{{ liveInfo.end_time }}</div>
|
<div class="info-content-item-value">{{ liveInfo.end_time }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-content-item" style="">
|
<div class="info-content-item" style="">
|
||||||
<div class="info-content-item-title">詳細</div>
|
<div class="info-content-item-title">詳細</div>
|
||||||
<div
|
<div class="info-content-item-value" style="
|
||||||
class="info-content-item-value"
|
|
||||||
style="
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
"
|
">
|
||||||
>
|
<svg t="1733988199430" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
<svg
|
p-id="6925" data-spm-anchor-id="a313x.search_index.0.i0.14ef3a81TzRpck" width="64" height="64"
|
||||||
t="1733988199430"
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
class="icon"
|
|
||||||
viewBox="0 0 1024 1024"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
p-id="6925"
|
|
||||||
data-spm-anchor-id="a313x.search_index.0.i0.14ef3a81TzRpck"
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
d="M892.5 304.6L689.4 101.4c-22.7-22.7-52.8-35.1-84.9-35.1H218.7c-66.2 0-120 53.8-120 120v654.1c0 66.2 53.8 120 120 120h589c66.2 0 120-53.8 120-120v-451c0-32-12.5-62.2-35.2-84.8zM667.7 192.9l123.4 123.4h-83.4c-22.1 0-40-17.9-40-40v-83.4z m140 687.5h-589c-22.1 0-40-17.9-40-40V186.3c0-22.1 17.9-40 40-40h369v130c0 66.2 53.8 120 120 120h140v444.1c0 22-17.9 40-40 40z"
|
d="M892.5 304.6L689.4 101.4c-22.7-22.7-52.8-35.1-84.9-35.1H218.7c-66.2 0-120 53.8-120 120v654.1c0 66.2 53.8 120 120 120h589c66.2 0 120-53.8 120-120v-451c0-32-12.5-62.2-35.2-84.8zM667.7 192.9l123.4 123.4h-83.4c-22.1 0-40-17.9-40-40v-83.4z m140 687.5h-589c-22.1 0-40-17.9-40-40V186.3c0-22.1 17.9-40 40-40h369v130c0 66.2 53.8 120 120 120h140v444.1c0 22-17.9 40-40 40z"
|
||||||
p-id="6926"
|
p-id="6926" fill="#8a8a8a"></path>
|
||||||
fill="#8a8a8a"
|
|
||||||
></path>
|
|
||||||
<path
|
<path
|
||||||
d="M310 378.1h177.1c22.1 0 40-17.9 40-40s-17.9-40-40-40H310c-22.1 0-40 17.9-40 40s17.9 40 40 40zM716.4 473.3H310c-22.1 0-40 17.9-40 40s17.9 40 40 40h406.4c22.1 0 40-17.9 40-40s-17.9-40-40-40zM716.4 648.6H310c-22.1 0-40 17.9-40 40s17.9 40 40 40h406.4c22.1 0 40-17.9 40-40s-17.9-40-40-40z"
|
d="M310 378.1h177.1c22.1 0 40-17.9 40-40s-17.9-40-40-40H310c-22.1 0-40 17.9-40 40s17.9 40 40 40zM716.4 473.3H310c-22.1 0-40 17.9-40 40s17.9 40 40 40h406.4c22.1 0 40-17.9 40-40s-17.9-40-40-40zM716.4 648.6H310c-22.1 0-40 17.9-40 40s17.9 40 40 40h406.4c22.1 0 40-17.9 40-40s-17.9-40-40-40z"
|
||||||
p-id="6927"
|
p-id="6927" fill="#8a8a8a"></path>
|
||||||
fill="#8a8a8a"
|
|
||||||
></path>
|
|
||||||
</svg>
|
</svg>
|
||||||
詳細なし
|
詳細なし
|
||||||
</div>
|
</div>
|
||||||
@ -440,16 +382,25 @@ export default {
|
|||||||
audio.remove(); // 移除 <video> 元素
|
audio.remove(); // 移除 <video> 元素
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
audioTracks[index].play(this.$refs.screenAudio);
|
// audioTracks[index].play(this.$refs.screenAudio);
|
||||||
} else {
|
} else {
|
||||||
this.teacherAudioList.push({
|
this.teacherAudioList.push({
|
||||||
name: audioTracks[index].userID,
|
name: audioTracks[index].userID,
|
||||||
isMute: false,
|
isMute: false,
|
||||||
showVolumeControl: false,
|
showVolumeControl: false,
|
||||||
});
|
});
|
||||||
// console.log("teacherAudioList:", this.teacherAudioList);
|
// audioTracks[index].play(this.liveContent);
|
||||||
|
}
|
||||||
audioTracks[index].play(this.liveContent);
|
// 无论是共享的音频track还是老师的音频track,都统一合并到一起
|
||||||
|
if (this.$refs.player.srcObject) {
|
||||||
|
// 如果已有媒体流,添加新轨道
|
||||||
|
const existingStream = this.$refs.player.srcObject;
|
||||||
|
existingStream.addTrack(audioTracks[index]._track.mediaTrack);
|
||||||
|
} else {
|
||||||
|
// 如果没有媒体流,创建新的并添加轨道
|
||||||
|
const newStream = new MediaStream();
|
||||||
|
newStream.addTrack(audioTracks[index]._track.mediaTrack);
|
||||||
|
this.$refs.player.srcObject = newStream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,37 +411,61 @@ export default {
|
|||||||
// 如果存在 <video> 标签,则遍历并移除它们
|
// 如果存在 <video> 标签,则遍历并移除它们
|
||||||
// console.log("存在屏幕共享::::", videoElements);
|
// console.log("存在屏幕共享::::", videoElements);
|
||||||
|
|
||||||
if (videoElements.length > 0) {
|
// if (videoElements.length > 0) {
|
||||||
videoElements.forEach((video) => {
|
// videoElements.forEach((video) => {
|
||||||
video.remove(); // 移除 <video> 元素
|
// video.remove(); // 移除 <video> 元素
|
||||||
});
|
// });
|
||||||
|
// }
|
||||||
|
// videoTracks[index].play(this.liveContent);
|
||||||
|
|
||||||
|
//将音频track和视频track合流
|
||||||
|
if (this.$refs.player.srcObject) {
|
||||||
|
// 如果已有媒体流,添加新轨道
|
||||||
|
const existingStream = this.$refs.player.srcObject;
|
||||||
|
existingStream.addTrack(videoTracks[index]._track.mediaTrack);
|
||||||
|
} else {
|
||||||
|
// 如果没有媒体流,创建新的并添加轨道
|
||||||
|
const newStream = new MediaStream();
|
||||||
|
newStream.addTrack(videoTracks[index]._track.mediaTrack);
|
||||||
|
this.$refs.player.srcObject = newStream;
|
||||||
}
|
}
|
||||||
videoTracks[index].play(this.liveContent);
|
|
||||||
|
|
||||||
// 使用 setTimeout 确保视频元素完全创建后再设置控件
|
// 使用 setTimeout 确保视频元素完全创建后再设置控件
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const videos = document.querySelectorAll(
|
const videos = this.$refs.player;
|
||||||
"video.qnrtc-video-player.qnrtc-stream-player"
|
videos.controls = true;
|
||||||
);
|
|
||||||
// 遍历这些元素并添加 controls 属性
|
|
||||||
for (let i = 0; i < videos.length; i++) {
|
|
||||||
videos[i].controls = true;
|
|
||||||
// 确保控件可见
|
// 确保控件可见
|
||||||
videos[i].style.pointerEvents = "auto";
|
videos.style.pointerEvents = "auto";
|
||||||
//关闭画中画
|
//关闭画中画
|
||||||
videos[i].disablePictureInPicture = true;
|
videos.disablePictureInPicture = true;
|
||||||
// 打破视频宽高比,全部填充
|
// 打破视频宽高比,全部填充
|
||||||
videos[i].style.objectFit = "contain";
|
videos.style.objectFit = "contain";
|
||||||
// 关闭右键菜单
|
// 关闭右键菜单
|
||||||
videos[i].addEventListener("contextmenu", function (e) {
|
videos.addEventListener("contextmenu", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
// const videos = document.querySelectorAll(
|
||||||
|
// "video.qnrtc-video-player.qnrtc-stream-player"
|
||||||
|
// );
|
||||||
|
// 遍历这些元素并添加 controls 属性
|
||||||
|
// for (let i = 0; i < videos.length; i++) {
|
||||||
|
// videos[i].controls = true;
|
||||||
|
// // 确保控件可见
|
||||||
|
// videos[i].style.pointerEvents = "auto";
|
||||||
|
// //关闭画中画
|
||||||
|
// videos[i].disablePictureInPicture = true;
|
||||||
|
// // 打破视频宽高比,全部填充
|
||||||
|
// videos[i].style.objectFit = "contain";
|
||||||
|
// // 关闭右键菜单
|
||||||
|
// videos[i].addEventListener("contextmenu", function (e) {
|
||||||
|
// e.preventDefault();
|
||||||
|
// });
|
||||||
//添加水印
|
//添加水印
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.isStop = false;
|
this.isStop = false;
|
||||||
this.isVisible = true;
|
this.isVisible = true;
|
||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
// }
|
||||||
}, 100);
|
}, 100);
|
||||||
} else if (videoTracks[index].tag === "video") {
|
} else if (videoTracks[index].tag === "video") {
|
||||||
const teacherCameraElement = this.$refs.teacherCamera;
|
const teacherCameraElement = this.$refs.teacherCamera;
|
||||||
@ -859,7 +834,7 @@ export default {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 35vh;
|
height: 35vh;
|
||||||
background-color: gray;
|
background-color: black;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user