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 { Button, ToastFactory, } from '@douyinfe/semi-ui'; import VideoHeader from './voiceHeader' import VideoOperation from './videoOperation' import './videoPlay.less'; import EZUIKit, { log } from 'ezuikit-js' import flvjs from 'flv.js' const timeFormat = 'YYYY-MM-DD HH:mm:ss' const yingshiUrl = 'https://open.ys7.com/ezopen/h5/iframe' const yingshiCloseSoundKey = 'closeSound' const yingshiOpenSoundKey = 'openSound' let videoFront let videoAfter // let duration = moment.duration(videoAfter.diff(videoFront))._data.milliseconds; const VideoPlay = ({ dispatch, actions, 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.6nn6duwz8g8gbd919as9a6ea82bmn31x-709fnp7s3k-13q3v7e-mlov7lysf', // 萤石必须 // 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.hd.local.rec', // }, // videoObj = { // type: 'yingshi', // audio: false, // serialNo: 'G56385051', // 设备序列号 必须 // channelNo: 1, // // yingshiToken: 'at.6nn6duwz8g8gbd919as9a6ea82bmn31x-709fnp7s3k-13q3v7e-mlov7lysf', // 萤石必须 // playUrlSd: 'ezopen://open.ys7.com/G56384814/1.live', // 必须 // // playUrl: 'ws://221.230.55.27:8081/jessica/34020000001110000077/34020000001310000003', // playUrlHd: 'ezopen://open.ys7.com/G56384814/1.hd.live', // replayUrl: 'ezopen://open.ys7.com/G56384814/1.hd.local.rec', // }, // videoObj = { // type: 'cascade', // audio: false, // cloudControl: true, // serialNo: '34020000001310000001', // 设备序列号 必须 // topSerialNo: '34020000001320000001', // 设备顶级序列号 必须 // playUrlSd: 'wss://221.230.55.27:8082/jessica/34020000001320000001/34020000001310000001', // 必须 // // playUrlHd: 'ezopen://open.ys7.com/G75922040/1.hd.live', // // replayUrl: 'ezopen://open.ys7.com/G75922040/1.rec', // }, // iotVideoServer, iotVideoPlayServer, local, //是否本地调用视频 }) => { if (videoObj.type == 'yingshi') { videoObj = { ...videoObj, playUrlSd: `ezopen://open.ys7.com/${videoObj.serialNo}/${videoObj.channelNo || '1'}.live`, playUrlHd: `ezopen://open.ys7.com/${videoObj.serialNo}/${videoObj.channelNo || '1'}.hd.live`, replayUrl: `ezopen://open.ys7.com/${videoObj.serialNo}/${videoObj.channelNo || '1'}.hd.local.rec`, } } else { videoObj = { ...videoObj, playUrlSd: `${iotVideoPlayServer}/jessica/${videoObj.topSerialNo}/${videoObj.serialNo}`, } } const { openness } = actions; const [jessibuca, setjessibuca] = useState(null) const [player, setPlayer] = 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 [photo, setPhoto] = useState(1)//滚动备注 const [size, setSize] = useState({ parentWidth: sizeWh?.parentWidth, parentHeight: sizeWh?.parentHeight, width: width || sizeWh?.parentWidth, height: height || sizeWh?.parentHeight }) //视频本身和父级尺寸 const [resolution, setResolution] = useState('sd') // 标清 sd 高清 hd const [videoMask, setVideoMask] = useState(true) // 视频遮罩 const [disappear, setDisappear] = useState(false) // 视频消失 const [numbers, setNumbers] = useState(false) const [written, setWritten] = useState('') const [hideFullScreenBut, setHideFullScreenBut] = useState(false) // 标记萤石操作中,等待ifream返回信息后清空 const [yingshiPrepare, setYingshiPrepare] = useState('') const operationRef = useRef(null) const Begain = useRef() const playBackTime = useRef([]) const quanp = useRef() const processChangeTimeoutRef = useRef(null) // 标记萤石操作中,等待ifream返回信息后清空 const yingshiPrepareRef = useRef(null) const playState = useRef(false) //播放状态 const yingshiPlayer = useRef(null) const jessibucas = useRef(null) const flvPlayer = useRef() useEffect(() => { setRoll(false) }, [resolution]); useEffect(() => { if (disappear || !videoMask) { let duration = moment.duration(videoAfter?.diff(videoFront))._data.milliseconds; setTimeout(() => { if (disappear || duration > 2000) { setVideoMask(true) dispatch(openness.getErrorCode(videoObj.videoToken ? { status: numbers, platform: videoObj.type, token: videoObj.videoToken } : { status: numbers, platform: videoObj.type })).then((res) => { if (res.payload.data) { if (res.payload.data.paraphraseCustom) { setWritten(res.payload.data.paraphraseCustom) } else { if (res.payload.data.describe) { setWritten(res.payload.data.describe) } else { setWritten('视频异常,问题处理中...') } } } else { setWritten('视频异常,问题处理中...') } }); } }, duration > 2000 ? 0 : 2000 - duration) } }, [disappear, videoMask]) useEffect(() => { setResolution(changeData?.hdChecked ? 'hd' : 'sd') if (player) { videoFront = new moment(); //验证前时间 player.stop().then(() => { player.play({ url: changeData?.hdChecked ? videoObj.playUrlHd : videoObj.playUrlSd }) }) } }, [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([]) playBackTime.current = [] } 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)]) playBackTime.current = [moment().subtract(72, 'hours').format(timeFormat), moment().format(timeFormat)] } setoperationState(nextOperationState) } // 实时播放左下方操作栏内容 const operation = [{ key: 'control', hide: !videoObj.cloudControl, click: () => { changeSelectState('control') } }, { key: 'talk', hide: !videoObj.audio, click: (e) => { changeSelectState('talk') } }, { key: 'fullScreen', hide: hideFullScreenBut, click: (fullNoChange = false) => { changeSelectState('fullScreen') let videoplay = document.getElementById("vcmp_videoplay" + videoObj.id) if (screenfull.isEnabled) { if (!fullNoChange) { screenfull.toggle(videoplay); } if (videoObj?.type == 'yingshi' && (player || yingshiPlayer.current)) { if (operationRef.current?.fullScreen.select) { (player || yingshiPlayer.current).reSize(screen.width, screen.height); } else { (player || yingshiPlayer.current).reSize(size?.width, size?.height); } } } } }, { key: 'histroy', hide: !Boolean(videoObj.replayUrl), click: () => { changeSelectState('histroy') videoFront = new moment(); //验证前时间 player.stop().then(() => { if (operationRef.current?.histroy?.select && Begain.current) { player.play({ url: `${videoObj.replayUrl}?begin=${moment(Begain.current).format("YYYYMMDDHHmmss")}&end=${moment(playBackTime.current[1]).format("YYYYMMDDHHmmss")}` }) } playState.current = false }) } },] // useEffect(() => { // createPlay() // }, [quanp.current]) useEffect(() => { createPlay() let nextOperationState = {} for (let p of operation) { nextOperationState[p.key] = { select: false } } setoperationState(nextOperationState) operationRef.current = nextOperationState // 全屏状态监听 screenfull.on('change', (e) => { let curFullElement = screenfull.element if (curFullElement && curFullElement.id == 'vcmp_videoplay' + videoObj.id) { if (e?.path[0]?.id?.includes("vcmp_videoplay")) { if (screenfull.isFullscreen && operationRef.current && !operationRef.current['fullScreen'].select) { changeSelectState('fullScreen') } if (!screenfull.isFullscreen && operationRef.current && operationRef.current['fullScreen'].select) { changeSelectState('fullScreen') if (yingshiPlayer.current) { // yingshiPlayer.current.reSize(size?.width, size?.height); } } setHideFullScreenBut(false) } } else if (curFullElement && curFullElement.id == 'rearProjection') { setHideFullScreenBut(true) } else { setHideFullScreenBut(false) setTimeout(() => { if (operationRef.current.fullScreen.select) { operation.find(cf => cf.key == 'fullScreen').click(true) } }, 0) } }); document.onkeydown = (e) => { } // const resize_ = () => { // const VideoLocal = document.getElementById('vcmp_videoplay') // setSize({ parentWidth: VideoLocal?.clientWidth, parentHeight: VideoLocal?.clientHeight, width: VideoLocal?.clientWidth, height: VideoLocal?.clientHeight }) // } // if (local) { // window.addEventListener('resize', resize_); //只要窗口殴大小发生像素变化就会触发 // } document.addEventListener("visibilitychange", function () { const buffered = flvPlayer.current.buffered.end(0) - 0.1 if (buffered - flvPlayer.current.currentTime > 1) { flvPlayer.current.currentTime = buffered } }) return () => { if (jessibucas.current) { jessibucas.current.destroy() const bye = request.get(`${iotVideoServer}/api/gb28181/bye?id=${videoObj.topSerialNo}&channel=${videoObj.serialNo}`).then(v => { }) } if (yingshiPlayer.current && videoObj.type == 'yingshi') { yingshiPlayer.current.stop() } if (flvPlayer && flvPlayer.current) { flvPlayer.current.destroy(); } } }, []) useEffect(() => { if (histroyTime.length) { setHistroyBegain(histroyTime[0]) Begain.current = histroyTime[0] document.getElementById('process_point').style.left = 0 + 'px'; // 重置进度条的位置 if (videoObj.type == 'yingshi') { // yingshiPrepareRef.current = 'play' // setYingshiPrepare('play') } } else { setHistroyBegain(null) Begain.current == 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) ) Begain.current = 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) videoFront = new moment(); //验证前时间 player.stop().then(() => { player.play({ url: `${videoObj.replayUrl}?begin=${moment(Begain.current).format("YYYYMMDDHHmmss")}&end=${moment(playBackTime.current[1]).format("YYYYMMDDHHmmss")}` }) playState.current = false }) } else { // 随播放时间变化更新进度条 document.getElementById('process_point').style.left = processDisX - 4.5 + 'px' } } }, [processDisX]) const createPlay = 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); // }) videoFront = new moment(); //验证前时间 const inviteRes_ = await request.get(`${iotVideoServer}/api/gb28181/invite?id=${videoObj.topSerialNo}&channel=${videoObj.serialNo}`).then((res) => { videoAfter = new moment(); //验证后时间 }) } catch (error) { console.log(error.response); } let container = document.getElementById(containerId); // 播放方式 1 // const jessibuca = new window.Jessibuca({ // container: container, // videoBuffer: 0.2, // 缓存时长 // isResize: false, // text: "", // loadingText: "加载中", // debug: true, // showBandwidth: false, // 显示网速 // operateBtns: { // fullscreen: false, // screenshot: false, // play: false, // audio: false, // }, // forceNoOffscreen: false, // controlAutoHide: true, // isNotMute: false, // }); // setjessibuca(jessibuca) // jessibucas.current = jessibuca // play({ jessibuca }) // 播放方式 2 const flv = flvjs.createPlayer({ type: 'flv', // url: 'ws://10.8.30.42:8081/jessica/34020000001110000001/34020000001310000001.flv', url: `${iotVideoServer}/jessica/${videoObj.topSerialNo}/${videoObj.serialNo}.flv`, isLive: true, hasAudio: false, hasVideo: true, enableWorker: false, enalleStashBuffer: true, stashInitialSize: 128, lazyLoadMaxDuration: 3 * 60, seekType: 'range', autoCleanupSourceBuffer: true, }); flv.attachMediaElement(container); flv.load(); flv.play(); flvPlayer.current = flv } else { videoFront = new moment(); //验证前时间 const player = new EZUIKit.EZUIKitPlayer({ id: containerId, // 视频容器ID accessToken: videoObj?.yingshiToken, url: videoObj.playUrlSd, width: setupSize('width'), height: setupSize('height'), handleSuccess: (e) => { //播放成功 setRoll(true) setVideoMask(false) playState.current = true videoAfter = new moment(); //验证后时间 }, handleError: (e) => { //播放失败 console.log(e, '播放失败'); setNumbers(e.retcode) videoAfter = new moment(); //验证后时间 setDisappear(true) }, }) setPlayer(player) yingshiPlayer.current = player } } const play = (params) => { if (videoObj.type == 'yingshi') { } else if ((params.jessibuca || jessibuca) && videoObj.playUrlSd) { const jes = params.jessibuca || jessibuca jes.play(videoObj.playUrlSd); setIsPlaying(true) } } const pause = () => { if (videoObj.type == 'yingshi' && player) { } 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) } } const setupSize = (data) => { if (!operationRef.current?.fullScreen.select) { let containerWidth = sizeWh?.parentWidth //容器的宽高和视频的宽高 let containerHeight = sizeWh?.parentHeight let videoWidth = width || sizeWh?.width let videoHeight = height || sizeWh?.height if (IsSize == 'true') { if (containerWidth >= videoWidth && containerHeight >= videoHeight) { if (videoHeight / videoWidth >= 0.55 && videoHeight / videoWidth <= 0.57) { } else { console.warn('宽高不符合尺寸要求,故返回合适的尺寸') if (videoWidth / 16 > videoHeight / 9) { videoWidth = (videoHeight / 9) * 16 } else { videoHeight = (videoWidth / 16) * 9 } } } else { console.warn('传递宽高参数有误,请确认容器大小范围内') if (containerWidth / 16 > containerHeight / 9) { videoWidth = (containerHeight / 9) * 16 } else { videoHeight = (containerWidth / 16) * 9 } } if (videoObj.type == 'yingshi' && player) { player.reSize(videoWidth, videoHeight) } } else { if (videoObj.type == 'yingshi' && player?.pluginStatus) { player.reSize(videoWidth, videoHeight) } } setSize({ parentWidth: containerWidth, parentHeight: containerHeight, width: videoWidth, height: videoHeight }) return data == 'width' ? videoWidth : data == 'height' ? videoHeight : '' } } useEffect(() => { setupSize() }, [sizeWh]) return ( <>
{/* */} {/* 视频内容 */} { //