| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /**
- * srs webrtc palyer
- * auth Caner
- */
- import MD5 from 'js-md5'
- class WebRtcPlayer {
- private Peer: any
- private TIMER: any
- constructor(option: { HOST: string; TOKEN: string; UUID: string; PROFILE: number; PORT: number; DOM: HTMLVideoElement; starttime?: number; endtime?: number }) {
- this.initWebRtc(option.HOST, option.PORT, option.TOKEN, option.UUID, option.PROFILE, option.DOM, option.starttime, option.endtime).then(res => {
- this.Peer = res
- }).catch(() => {
- this.Peer = null
- })
- }
- /**
- * 同步睡眠
- * @param ms 毫秒
- * @returns
- */
- private sleep(ms: number) { return new Promise((resolve) => { setTimeout(resolve, ms) }) }
- /**
- * 初始化webrtc
- * @param HOST 媒体服务器地址
- * @param TOKEN 用户token
- * @param UUID 摄像头uuid
- * @param PROFILE 码流
- * @param DOM video节点
- * @returns
- */
- private async initWebRtc(HOST: string, PORT: number, TOKEN: string, UUID: string, PROFILE: number, DOM: HTMLVideoElement, STIME?: number, ETIME?: number) {
- try {
- const Peer = new RTCPeerConnection() as any
- Peer.addTransceiver('video', { direction: 'recvonly' })
- const offer = await Peer.createOffer()
- await Peer.setLocalDescription(offer)
- // 监听视频=播放
- Peer.ontrack = (event: Event | any) => {
- if (DOM) {
- const { streams } = event
- DOM.srcObject = streams[0]
- console.log('track', event)
- }
- }
- Peer.oniceconnectionstatechange = () => {
- const state = Peer.iceConnectionState
- console.log('ICE状态', state)
- }
- Peer.onicegatheringstatechange = () => {
- console.log('GatheringState: ', Peer.iceGatheringState)
- }
- Peer.onconnectionstatechange = () => {
- const state = Peer.connectionState
- console.log('连接状态', state)
- }
- // SDP SRS params 区分历史与实时
- const STREAM = STIME && ETIME ? MD5(UUID + PROFILE) : UUID + PROFILE
- const params = STIME && ETIME ? {
- api: `http://${HOST}:${PORT}/rtc/v1/play/?token=${TOKEN}&uuid=${UUID}&stream=${UUID + PROFILE}&profile=${PROFILE}`,
- clientip: null,
- sdp: offer.sdp,
- streamurl: `webrtc://${HOST}/replay/${STREAM}?token=${TOKEN}&starttime=${STIME}&endtime=${ETIME}&uuid=${UUID}&stream=${STREAM}&profile=${PROFILE}`,
- tid: Number(Math.floor(new Date().getTime() * Math.random() * 100)).toString(16).slice(0, 7)
- } : {
- api: `http://${HOST}:${PORT}/rtc/v1/play/?token=${TOKEN}&uuid=${UUID}&stream=${UUID + PROFILE}&profile=${PROFILE}`,
- clientip: null,
- sdp: offer.sdp,
- streamurl: `webrtc://${HOST}/live/${STREAM}?token=${TOKEN}&uuid=${UUID}&stream=${STREAM}&profile=${PROFILE}`,
- tid: Number(Math.floor(new Date().getTime() * Math.random() * 100)).toString(16).slice(0, 7)
- }
- console.log('params', params)
- // 发送offer
- const res = await window.fetch(params.api, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(params)
- })
- // 接收 answer
- const { sdp } = await res.json()
- if (sdp) await Peer.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp }))
- return Peer
- } catch (error) {
- console.warn('webRtcInit:', error);
- return null
- }
- }
- /**
- * 云台控制
- * @param URL
- * @param UUID
- * @param TOKEN
- * @param command 指令:数字键盘1-9去掉5,10:焦距放大,11:焦距缩小 12:亮度,13:色彩饱和度,14:对比度,15:清晰度
- * @param number [云台速度|焦距参数|色彩饱和度]等值 亮度值 0-100
- * @returns
- */
- public contrl(URL: string, UUID: string, TOKEN: string, command: number, number: number) {
- if (!UUID) return
- if (this.TIMER !== null) clearTimeout(this.TIMER)
- this.TIMER = setTimeout(() => {
- window.fetch(URL, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- code: 'cloudcontrol.control',
- token: TOKEN,
- body: {
- uuid: UUID,
- command,
- number
- }
- })
- })
- }, 500);
- }
- /**
- * 视频截图
- * @param option
- * @returns base64
- */
- public capPhoto(DOM: HTMLVideoElement) {
- const canvas = document.createElement('canvas')
- canvas.width = DOM.offsetWidth
- canvas.height = DOM.offsetHeight
- const context = canvas.getContext('2d')
- context?.drawImage(DOM, 0, 0, DOM.offsetWidth, DOM.offsetHeight)
- const base64 = canvas.toDataURL('image/jpg')
- return base64
- }
- /**
- * 视频录像
- * @param DOM
- * @param TIME ms
- * @returns
- */
- public async capVideo(DOM: HTMLVideoElement, TIME: number) {
- const recordedBlobs = [] as any
- const MediaStream = DOM['srcObject'] as MediaStream
- const mediaRecorder = new MediaRecorder(MediaStream, { mimeType: 'video/webm;codecs=h264' })
- mediaRecorder.ondataavailable = (event: { data: { size: number } }) => {
- if (event.data && event.data.size > 0) {
- recordedBlobs.push(event.data);
- }
- }
- mediaRecorder.start()
- await this.sleep(TIME || 1000 * 3)
- mediaRecorder.stop()
- return await new Promise((resolve, reject) => {
- mediaRecorder.onstop = () => {
- const blob = new Blob(recordedBlobs, { type: 'video/mp4' });
- resolve(blob)
- }
- mediaRecorder.onerror = reject
- })
- }
- /**
- * 关闭webrtc
- */
- public async close() {
- if (this.Peer) this.Peer.close()
- if (this.TIMER) clearTimeout(this.TIMER)
- }
- }
- export default WebRtcPlayer
|