重构播放器分享功能,为各处播放器增加播放器切换能力

This commit is contained in:
lin 2026-05-25 22:05:15 +08:00
parent a22ba288fc
commit fac2195ace
19 changed files with 280 additions and 181 deletions

View File

@ -95,5 +95,4 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
}
}
}
}

View File

@ -139,7 +139,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
ssrc = ssrcFactory.getPlaySsrc(mediaServer);
}
String streamId = String.format("%08x", Long.parseLong(ssrc)).toLowerCase();
String streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
String streamReplace = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId());
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
@ -309,7 +309,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
// 收流超时
// 关闭收流端口
String closeStreamId = rtpServerParam.getMediaServer().isRtpEnable()
? String.format("%08x", rtpServerParam.getSsrc()) : rtpServerParam.getStreamId();
? String.format("%08x", rtpServerParam.getSsrc()).toUpperCase() : rtpServerParam.getStreamId();
mediaServerService.closeRTPServer(rtpServerParam.getMediaServer(), rtpServerParam.getApp(), closeStreamId);
subscribe.removeSubscribe(rtpHook);
callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
@ -324,8 +324,15 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
int rtpServerPort;
if (rtpServerParam.getMediaServer().isRtpEnable()) {
String zlmStreamId = String.format("%08x", rtpServerParam.getSsrc());
Long checkSsrc = rtpServerParam.isSsrcCheck() ? rtpServerParam.getSsrc() : 0L;
String zlmStreamId;
long checkSsrc;
if (rtpServerParam.getSsrc() != null) {
zlmStreamId = String.format("%08x", rtpServerParam.getSsrc()).toUpperCase();
checkSsrc = rtpServerParam.isSsrcCheck() ? rtpServerParam.getSsrc() : 0L;
}else {
zlmStreamId = rtpServerParam.getStreamId();
checkSsrc = 0L;
}
rtpServerPort = mediaServerService.createRTPServer(rtpServerParam.getMediaServer(), rtpServerParam.getApp(), zlmStreamId, checkSsrc, rtpServerParam.getPort(), rtpServerParam.isOnlyAuto(),
rtpServerParam.isDisableAudio(), rtpServerParam.isReUsePort(), rtpServerParam.getTcpMode());
} else {

View File

@ -7,7 +7,7 @@ import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
const whiteList = ['/login', '/play/share'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar

View File

@ -288,15 +288,10 @@ export const constantRoutes = [
]
},
{
path: '/play/wasm/:url',
name: 'wasmPlayer',
path: '/play/share',
name: 'sharePlayer',
hidden: true,
component: () => import('@/views/common/jessibuca.vue')
},
{
path: '/play/rtc/:url',
name: 'rtcPlayer',
component: () => import('@/views/common/rtcPlayer.vue')
component: () => import('@/views/common/share.vue')
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }

View File

@ -164,7 +164,6 @@
<div v-else-if="playbackStreamInfo">
<h265web
ref="playbackPlayer"
:video-url="playbackVideoUrl"
:height="'400px'"
:show-button="false"
:has-audio="true"
@ -315,6 +314,11 @@ export default {
this.playbackVideoUrl = data['ws_flv']
}
this.playbackLoading = false
this.$nextTick(() => {
if (this.$refs.playbackPlayer) {
this.$refs.playbackPlayer.play(this.playbackVideoUrl)
}
})
}).catch(err => {
this.playbackLoading = false
this.playbackError = (err && err.msg) ? err.msg : '回放请求失败,请检查通道是否有该时段录像'

View File

@ -60,7 +60,6 @@
</div>
<h265web
ref="recordVideoPlayer"
:video-url="videoUrl"
:height="'calc(100vh - 250px)'"
:show-button="false"
:has-audio="true"
@ -465,6 +464,11 @@ export default {
this.streamInfo = data
this.videoUrl = this.getUrlByStreamInfo()
this.hasAudio = this.streamInfo.tracks && this.streamInfo.tracks.length > 1
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
})
}
},

View File

