|
|
@@ -81,14 +81,13 @@
|
|
|
</div>
|
|
|
<div style="border-radius: 5px; overflow: hidden;" v-else-if="liveType == 1">
|
|
|
<video
|
|
|
- controls
|
|
|
+ id="live-tcplayer-container"
|
|
|
ref="livingPlayer"
|
|
|
- autoplay
|
|
|
- width="100%"
|
|
|
- @click.prevent
|
|
|
- @contextmenu.prevent
|
|
|
- class="custom-video"
|
|
|
- style="display: block; background: #000; height: 45vh;"
|
|
|
+ preload="auto"
|
|
|
+ playsinline
|
|
|
+ webkit-playsinline
|
|
|
+ class="custom-video tcplayer-live"
|
|
|
+ style="display: block; background: #000; height: 45vh; width: 100%;"
|
|
|
></video>
|
|
|
<!-- 时间显示(可选) -->
|
|
|
<div ref="liveElapsedTime" class="time-display">
|
|
|
@@ -323,6 +322,8 @@ export default {
|
|
|
},
|
|
|
livingUrl:"",
|
|
|
videoUrl: "",
|
|
|
+ tcPlayer: null,
|
|
|
+ tcPlayerSdkReady: false,
|
|
|
status: 0,
|
|
|
loadMsgMaxPage: 2,
|
|
|
liveVideo: {},
|
|
|
@@ -473,6 +474,7 @@ export default {
|
|
|
// 使用 deactivated 和 activated 钩子替代 beforeDestroy 和 destroyed
|
|
|
deactivated() {
|
|
|
this.saveChatScrollPosition();
|
|
|
+ this.destroyTcPlayer();
|
|
|
},
|
|
|
|
|
|
activated() {
|
|
|
@@ -480,11 +482,15 @@ export default {
|
|
|
this.restoreChatScrollPosition();
|
|
|
});
|
|
|
this.$nextTick(() => {
|
|
|
- const video = this.$refs.videoPlayer;
|
|
|
- if (video != null) {
|
|
|
- this.initVideoPlayer(this.liveInfo.startTime)
|
|
|
+ if (this.liveType === 1 && this.livingUrl) {
|
|
|
+ this.initPlayer();
|
|
|
+ } else {
|
|
|
+ const video = this.$refs.videoPlayer;
|
|
|
+ if (video != null) {
|
|
|
+ this.initVideoPlayer(this.liveInfo.startTime);
|
|
|
+ }
|
|
|
}
|
|
|
- })
|
|
|
+ });
|
|
|
},
|
|
|
methods: {
|
|
|
deleteMsg(m){
|
|
|
@@ -745,8 +751,9 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
if (res.data.liveType == 1) {
|
|
|
+ this.liveType = 1
|
|
|
this.livingUrl = res.data.flvHlsUrl
|
|
|
- this.livingUrl = this.livingUrl.replace("flv","m3u8")
|
|
|
+ // this.livingUrl = this.livingUrl.replace("flv","m3u8")
|
|
|
this.$nextTick(() => {
|
|
|
this.initPlayer()
|
|
|
})
|
|
|
@@ -792,32 +799,85 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
+ loadTcPlayerSdk() {
|
|
|
+ if (this.tcPlayerSdkReady && window.TCPlayer) {
|
|
|
+ return Promise.resolve();
|
|
|
+ }
|
|
|
+ if (this._tcPlayerSdkPromise) {
|
|
|
+ return this._tcPlayerSdkPromise;
|
|
|
+ }
|
|
|
+ const loadScript = (src) => new Promise((resolve, reject) => {
|
|
|
+ if (document.querySelector(`script[src="${src}"]`)) {
|
|
|
+ resolve();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const script = document.createElement('script');
|
|
|
+ script.src = src;
|
|
|
+ script.onload = () => resolve();
|
|
|
+ script.onerror = () => reject(new Error('Failed to load ' + src));
|
|
|
+ document.head.appendChild(script);
|
|
|
+ });
|
|
|
+ const loadCss = (href) => {
|
|
|
+ if (document.querySelector(`link[href="${href}"]`)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const link = document.createElement('link');
|
|
|
+ link.rel = 'stylesheet';
|
|
|
+ link.href = href;
|
|
|
+ document.head.appendChild(link);
|
|
|
+ };
|
|
|
+ this._tcPlayerSdkPromise = Promise.resolve()
|
|
|
+ .then(() => {
|
|
|
+ loadCss('https://web.sdk.qcloud.com/player/tcplayer/release/v4.9.1/tcplayer.min.css');
|
|
|
+ return loadScript('https://video.sdk.qcloudecdn.com/web/TXLivePlayer-1.3.2.min.js');
|
|
|
+ })
|
|
|
+ .then(() => loadScript('https://web.sdk.qcloud.com/player/tcplayer/release/v4.9.1/tcplayer.v4.9.1.min.js'))
|
|
|
+ .then(() => {
|
|
|
+ this.tcPlayerSdkReady = true;
|
|
|
+ });
|
|
|
+ return this._tcPlayerSdkPromise;
|
|
|
+ },
|
|
|
+ destroyTcPlayer() {
|
|
|
+ if (this.tcPlayer) {
|
|
|
+ try {
|
|
|
+ this.tcPlayer.dispose();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('销毁 TCPlayer 失败:', e);
|
|
|
+ }
|
|
|
+ this.tcPlayer = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
initPlayer(){
|
|
|
- var isUrl = this.livingUrl === null || this.livingUrl.trim() === ''
|
|
|
+ const isUrl = this.livingUrl === null || this.livingUrl.trim() === '';
|
|
|
if (isUrl) {
|
|
|
- console.error('直播地址为空,无法初始化播放器')
|
|
|
- return
|
|
|
+ console.error('直播地址为空,无法初始化播放器');
|
|
|
+ return;
|
|
|
}
|
|
|
- if (Hls.isSupported() && !isUrl) {
|
|
|
- const videoElement = this.$refs.livingPlayer
|
|
|
- if (!videoElement) {
|
|
|
- console.error('找不到 video 元素')
|
|
|
- return
|
|
|
- }
|
|
|
- this.hls = new Hls();
|
|
|
- this.hls.attachMedia(videoElement);
|
|
|
- this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
|
|
- this.hls.loadSource(this.livingUrl);
|
|
|
- this.hls.on(Hls.Events.STREAM_LOADED, (event, data) => {
|
|
|
- videoElement.play();
|
|
|
+ this.loadTcPlayerSdk().then(() => {
|
|
|
+ this.destroyTcPlayer();
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (!this.$refs.livingPlayer || !window.TCPlayer) {
|
|
|
+ console.error('找不到 video 元素或 TCPlayer 未加载');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.tcPlayer = window.TCPlayer('live-tcplayer-container', {
|
|
|
+ sources: [this.livingUrl],
|
|
|
+ autoplay: true,
|
|
|
+ width: '100%',
|
|
|
+ height: '45vh',
|
|
|
+ live: true,
|
|
|
+ controls: true,
|
|
|
+ playsinline: true,
|
|
|
+ 'webkit-playsinline': true,
|
|
|
+ x5_player: true,
|
|
|
+ x5_type: 'h5-page',
|
|
|
+ x5_fullscreen: false
|
|
|
});
|
|
|
});
|
|
|
- this.hls.on(Hls.Events.ERROR, (event, data) => {
|
|
|
- console.error('HLS 错误:', data);
|
|
|
- });
|
|
|
- } else {
|
|
|
- console.error('浏览器不支持 HLS')
|
|
|
- }
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('TCPlayer SDK 加载失败:', err);
|
|
|
+ this.$message.error('直播播放器加载失败,请刷新页面重试');
|
|
|
+ });
|
|
|
},
|
|
|
handleClick(tab) {
|
|
|
const tabName = tab.name;
|
|
|
@@ -1358,8 +1418,9 @@ export default {
|
|
|
},
|
|
|
},
|
|
|
destroyed() {
|
|
|
+ this.destroyTcPlayer();
|
|
|
this.hls?.destroy();
|
|
|
- clearInterval(this.processInterval)
|
|
|
+ clearInterval(this.processInterval);
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
@@ -1466,4 +1527,10 @@ export default {
|
|
|
border: none !important;
|
|
|
box-shadow: none !important;
|
|
|
}
|
|
|
+ .tcplayer-live {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ ::v-deep .tcplayer {
|
|
|
+ margin: 0 auto;
|
|
|
+ }
|
|
|
</style>
|