|
|
@@ -1,22 +1,9 @@
|
|
|
<template>
|
|
|
<div class="live-player">
|
|
|
- <!-- 修改:所有录播和回放都使用同一个video元素,MP4和HLS都支持 -->
|
|
|
- <video
|
|
|
- v-if="videoParam.liveType == 2 || videoParam.liveType == 3"
|
|
|
- ref="videoPlayer"
|
|
|
- :loop="videoParam.liveType == 2"
|
|
|
- autoplay
|
|
|
- class="player"
|
|
|
- >
|
|
|
- <!-- 去掉type,让浏览器自动检测 -->
|
|
|
+ <video v-if="videoParam.liveType == 2" ref="videoPlayer" loop autoplay class="player">
|
|
|
+ <source :src="videoParam.videoUrl" type="application/x-mpegURL">
|
|
|
</video>
|
|
|
-
|
|
|
- <video
|
|
|
- v-if="videoParam.liveType == 1"
|
|
|
- ref="livePlayer"
|
|
|
- autoplay
|
|
|
- class="player"
|
|
|
- >
|
|
|
+ <video v-if="videoParam.liveType == 1" ref="livePlayer" loop autoplay class="player">
|
|
|
</video>
|
|
|
</div>
|
|
|
</template>
|
|
|
@@ -40,33 +27,23 @@ export default {
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
- videoDuration: 0,
|
|
|
- startTime: 0,
|
|
|
- hls: null,
|
|
|
- liveHls: null // 分开管理直播和录播的HLS实例
|
|
|
+ videoDuration: 0, // 视频总时长(秒)
|
|
|
+ startTime: 0, // 开播时间戳(毫秒)
|
|
|
+ hls: null, // HLS 实例
|
|
|
};
|
|
|
},
|
|
|
mounted() {
|
|
|
- this.initPlayer();
|
|
|
+
|
|
|
+ // 这里可以添加播放器初始化逻辑
|
|
|
},
|
|
|
methods: {
|
|
|
videoPlay(url) {
|
|
|
- const videoElement = this.$refs.videoPlayer;
|
|
|
- if (!videoElement) {
|
|
|
- console.error('找不到 video 元素');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 判断是否是MP4格式
|
|
|
- const isMp4 = url.toLowerCase().endsWith('.mp4') ||
|
|
|
- url.toLowerCase().includes('.mp4?');
|
|
|
-
|
|
|
- // 判断是否是HLS格式(m3u8)
|
|
|
- const isHls = url.toLowerCase().endsWith('.m3u8') ||
|
|
|
- url.toLowerCase().includes('.m3u8?');
|
|
|
-
|
|
|
- if (isHls && Hls.isSupported()) {
|
|
|
- // HLS格式使用hls.js播放
|
|
|
+ if (Hls.isSupported()) {
|
|
|
+ const videoElement = this.$refs.videoPlayer
|
|
|
+ if (!videoElement) {
|
|
|
+ console.error('找不到 video 元素')
|
|
|
+ return
|
|
|
+ }
|
|
|
this.hls = new Hls();
|
|
|
this.hls.attachMedia(videoElement);
|
|
|
this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
|
|
@@ -78,165 +55,104 @@ export default {
|
|
|
this.hls.on(Hls.Events.ERROR, (event, data) => {
|
|
|
console.error('HLS 错误:', data);
|
|
|
});
|
|
|
-
|
|
|
- // 录播的时间位置计算
|
|
|
+ // 1. 初始化开播时间
|
|
|
+ this.startTime = new Date(this.videoParam.startTime).getTime();
|
|
|
if (this.videoParam.liveType === 2) {
|
|
|
+ // 2. 监听视频元数据加载完成(获取视频时长)
|
|
|
videoElement.addEventListener('loadedmetadata', () => {
|
|
|
- this.videoDuration = videoElement.duration;
|
|
|
- this.updateVideoPosition(videoElement);
|
|
|
- });
|
|
|
- }
|
|
|
+ this.videoDuration = videoElement.duration; // 获取视频时长(秒)
|
|
|
|
|
|
- } else if (isMp4 || !isHls) {
|
|
|
- // MP4格式或非HLS格式直接使用video元素播放
|
|
|
- videoElement.src = url;
|
|
|
-
|
|
|
- // 录播的时间位置计算
|
|
|
- if (this.videoParam.liveType === 2) {
|
|
|
- videoElement.addEventListener('loadedmetadata', () => {
|
|
|
- this.videoDuration = videoElement.duration;
|
|
|
+ // 初始化视频播放位置
|
|
|
this.updateVideoPosition(videoElement);
|
|
|
+
|
|
|
});
|
|
|
}
|
|
|
-
|
|
|
- // 触发播放
|
|
|
- videoElement.load();
|
|
|
- videoElement.play().catch(e => {
|
|
|
- console.warn('自动播放失败:', e);
|
|
|
- });
|
|
|
-
|
|
|
} else {
|
|
|
- // 不支持HLS的浏览器,尝试直接播放
|
|
|
- console.warn('浏览器不支持HLS,尝试直接播放');
|
|
|
- videoElement.src = url;
|
|
|
- videoElement.load();
|
|
|
- videoElement.play().catch(e => {
|
|
|
- console.warn('播放失败:', e);
|
|
|
- });
|
|
|
+ console.error('浏览器不支持 HLS')
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
- updateVideoPosition(video) {
|
|
|
- const currentTime = new Date().getTime();
|
|
|
- this.startTime = new Date(this.videoParam.startTime).getTime();
|
|
|
- const elapsedTime = currentTime - this.startTime;
|
|
|
-
|
|
|
+ updateVideoPosition(video){
|
|
|
+ const currentTime = new Date().getTime(); // 当前时间戳(毫秒)
|
|
|
+ const elapsedTime = currentTime - this.startTime; // 已流逝时间(毫秒)
|
|
|
if (elapsedTime < 0) {
|
|
|
+ // 未开播:视频停在初始位置
|
|
|
video.currentTime = 0;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const elapsedSeconds = elapsedTime / 1000;
|
|
|
- if (this.videoDuration > 0) {
|
|
|
- video.currentTime = elapsedSeconds % this.videoDuration;
|
|
|
- }
|
|
|
+ // 已开播:计算视频循环后的位置(流逝时间 % 视频时长)
|
|
|
+ const elapsedSeconds = elapsedTime / 1000; // 转换为秒
|
|
|
+ // 视频内的播放位置(秒)
|
|
|
+ // 设置视频播放位置
|
|
|
+ video.currentTime = elapsedSeconds % this.videoDuration;
|
|
|
},
|
|
|
-
|
|
|
livePlay(url) {
|
|
|
if (Hls.isSupported()) {
|
|
|
- const videoElement = this.$refs.livePlayer;
|
|
|
+ const videoElement = this.$refs.livePlayer
|
|
|
if (!videoElement) {
|
|
|
- console.error('找不到 video 元素');
|
|
|
- return;
|
|
|
+ console.error('找不到 video 元素')
|
|
|
+ return
|
|
|
}
|
|
|
-
|
|
|
- this.liveHls = new Hls();
|
|
|
- this.liveHls.attachMedia(videoElement);
|
|
|
- this.liveHls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
|
|
- this.liveHls.loadSource(url);
|
|
|
- this.liveHls.on(Hls.Events.STREAM_LOADED, (event, data) => {
|
|
|
+ this.hls = new Hls();
|
|
|
+ this.hls.attachMedia(videoElement);
|
|
|
+ this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
|
|
+ this.hls.loadSource(url);
|
|
|
+ this.hls.on(Hls.Events.STREAM_LOADED, (event, data) => {
|
|
|
videoElement.play();
|
|
|
});
|
|
|
});
|
|
|
- this.liveHls.on(Hls.Events.ERROR, (event, data) => {
|
|
|
+ this.hls.on(Hls.Events.ERROR, (event, data) => {
|
|
|
console.error('HLS 错误:', data);
|
|
|
});
|
|
|
-
|
|
|
} else {
|
|
|
- // 浏览器原生支持HLS(如Safari)
|
|
|
- const videoElement = this.$refs.livePlayer;
|
|
|
- if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
|
|
|
- videoElement.src = url;
|
|
|
- videoElement.play().catch(e => {
|
|
|
- console.warn('自动播放失败:', e);
|
|
|
- });
|
|
|
- } else {
|
|
|
- console.error('浏览器不支持 HLS');
|
|
|
- }
|
|
|
+ console.error('浏览器不支持 HLS')
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
initPlayer() {
|
|
|
- // 清理之前的实例
|
|
|
- if (this.hls) {
|
|
|
- this.hls.destroy();
|
|
|
- this.hls = null;
|
|
|
- }
|
|
|
- if (this.liveHls) {
|
|
|
- this.liveHls.destroy();
|
|
|
- this.liveHls = null;
|
|
|
- }
|
|
|
|
|
|
if (this.videoParam.liveType === 1) {
|
|
|
// 直播
|
|
|
const isUrl = this.videoParam.livingUrl === null || this.videoParam.livingUrl.trim() === '';
|
|
|
if (isUrl) {
|
|
|
- console.error('直播地址为空,无法初始化播放器');
|
|
|
- return;
|
|
|
+ console.error('直播地址为空,无法初始化播放器')
|
|
|
+ return
|
|
|
}
|
|
|
this.$nextTick(() => {
|
|
|
this.livePlay(this.videoParam.livingUrl);
|
|
|
- });
|
|
|
+ })
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- const viUrl = this.videoParam.videoUrl === null || this.videoParam.videoUrl.trim() === '';
|
|
|
+ const viUrl = this.videoParam.videoUrl === null || this.videoParam.videoUrl.trim() === ''
|
|
|
if (viUrl) {
|
|
|
- console.error('播放地址为空,无法初始化播放器');
|
|
|
- return;
|
|
|
+ console.error('播放地址为空,无法初始化播放器')
|
|
|
+ return
|
|
|
}
|
|
|
-
|
|
|
- if (this.videoParam.liveType === 2 || this.videoParam.liveType === 3) {
|
|
|
- // 录播或直播回放
|
|
|
- this.$nextTick(() => {
|
|
|
- this.videoPlay(this.videoParam.videoUrl);
|
|
|
- });
|
|
|
- } else {
|
|
|
- console.error('直播类型错误,无法初始化播放器');
|
|
|
+ if(this.videoParam.liveType === 2){
|
|
|
+ // 录播
|
|
|
+ this.videoPlay(this.videoParam.videoUrl);
|
|
|
+ } else if(this.videoParam.liveType === 3){
|
|
|
+ // 直播回放
|
|
|
+ this.videoPlay(this.videoParam.videoUrl);
|
|
|
+ }else {
|
|
|
+ console.error('直播类型错误,无法初始化播放器')
|
|
|
}
|
|
|
+ // 创建播放器实例
|
|
|
+ const videoPlayer = this.$refs.videoPlayer;
|
|
|
+ // 添加播放器事件监听器
|
|
|
+ videoPlayer.addEventListener('play', () => {
|
|
|
+ console.log('播放器已开始播放');
|
|
|
+ });
|
|
|
+ videoPlayer.addEventListener('pause', () => {
|
|
|
+ console.log('播放器已暂停');
|
|
|
+ });
|
|
|
+ videoPlayer.addEventListener('ended', () => {
|
|
|
+ console.log('播放器已结束');
|
|
|
+ });
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
- watch: {
|
|
|
- // 监听videoParam变化,重新初始化播放器
|
|
|
- videoParam: {
|
|
|
- handler() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.initPlayer();
|
|
|
- });
|
|
|
- },
|
|
|
- deep: true
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
beforeDestroy() {
|
|
|
- // 销毁HLS实例
|
|
|
- this.hls?.destroy();
|
|
|
- this.liveHls?.destroy();
|
|
|
-
|
|
|
- // 清理video元素
|
|
|
- const videoElements = [
|
|
|
- this.$refs.videoPlayer,
|
|
|
- this.$refs.livePlayer
|
|
|
- ];
|
|
|
-
|
|
|
- videoElements.forEach(video => {
|
|
|
- if (video) {
|
|
|
- video.pause();
|
|
|
- video.src = '';
|
|
|
- video.load();
|
|
|
- }
|
|
|
- });
|
|
|
+ this.hls?.destroy()
|
|
|
+ // 销毁播放器实例
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
@@ -250,8 +166,5 @@ export default {
|
|
|
width: 100%;
|
|
|
height: auto;
|
|
|
border-radius: 8px;
|
|
|
- max-height: 300px; /* 设置最大高度,避免过大 */
|
|
|
- object-fit: contain; /* 保持比例,不拉伸 */
|
|
|
- background-color: #000; /* 黑色背景,避免视频加载时显示白色 */
|
|
|
}
|
|
|
</style>
|