You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

437 lines
17 KiB

import React, { useState, useEffect, useRef } from "react";
import { connect } from "react-redux";
import screenfull from 'screenfull';
import moment from "moment";
import request from 'superagent'
import { VideoServeApi, IotVideoServerRequest, checkAudioVideo } from '$utils'
import { ToastFactory, } from '@douyinfe/semi-ui';
import VideoHeader from './voiceHeader'
import VideoOperation from './videoOperation'
import './videoPlay.less';
const timeFormat = 'YYYY-MM-DD HH:mm:ss'
const yingshiUrl = 'https://open.ys7.com/ezopen/h5/iframe'
const yingshiCloseSoundKey = 'closeSound'
const yingshiOpenSoundKey = 'openSound'
const VideoPlay = ({
height, width, containerId = 'myPlayer',
// playUrl,
name,
global,
videoStyle,
changeData,
videoObj,
sizeWh,
slideDown, //视频下方操作是否滑动
IsSize, //是否按照16:9的比例播放
// videoObj = {
// type: 'yingshi',
// audio: false,
// serialNo: 'G75922040', // 设备序列号 必须
// channelNo: 1, //
// yingshiToken: 'at.3j6eyqbn0g5xvcut73v0rzdu1nh0gnxx-4ua03m82o9-12u1t9g-rtzndpyds', // 萤石必须
// playUrlSd: 'ezopen://open.ys7.com/G75922040/1.live', // 必须
// // playUrl: 'ws://221.230.55.27:8081/jessica/34020000001110000077/34020000001310000003',
// playUrlHd: 'ezopen://open.ys7.com/G75922040/1.hd.live',
// // replayUrl: 'ezopen://open.ys7.com/G75922040/1.rec',
// },
// videoObj = {
// type: 'cascade',
// audio: false,
// serialNo: '34020000001310000001', // 设备序列号 必须
// topSerialNo: '34020000001110000077', // 设备顶级序列号 必须
// playUrlSd: 'ws://221.230.55.27:8081/jessica/34020000001110000077/34020000001310000001', // 必须
// // playUrlHd: 'ezopen://open.ys7.com/G75922040/1.hd.live',
// // replayUrl: 'ezopen://open.ys7.com/G75922040/1.rec',
// },
//
iotVideoServer,
local, //是否本地调用视频
}) => {
const [jessibuca, setjessibuca] = useState(null)
const [isPlaying, setIsPlaying] = useState(false)
const [operationState, setoperationState] = useState()
const [voiceDisY, setVoiceDisY] = useState(0)
const [processDisX, setProcessDisX] = useState(0)
const [isAdjustProcess, setIsAdjustProcess] = useState(false)
const [histroyTime, setHistroyTime] = useState([])
const [histroyBegain, setHistroyBegain] = useState()
const [roll, setRoll] = useState()//滚动备注
const [size, setSize] = useState(sizeWh) //视频本身和父级尺寸
const [resolution, setResolution] = useState('sd') // 标清 sd 高清 hd
// const [frequency, setFrequency] = useState(true)
// 标记萤石操作中,等待ifream返回信息后清空
const [yingshiPrepare, setYingshiPrepare] = useState('')
const operationRef = useRef(null)
const processChangeTimeoutRef = useRef(null)
// 标记萤石操作中,等待ifream返回信息后清空
const yingshiPrepareRef = useRef(null)
useEffect(() => {
setRoll(false)
}, [resolution]);
useEffect(() => {
setResolution(changeData?.hdChecked ? 'hd' : 'sd')
}, [changeData?.hdChecked])
const changeSelectState = (key) => {
if (videoObj.type == 'yingshi' && yingshiPrepareRef.current) {
return
}
const nextOperationState = JSON.parse(JSON.stringify(operationRef.current))
if (key == 'histroy' && nextOperationState.histroy.select) {
// 取消历史播放
setProcessDisX(0)
setHistroyTime([])
}
for (let k in nextOperationState) {
if (k == key) {
nextOperationState[k].select = !nextOperationState[k].select
} else if (k !== 'fullScreen') {
nextOperationState[k].select = false
}
}
operationRef.current = nextOperationState
if (operationRef.current.histroy.select && histroyTime.length == 0) {
setHistroyTime([moment().subtract(72, 'hours').format(timeFormat), moment().format(timeFormat)])
}
setoperationState(nextOperationState)
}
// 实时播放左下方操作栏内容
const operation = [{
key: 'control',
click: () => {
changeSelectState('control')
}
}, {
key: 'talk',
hide: !(videoObj.type == 'yingshi'),
click: (e) => {
console.log(e);
changeSelectState('talk')
}
}, {
key: 'fullScreen',
click: () => {
if (yingshiPrepareRef.current) {
return
}
changeSelectState('fullScreen')
let player = document.getElementById('vcmp_videoplay')
console.log(player);
if (screenfull.isEnabled) {
screenfull.toggle(player);
}
}
}, {
key: 'histroy',
hide: !Boolean(videoObj.replayUrl),
click: () => {
changeSelectState('histroy')
yingshiPrepareRef.current = 'play'
setYingshiPrepare('play')
}
},]
useEffect(() => {
if (videoObj.type == 'yingshi') {
yingshiPrepareRef.current = 'play'
setYingshiPrepare('play')
} else {
createJessibuca()
}
let nextOperationState = {}
for (let p of operation) {
nextOperationState[p.key] = {
select: false
}
}
setoperationState(nextOperationState)
operationRef.current = nextOperationState
// 全屏状态监听
screenfull.on('change', () => {
if (screenfull.isFullscreen && operationRef.current && !operationRef.current['fullScreen'].select) {
changeSelectState('fullScreen')
}
if (!screenfull.isFullscreen && operationRef.current && operationRef.current['fullScreen'].select) {
changeSelectState('fullScreen')
}
});
// 萤石 ifream 信息监听
const listenYingshiMessage = async (e) => {
const { data, origin } = e
if (origin !== 'https://open.ys7.com') return
if (data.type == "handleSuccess") {
setRoll(true)
if (yingshiPrepareRef.current == 'play') {
setIsPlaying(true)
}
} else if (data.type == yingshiOpenSoundKey && data.code == 0) {
if (yingshiPrepareRef.current == yingshiOpenSoundKey) {
setVoiceDisY(30)
}
} if (data.type == yingshiCloseSoundKey && data.code == 0) {
if (yingshiPrepareRef.current == yingshiCloseSoundKey) {
setVoiceDisY(0)
}
}
yingshiPrepareRef.current = null
setYingshiPrepare(null)
}
if (videoObj.type == 'yingshi') {
window.addEventListener('message', listenYingshiMessage);
}
return () => {
window.removeEventListener('message', listenYingshiMessage);
}
}, [])
useEffect(() => {
if (histroyTime.length) {
setHistroyBegain(histroyTime[0])
document.getElementById('process_point').style.left = 0 + 'px'; // 重置进度条的位置
if (videoObj.type == 'yingshi') {
yingshiPrepareRef.current = 'play'
setYingshiPrepare('play')
}
} else {
setHistroyBegain(null)
}
}, [histroyTime])
useEffect(() => {
if (operationState && operationState.histroy.select) {
if (isAdjustProcess) {
// 调整进度条 更新播放开始时间
if (processChangeTimeoutRef.current) {
clearTimeout(processChangeTimeoutRef.current)
}
processChangeTimeoutRef.current = setTimeout(() => {
setHistroyBegain(
moment(histroyTime[0])
.add(
Math.abs(moment(histroyTime[0]).diff(moment(histroyTime[1]), 'seconds')) * (processDisX / document.getElementById('process_point').parentElement.offsetWidth),
'second'
)
.format(timeFormat)
)
if (videoObj.type == 'yingshi') {
yingshiPrepareRef.current = 'play'
setYingshiPrepare('play')
}
}, 300)
} else {
// 随播放时间变化更新进度条
document.getElementById('process_point').style.left = processDisX - 4.5 + 'px'
}
}
}, [processDisX])
const createJessibuca = async () => {
if (videoObj.type != 'yingshi') {
try {
// const inviteRes = await IotVideoServerRequest.get(VideoServeApi.invite, {
// id: '36011200002002021114',
// channel: '36011200581314002900'
// }).then(res => {
// console.log(res);
// }, err => {
// console.log(err);
// })
const inviteRes_ = await request.get(`${iotVideoServer}/api/gb28181/invite?id=${videoObj.topSerialNo}&channel=${videoObj.serialNo}`)
} catch (error) {
console.log(error.response);
}
let $container = document.getElementById(containerId);
const jessibuca = new window.Jessibuca({
container: $container,
videoBuffer: 0.2, // 缓存时长
isResize: false,
text: "",
loadingText: "加载中",
debug: true,
showBandwidth: false, // 显示网速
operateBtns: {
fullscreen: true,
screenshot: false,
play: false,
audio: false,
},
forceNoOffscreen: false,
isNotMute: false,
});
setjessibuca(jessibuca)
play({ jessibuca })
}
}
const yingshiOperation = (operation) => {
document.getElementById(containerId).contentWindow.postMessage(operation, yingshiUrl)
// setIsPlaying(operation == 'play')
}
const play = (params) => {
if (videoObj.type == 'yingshi') {
yingshiOperation('play')
} else if ((params.jessibuca || jessibuca) && videoObj.playUrlSd) {
const jes = params.jessibuca || jessibuca
jes.play(videoObj.playUrlSd);
setIsPlaying(true)
}
}
const pause = () => {
if (videoObj.type == 'yingshi') {
// yingshiOperation('stop')
} else if (jessibuca) {
jessibuca.pause();
setIsPlaying(false)
}
}
const closeSound = () => {
if (videoObj.type == 'yingshi') {
yingshiPrepareRef.current = yingshiCloseSoundKey
setYingshiPrepare(yingshiCloseSoundKey)
yingshiOperation(yingshiCloseSoundKey)
}
}
const openSound = () => {
if (videoObj.type == 'yingshi') {
yingshiPrepareRef.current = yingshiOpenSoundKey
setYingshiPrepare(yingshiOpenSoundKey)
yingshiOperation(yingshiOpenSoundKey)
}
}
useEffect(() => {
if (local) {
//弹框视频自适应
const VideoLocal = document.getElementById('video_local')
setSize({ parentWidth: VideoLocal?.clientWidth, parentHeight: '100%', width: width, height: height })
} else {
setSize(sizeWh)
}
}, [sizeWh])
useEffect(() => {
if (size?.width || size?.height) {
// if (size?.parentWidth >= size?.width && size?.parentHeight >= size?.height) {
if (size?.width && size?.height) {
if (size?.height / size?.width < 0.55 || size?.height / size?.width > 0.57) {
if (size?.width / 16 > size?.height / 9) {
setSize({ ...size, width: (size?.height / 9) * 16, })
} else {
setSize({ ...size, height: (size?.width / 16) * 9 })
}
}
} else if (size?.width) {
setSize({ ...size, height: (size?.width / 16) * 9, })
} else if (size?.height) {
setSize({ ...size, width: (size?.height / 9) * 16, })
}
// } else {
// setSize({ ...size, width: size?.parentWidth, height: size?.parentHeight })
// }
} else {
if (size && size?.width / 16 > size?.height / 9) {
setSize({ ...size, height: size?.parentHeight })
} else {
setSize({ ...size, width: size?.parentWidth, })
}
}
}, [size])
return (
<>
<div className="vcmp_videoplay" style={{ width: IsSize == 'true' ? size?.parentWidth : width || '100%', height: IsSize == 'true' ? size?.parentHeight : height || '100%', backgroundColor: 'black', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', }}>
<div id="vcmp_videoplay" style={{ position: 'relative', height: IsSize == 'true' ? size?.height : height || '100%', width: IsSize == 'true' ? size?.width : width || '100%', minWidth: 400, minHeight: 225, overflow: 'hidden' }}>
{/* 顶部信息 */}
{<VideoHeader
operationState={operationState} changeSelectState={changeSelectState}
histroyTime={histroyTime}
setoperationState={setoperationState} name={name}
roll={roll}
showTime={
videoObj.type == 'yingshi' && yingshiPrepare == 'play' ?
null : (histroyBegain || moment())
}
setProcessDisX={setProcessDisX}
content={videoObj.content}
videoStyle={videoStyle}
/>}
{/* 视频内容 */}
{videoObj.type == 'yingshi' ?
<iframe
frameBorder="0"
allowFullScreen='true'
id={containerId}
src={
`${yingshiUrl}?audio=${videoObj.audio && operationState && !operationState.histroy.select ? '1' : '0'}&url=${operationState && operationState.histroy.select && histroyBegain ? `${videoObj.replayUrl}?begin=${moment(histroyBegain).format("YYYYMMDDHHmmss")}&end=${moment(histroyTime[1]).format("YYYYMMDDHHmmss")}` : resolution == 'sd' ? videoObj.playUrlSd : videoObj.playUrlHd}&autoplay=${'1'}&accessToken=${videoObj.yingshiToken}`
}
// https://open.ys7.com/doc/zh/book/index/live_proto.html
// 单个播放器的长宽比例限制最小为{width: 400px;height: 300px;}
width={'100%'}
height={'100%'}
wmode="transparent"
style={{ pointerEvents: 'none' }}
/> :
<div
id={containerId}
style={{
height: '100%', width: '100%'
}}>
</div>
}
{/* 下方操作栏 */}
{/* 显示操作功能条件(宽高) */}
{size?.parentWidth > 400 ?
<VideoOperation
operationState={operationState} operation={operation}
voiceDisY={voiceDisY} setVoiceDisY={setVoiceDisY}
processDisX={processDisX} setProcessDisX={setProcessDisX}
isAdjustProcess={isAdjustProcess} setIsAdjustProcess={setIsAdjustProcess}
resolution={resolution} setResolution={setResolution}
histroyTime={histroyTime} setHistroyTime={setHistroyTime}
histroyBegain={histroyBegain}
play={play} pause={pause} closeSound={closeSound} openSound={openSound}
isPlaying={isPlaying}
videoObj={videoObj}
setYingshiPrepare={setYingshiPrepare}
yingshiPrepareRef={yingshiPrepareRef}
slideDown={slideDown}
/> : ""
}
</div>
</div>
</>
)
}
function mapStateToProps (state) {
const { auth, global } = state;
console.log(global);
return {
user: auth.user,
iotVideoServer: global.iotVideoServer,
};
}
export default connect(mapStateToProps)(VideoPlay);