@ -1,19 +1,28 @@
<template>
<div id="cloudRecordPlayer" style="height: 100%">
<div class="cloud-record-playBox" :style="playBoxStyle">
<h265web v-if="playerType === 'H265web'" ref="recordVideoPlayer" :video-url="videoUrl" :height="'calc(100% - 250px)'" :show-button="false" @playTimeChange="showPlayTimeChange" @playStatusChange="playingChange"/>
<jessibucaPlayer
v-if="playerType === 'Jessibuca'"
ref="recordVideoPlayer"
:height="'calc(100% - 250px)'"
:show-button="false"
:video-url="videoUrl"
@playTimeChange="showPlayTimeChange"
@playStatusChange="playingChange"
fluent
autoplay
live
/>
<rtcPlayer
v-if="playerType === 'WebRTC'"
ref="recordVideoPlayer"
:has-audio="true"
:show-controls="false"
style="height: calc(100% - 250px)"
autoplay
@playTimeChange="showPlayTimeChange"
@playStatusChange="playingChange"
/>
<h265web v-if="playerType === 'H265web'" ref="recordVideoPlayer" :height="'calc(100% - 250px)'" :show-button="false" @playTimeChange="showPlayTimeChange" @playStatusChange="playingChange"/>
</div>
<div class="cloud-record-player-option-box">
<div class="cloud-record-show-time">
@ -70,10 +79,11 @@
<div class="cloud-record-record-play-control-item record-play-control-player">
<el-dropdown @command="changePlayerType" :popper-append-to-body='false' >
<a target="_blank" class="cloud-record-record-play-control-item record-play-control-speed" title="选择播放器">{{ playerType }}</a>
<a target="_blank" class="cloud-record-record-play-control-item record-play-control-speed" title="选择播放器">{{ playerLabel }}</a>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="H265web" >H265web</el-dropdown-item>
<el-dropdown-item command="Jessibuca" >Jessibuca</el-dropdown-item>
<el-dropdown-item command="WebRTC" >WebRTC</el-dropdown-item>
<el-dropdown-item command="H265web" >H265web</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
@ -88,18 +98,18 @@
<script>
import h265web from '../common/h265web.vue'
import jessibucaPlayer from '@/views/common/jessibuca.vue'
import rtcPlayer from '../common/rtcPlayer.vue'
import moment from 'moment'
import momentDurationFormatSetup from 'moment-duration-format'
import screenfull from 'screenfull'
import jessibucaPlayer from '@/views/common/jessibuca.vue'
momentDurationFormatSetup(moment)
export default {
name: 'CloudRecordPlayer',
components: {
jessibucaPlayer,
h265web
jessibucaPlayer, rtcPlayer, h265web
},
props: ['showListCallback', 'showNextCallback', 'showLastCallback', 'lastDiable', 'nextDiable'],
data() {
@ -119,6 +129,11 @@ export default {
playing: false,
initTime: null,
playerType: 'Jessibuca',
playerUrls: {
Jessibuca: ['ws_flv', 'wss_flv'],
WebRTC: ['rtc', 'rtcs'],
H265web: ['ws_flv', 'wss_flv']
},
playSpeedRange: [1, 2, 4, 6, 8, 16, 20]
}
},
@ -157,6 +172,10 @@ export default {
}else {
return ''
}
},
playerLabel() {
const labels = { Jessibuca: 'Jessibuca', WebRTC: 'WebRTC', H265web: 'H265Web' }
return labels[this.playerType] || 'Jessibuca'
}
},
created() {
@ -168,9 +187,6 @@ export default {
this.$destroy('recordVideoPlayer')
},
methods: {
changePlayer(command) {
this.playerType = command
},
timeProcessMouseup(event) {
this.isMousedown = false
},
@ -228,21 +244,15 @@ export default {
if (this.playerType === playerType) {
return
}
let streamInfo = this.streamInfo
let videoUrl = this.videoUrl
this.$refs.recordVideoPlayer.destroy()
this.seekRecord(0, () => {
this.$nextTick(() => {
setTimeout(() => {
this.playerType = playerType
this.playerTime = 0
this.streamInfo = streamInfo
this.videoUrl = videoUrl
}, 1000)
if (this.streamInfo) {
this.videoUrl = this.getUrlByStreamInfo()
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
})
}
},
seekBackward() {
// 退
@ -290,15 +300,31 @@ export default {
this.isFullScreen = true
},
setStreamInfo(streamInfo, timeLen, startTime) {
const keys = this.playerUrls[this.playerType]
if (location.protocol === 'https:') {
this.videoUrl = streamInfo['wss_flv']
this.videoUrl = streamInfo[keys[1]]
} else {
this.videoUrl = streamInfo['ws_flv']
this.videoUrl = streamInfo[keys[0]]
}
console.log(location.protocol)
this.streamInfo = streamInfo
this.timeLen = timeLen
this.startTime = startTime
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
},
getUrlByStreamInfo() {
if (!this.streamInfo) return ''
const keys = this.playerUrls[this.playerType]
if (location.protocol === 'https:') {
this.videoUrl = this.streamInfo[keys[1]]
} else {
this.videoUrl = this.streamInfo[keys[0]]
}
return this.videoUrl
},
seekRecord(playSeekValue, callback) {
this.$store.dispatch('cloudRecord/seek', {

View File

@ -23,7 +23,6 @@
v-if="activePlayer === 'jessibuca'"
ref="jessibuca"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
@ -37,7 +36,6 @@
v-if="activePlayer === 'webRTC'"
ref="webRTC"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
@ -51,7 +49,6 @@
<h265web
v-if="activePlayer === 'h265web'"
ref="h265web"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
@ -67,7 +64,6 @@
v-if="Object.keys(this.player).length == 1 && this.player.jessibuca"
ref="jessibuca"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
@ -77,9 +73,8 @@
/>
<rtc-player
v-if="Object.keys(this.player).length == 1 && this.player.webRTC"
ref="jessibuca"
ref="rtcPlayer"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
@ -90,9 +85,8 @@
/>
<h265web
v-if="Object.keys(this.player).length == 1 && this.player.h265web"
ref="jessibuca"
ref="h265web"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
@ -430,9 +424,12 @@ export default {
},
computed: {
getPlayerShared: function() {
const typeMap = { jessibuca: 0, webRTC: 1, h265web: 2 }
const type = typeMap[this.activePlayer] || 0
const baseUrl = window.location.origin + '/#/play/share?type=' + type + '&url=' + encodeURIComponent(this.videoUrl)
return {
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
sharedIframe: '' + window.location.origin + '<iframe src="/public#/play/wasm/"></iframe>' + encodeURIComponent(this.videoUrl) + '',
sharedUrl: baseUrl,
sharedIframe: '<iframe src="' + baseUrl + '"></iframe>',
sharedRtmp: this.videoUrl
}
}

View File

@ -7,21 +7,21 @@
v-if="Object.keys(this.player).length > 1">
<el-tab-pane label="Jessibuca" name="jessibuca">
<jessibucaPlayer v-if="activePlayer === 'jessibuca'" ref="jessibuca" :visible.sync="showVideoDialog"
:videoUrl="videoUrl" :error="videoError" :message="videoError"
:error="videoError" :message="videoError"
:hasAudio="hasAudio" fluent autoplay live></jessibucaPlayer>
</el-tab-pane>
<el-tab-pane label="WebRTC" name="webRTC">
<rtc-player v-if="activePlayer === 'webRTC'" ref="webRTC" :visible.sync="showVideoDialog"
:videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px"
:error="videoError" :message="videoError" height="100px"
:hasAudio="hasAudio" fluent autoplay live></rtc-player>
</el-tab-pane>
<el-tab-pane label="h265web">h265web敬请期待</el-tab-pane>
</el-tabs>
<jessibucaPlayer v-if="Object.keys(this.player).length == 1 && this.player.jessibuca" ref="jessibuca"
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
:visible.sync="showVideoDialog" :error="videoError" :message="videoError"
:hasAudio="hasAudio" fluent autoplay live></jessibucaPlayer>
<rtc-player v-if="Object.keys(this.player).length == 1 && this.player.webRTC" ref="jessibuca"
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
:visible.sync="showVideoDialog" :error="videoError" :message="videoError"
height="100px" :hasAudio="hasAudio" fluent autoplay live></rtc-player>
</div>
@ -266,9 +266,12 @@ export default {
},
computed: {
getPlayerShared: function () {
const typeMap = { jessibuca: 0, webRTC: 1, h265web: 2 }
const type = typeMap[this.activePlayer] || 0
const baseUrl = window.location.origin + '/#/play/share?type=' + type + '&url=' + encodeURIComponent(this.videoUrl)
return {
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>',
sharedUrl: baseUrl,
sharedIframe: '<iframe src="' + baseUrl + '"></iframe>',
sharedRtmp: this.videoUrl
};
}
@ -359,6 +362,13 @@ export default {
this.activePlayer = tab.name;
this.videoUrl = this.getUrlByStreamInfo()
console.log(this.videoUrl)
if (this.$refs[this.activePlayer]) {
this.$refs[this.activePlayer].play(this.videoUrl)
} else {
this.$nextTick(() => {
this.$refs[this.activePlayer].play(this.videoUrl)
})
}
},
openDialog: function (tab, deviceId, channelId, param) {
if (this.showVideoDialog) {

View File

@ -64,32 +64,14 @@ export default {
}
},
watch: {
videoUrl(newData, oldData) {
this.play(newData)
},
playing(newData, oldData) {
this.$emit('playStatusChange', newData)
},
immediate: true
},
mounted() {
const paramUrl = decodeURIComponent(this.$route.params.url)
window.onresize = () => {
this.updatePlayerDomSize()
}
this.btnDom = document.getElementById('buttonsBox')
console.log('初始化时的地址为: ' + paramUrl)
if (paramUrl) {
this.play(this.videoUrl)
}
},
mounted() {},
destroyed() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].destroy()
}
this.playing = false
this.loaded = false
this.playerLoading = false
this.destroy()
},
methods: {
updatePlayerDomSize() {
@ -244,6 +226,9 @@ export default {
this.playing = false
this.err = ''
},
stop: function() {
this.destroy()
},
fullscreenSwich: function() {
const isFull = this.isFullscreen()
if (isFull) {

View File

@ -50,38 +50,14 @@ export default {
playerTime: 0,
rotate: 0,
vod: true, //
forceNoOffscreen: false
forceNoOffscreen: false,
localVideoUrl: this.videoUrl
}
},
created() {
if (this.$route.params.url) {
const paramUrl = decodeURIComponent(this.$route.params.url)
console.log(paramUrl)
if (!this.videoUrl) {
this.videoUrl = paramUrl
}
}
this.btnDom = document.getElementById('buttonsBox')
},
mounted() {
if (this.videoUrl) {
this.$nextTick(() => {
this.play(this.videoUrl)
})
}
},
watch: {
videoUrl: {
handler(newVal) {
if (newVal) {
this.$nextTick(() => {
this.play(newVal)
})
}
},
immediate: false
}
},
mounted() {},
destroyed() {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].videoPTS = 0
@ -223,7 +199,10 @@ export default {
console.warn('Jessibuca -> invalid url, skip play')
return
}
this.videoUrl = url
if (this.playing) {
this.stop()
}
this.localVideoUrl = url
console.log('Jessibuca -> url: ', url)
if (!jessibucaPlayer[this._uid]) {
this.create()

View File

@ -12,7 +12,7 @@ export default {
name: 'RtcPlayer',
props: {
videoUrl: { type: String, default: '' },
error: { type: String, default: '' },
error: { default: '' },
hasaudio: { type: Boolean, default: false },
showControls: { type: Boolean, default: true }
},
@ -21,28 +21,16 @@ export default {
timer: null
}
},
watch: {
videoUrl(newData, oldData) {
this.pause()
this.play(newData)
},
immediate: true
},
mounted() {
const paramUrl = decodeURIComponent(this.$route.params.url)
this.$nextTick(() => {
if (typeof (this.videoUrl) === 'undefined') {
this.videoUrl = paramUrl
}
console.log('初始化时的地址为: ' + this.videoUrl)
this.play(this.videoUrl)
})
},
mounted() {},
destroyed() {
clearTimeout(this.timer)
},
methods: {
play: function(url) {
if (webrtcPlayer != null) {
this.pause()
}
webrtcPlayer = new ZLMRTCClient.Endpoint({
element: document.getElementById('webRtcPlayerBox'), // video
debug: true, //
@ -87,6 +75,9 @@ export default {
webrtcPlayer = null
}
},
stop: function() {
this.pause()
},
eventcallbacK: function(type, message) {
console.log('player 事件回调')
console.log(type)

View File

@ -0,0 +1,54 @@
<template>
<div style="width: 100vw; height: 100vh; background-color: #000; overflow: hidden;">
<jessibucaPlayer
v-if="playerType === 0"
ref="player"
:show-button="true"
style="width: 100%; height: 100%"
/>
<rtc-player
v-if="playerType === 1"
ref="player"
:show-controls="true"
style="width: 100%; height: 100%"
/>
<h265web
v-if="playerType === 2"
ref="player"
:show-button="true"
style="width: 100%; height: 100%"
/>
</div>
</template>
<script>
import jessibucaPlayer from './jessibuca.vue'
import rtcPlayer from './rtcPlayer.vue'
import h265web from './h265web.vue'
export default {
name: 'SharePlayer',
components: { jessibucaPlayer, rtcPlayer, h265web },
data() {
return {
playerType: 0
}
},
created() {
const type = parseInt(this.$route.query.type)
if (!isNaN(type) && type >= 0 && type <= 2) {
this.playerType = type
}
},
mounted() {
const url = this.$route.query.url
if (url) {
this.$nextTick(() => {
if (this.$refs.player) {
this.$refs.player.play(decodeURIComponent(url))
}
})
}
}
}
</script>

View File

@ -71,7 +71,6 @@
<rtcPlayer
v-if="activePlayer === 'webRTC'"
ref="recordVideoPlayer"
:video-url="videoUrl"
:has-audio="true"
:show-controls="false"
style="height: calc(100vh - 220px)"
@ -82,7 +81,6 @@
<h265web
v-if="activePlayer === 'h265web'"
ref="recordVideoPlayer"
:video-url="videoUrl"
:height="'calc(100vh - 220px)'"
:show-button="false"
:has-audio="true"

View File

@ -41,7 +41,6 @@
v-if="activePlayer === 'webRTC'"
ref="webRTC"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
@ -55,7 +54,6 @@
<h265web
v-if="activePlayer === 'h265web'"
ref="h265web"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
@ -397,9 +395,12 @@ export default {
},
computed: {
getPlayerShared: function() {
const typeMap = { jessibuca: 0, webRTC: 1, h265web: 2 }
const type = typeMap[this.activePlayer] || 0
const baseUrl = window.location.origin + '/#/play/share?type=' + type + '&url=' + encodeURIComponent(this.videoUrl)
return {
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>',
sharedUrl: baseUrl,
sharedIframe: '<iframe src="' + baseUrl + '"></iframe>',
sharedRtmp: this.videoUrl
}
}

View File

@ -52,9 +52,29 @@
<div class="el-icon-loading" />
<div style="width: 100%; line-height: 2rem">正在加载</div>
</div>
<h265web
<jessibucaPlayer
v-if="activePlayer === 'jessibuca'"
ref="recordVideoPlayer"
:has-audio="true"
:height="'calc(100vh - 250px)'"
:show-button="false"
autoplay
@playStatusChange="playingChange"
@playTimeChange="showPlayTimeChange"
/>
<rtcPlayer
v-if="activePlayer === 'webRTC'"
ref="recordVideoPlayer"
:has-audio="true"
:show-controls="false"
style="height: calc(100vh - 250px)"
autoplay
@playStatusChange="playingChange"
@playTimeChange="showPlayTimeChange"
/>
<h265web
v-if="activePlayer === 'h265web'"
ref="recordVideoPlayer"
:video-url="videoUrl"
:height="'calc(100vh - 250px)'"
:show-button="false"
:has-audio="true"
@ -176,6 +196,18 @@
</div>
<div style="text-align: right;">
<div class="record-play-control" style="background-color: transparent; box-shadow: 0 0 10px transparent">
<el-dropdown @command="changePlayer">
<a
target="_blank"
class="record-play-control-item record-play-control-speed"
title="切换播放器"
>{{ playerLabel }}</a>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="jessibuca">Jessibuca</el-dropdown-item>
<el-dropdown-item command="webRTC">WebRTC</el-dropdown-item>
<el-dropdown-item command="h265web">H265Web</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<a
v-if="!isFullScreen"
target="_blank"
@ -203,6 +235,8 @@
<script>
import h265web from '../../common/h265web.vue'
import jessibucaPlayer from '../../common/jessibuca.vue'
import rtcPlayer from '../../common/rtcPlayer.vue'
import VideoTimeline from '../../common/VideoTimeLine/index.vue'
import recordDownload from '../../dialog/recordDownload.vue'
import ChooseTimeRange from '../../dialog/chooseTimeRange.vue'
@ -212,7 +246,7 @@ import screenfull from 'screenfull'
export default {
name: 'DeviceRecord',
components: {
h265web, VideoTimeline, recordDownload, ChooseTimeRange
h265web, jessibucaPlayer, rtcPlayer, VideoTimeline, recordDownload, ChooseTimeRange
},
data() {
return {
@ -225,6 +259,7 @@ export default {
detailFiles: [],
videoUrl: null,
streamInfo: null,
streamId: '',
loading: false,
chooseDate: null,
playTime: null,
@ -246,6 +281,12 @@ export default {
timelineControl: false,
showOtherSpeed: true,
timeSegments: [],
activePlayer: 'jessibuca',
playerUrls: {
jessibuca: ['ws_flv', 'wss_flv'],
webRTC: ['rtc', 'rtcs'],
h265web: ['ws_flv', 'wss_flv']
},
pickerOptions: {
cellClassName: (date) => {
//
@ -260,6 +301,10 @@ export default {
}
},
computed: {
playerLabel() {
const labels = { jessibuca: 'Jessibuca', webRTC: 'WebRTC', h265web: 'H265Web' }
return labels[this.activePlayer] || 'Jessibuca'
},
boxStyle() {
if (this.showSidebar) {
return {
@ -293,6 +338,18 @@ export default {
window.removeEventListener('beforeunload', this.stopPlayRecord)
},
methods: {
changePlayer(player) {
if (this.activePlayer === player) return
this.activePlayer = player
if (this.streamInfo) {
this.videoUrl = this.getUrlByStreamInfo()
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
}
},
sidebarControl() {
this.showSidebar = !this.showSidebar
},
@ -438,16 +495,23 @@ export default {
})
.then((data) => {
this.streamInfo = data
this.streamId = data.stream
this.videoUrl = this.getUrlByStreamInfo()
this.hasAudio = this.streamInfo.tracks && this.streamInfo.tracks.length > 1
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
})
}
},
getUrlByStreamInfo() {
const keys = this.playerUrls[this.activePlayer]
if (location.protocol === 'https:') {
this.videoUrl = this.streamInfo['wss_flv']
this.videoUrl = this.streamInfo[keys[1]]
} else {
this.videoUrl = this.streamInfo['ws_flv']
this.videoUrl = this.streamInfo[keys[0]]
}
return this.videoUrl
},

View File

@ -20,10 +20,10 @@
>
<el-tab-pane label="Jessibuca" name="jessibuca">
<jessibucaPlayer
style="min-height: 22.5vw"
v-if="activePlayer === 'jessibuca'"
ref="jessibuca"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
@ -37,7 +37,6 @@
v-if="activePlayer === 'webRTC'"
ref="webRTC"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
@ -51,7 +50,6 @@
<h265web
v-if="activePlayer === 'h265web'"
ref="h265web"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
@ -63,44 +61,6 @@
</el-tab-pane>
</el-tabs>
<jessibucaPlayer
v-if="Object.keys(this.player).length == 1 && this.player.jessibuca"
ref="jessibuca"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
:has-audio="hasAudio"
fluent
autoplay
live
/>
<rtc-player
v-if="Object.keys(this.player).length == 1 && this.player.webRTC"
ref="jessibuca"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
:has-audio="hasAudio"
fluent
autoplay
live
/>
<h265web
v-if="Object.keys(this.player).length == 1 && this.player.h265web"
ref="jessibuca"
:visible.sync="showVideoDialog"
:video-url="videoUrl"
:error="videoError"
:message="videoError"
height="100px"
:has-audio="hasAudio"
fluent
autoplay
live
/>
</div>
<div id="shared" style="text-align: right; margin-top: 1rem;">
@ -354,6 +314,7 @@
<script>
import rtcPlayer from '../../common/rtcPlayer.vue'
import elDragDialog from '@/directive/el-drag-dialog'
import crypto from 'crypto'
import jessibucaPlayer from '../../common/jessibuca.vue'
import mediaInfo from '../../common/mediaInfo.vue'
@ -361,6 +322,7 @@ import H265web from '../../common/h265web.vue'
export default {
name: 'DevicePlayer',
directives: { elDragDialog },
components: {
mediaInfo, H265web,
jessibucaPlayer, rtcPlayer
@ -414,9 +376,12 @@ export default {
},
computed: {
getPlayerShared: function() {
const typeMap = { jessibuca: 0, webRTC: 1, h265web: 2 }
const type = typeMap[this.activePlayer] || 0
const baseUrl = window.location.origin + '/#/play/share?type=' + type + '&url=' + encodeURIComponent(this.videoUrl)
return {
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
sharedIframe: '' + window.location.origin + '<iframe src="/public#/play/wasm/"></iframe>' + encodeURIComponent(this.videoUrl) + '',
sharedUrl: baseUrl,
sharedIframe: '<iframe src="' + baseUrl + '"></iframe>',
sharedRtmp: this.videoUrl
}
}
@ -440,6 +405,13 @@ export default {
changePlayer: function(tab) {
this.activePlayer = tab.name
this.videoUrl = this.getUrlByStreamInfo()
if (this.$refs[this.activePlayer]) {
this.$refs[this.activePlayer].play(this.videoUrl)
} else {
this.$nextTick(() => {
this.$refs[this.activePlayer].play(this.videoUrl)
})
}
},
openDialog: function(tab, deviceId, channelId, param) {
if (this.showVideoDialog) {

View File

@ -33,8 +33,7 @@
<div v-if="!videoUrl[i-1]" class="no-signal">{{ videoTip[i-1]?videoTip[i-1]:"无信号" }}</div>
<player
v-else
:ref="'player'[i-1]"
:video-url="videoUrl[i-1]"
:ref="'player' + i"
fluent
autoplay
:show-button="true"
@ -220,6 +219,15 @@ export default {
setTimeout(() => {
window.localStorage.setItem('videoUrl', JSON.stringify(_this.videoUrl))
}, 100)
this.$nextTick(() => {
const refName = 'player' + (idx + 1)
if (this.$refs[refName]) {
const player = this.$refs[refName] instanceof Array ? this.$refs[refName][0] : this.$refs[refName]
if (player && player.play) {
player.play(url)
}
}
})
},
checkPlayByParam() {
const query = this.$route.query

View File

@ -87,8 +87,8 @@
<el-table-column prop="stream" label="流ID" min-width="200" />
<el-table-column label="推流状态" min-width="100">
<template v-slot:default="scope">
<el-tag v-if="scope.row.pushing && $myServerId !== scope.row.serverId" size="medium" style="border-color: #ecf1af">推流中</el-tag>
<el-tag v-if="scope.row.pushing && $myServerId === scope.row.serverId" size="medium">推流中</el-tag>
<el-tag v-if="scope.row.pushing && myServerId !== scope.row.serverId" size="medium" style="border-color: #ecf1af">推流中</el-tag>
<el-tag v-if="scope.row.pushing && myServerId === scope.row.serverId" size="medium">推流中</el-tag>
<el-tag v-if="!scope.row.pushing" size="medium" type="info">已停止</el-tag>
</template>
</el-table-column>
@ -189,6 +189,11 @@ export default {
destroyed() {
clearTimeout(this.updateLooper)
},
computed: {
myServerId() {
return this.$store.getters.serverId
}
},
methods: {
initData: function() {
this.loading = true