//Player states. const playerStateFinish = 0; const playerStatePlaying = 1; const playerStatePausing = 2; var boundary = "XHFs29zHSUTjXw" var cms_header_format = `format:cms\r\nboundary:${boundary}\r\nts:${Date.now()}\r\ntrack:id=1,codec=alaw,rate=8000\r\n\r\n` function Player($container) { this.type = "video"; this.isLive = false; this.webglPlayer = null; this.pcmPlayer = null; this.videoLoadFinish = false; this.frameSize = 0; this.canvas = null; this.image = null; this.playerState = playerStateFinish; this.isGetRealSize = false; this.videoWidth = 0; this.videoHeight = 0; this.yLength = 0; this.uvLength = 0; this.isTalking = false; this.isListening = false; this.pauseDownload = false; this.isRedVideo = false; this.flowControl = false; this.fullscreenFlag = false; this.DownloadFinish = false; // add by ramon this.isReviewing = false; // add by ramon this.videoBuffer = []; this.audioBuffer = []; this.imageBuffer = []; this.currentVideots = 0; this.currentFrameIndex = 0; this.currentAudioIndex = 0; this.startAudioIndex = 0; this.videoPartHeaders = []; this.audioPartHeaders = []; this.diplayLastTick = 0 //this.currPart = null // del by ramon this.displayInterval = 0; // add by ramon this.lastDisplayTick = 0; // add by ramon //talk this.localAudioStream = null; this.mediaRecorder = null this.httpRequest = null this.cmsTalk = null //this.cmsTalk = new CmsTalk() //this.talkUrl = talkUrl //初始化元素 this.$container = $container; this.initCMSHtml(); //初始化解析器 this.initCMSParserWorker(); this.logger = new Logger("Player"); } Player.prototype.initCMSHtml = function () { var self = this; var html = `
`; var pictureDialogHtml = ``; this.$container.html(""); this.$container.append(html); this.$pictureDialog = $(pictureDialogHtml); this.$pictureDialog.appendTo($("body")); //全屏 this.$container.find("#fullscreenBtn").click(function () { this.fullscreenFlag = true; this.fullscreen(); }.bind(this)); this.$container.find("#canvasBox").dblclick(function () { if (this.fullscreenFlag) { this.exitfullscreen(); } else { this.fullscreen(); } this.fullscreenFlag = !this.fullscreenFlag; }.bind(this)); //暂停 this.$container.find("#pauseBtn").click(function () { if (self.pauseDownload) { $(this).attr("src", "./public/images/pause.svg"); self.resume(); } else { $(this).attr("src", "./public/images/play.svg"); self.pause(); } }); this.$container.find("#listenBtn").click(function () { console.log("listenBtn clicked", self.isListening); if (self.isListening) { $(this).attr("src", "./public/images/mute.svg"); self.stopListen(); } else { $(this).attr("src", "./public/images/sound.svg"); self.startListen(); } }); this.$container.find("#talkBtn").click(function () { console.log("talkBtn clicked", self.isTalking); if (self.isTalking) { $(this).attr("src", "./public/images/microphone-close.svg"); self.stopTalk() } else { $(this).attr("src", "./public/images/microphone.svg"); self.startTalk() } }); //循环红点画面 this.$container.find("#reviewBtn").click(function () { if (self.$container.find("#alarmblock").css("display") === "block") { if (!self.alarmTime) return; if (!self.isReviewing) { self.isReviewing = true; } else { self.isReviewing = false; } if (self.isReviewing) { if (self.type === "video") { //视频流 for (var i = 0; i < self.videoPartHeaders.length; i++) { if ((self.startTime + self.videoPartHeaders[i].ts + 500) >= (self.alarmTime - 2000)) { self.alarmBlockStartFrameIndex = i; self.currentFrameIndex = i; self.currentVideots = self.videoPartHeaders[i].ts; break; } } if (!self.alarmBlockStartFrameIndex) { self.isReviewing = false; return; } for (var i = self.alarmBlockStartFrameIndex; i < self.videoPartHeaders.length; i++) { if ((self.startTime + self.videoPartHeaders[i].ts) >= (self.alarmTime + 2000)) { self.alarmBlockEndFrameIndex = i; break; } } if (!self.alarmBlockEndFrameIndex) { self.alarmBlockEndFrameIndex = self.videoPartHeaders.length; } //声音播放 if (self.isListening) { self.isListeningFirst = false; if (self.pcmPlayer) { self.pcmPlayer.destroy(); self.pcmPlayer = null; } } } else { //图片流 for (var i = 0; i < self.imageBuffer.length; i++) { if ((self.startTime + self.imageBuffer[i].t + 500) >= (self.alarmTime - 2000)) { self.alarmBlockStartFrameIndex = i; self.currentFrameIndex = i; break; } } if (!self.alarmBlockStartFrameIndex) { self.isReviewing = false; return; } for (var i = 0; i < self.imageBuffer.length; i++) { if ((self.startTime + self.imageBuffer[i].t - 400) >= (self.alarmTime + 2000)) { self.alarmBlockEndFrameIndex = i; break; } } if (!self.alarmBlockEndFrameIndex) { self.alarmBlockEndFrameIndex = self.imageBuffer.length; } } $(this).parent().css("background", "red"); } else { $(this).parent().css("background", "#1C66A3"); } } }); //红点视频-播放声音 this.$container.find("#soundBtn").click(function () { console.log("soundBtn click", self.isListening); if (self.isListening) { $(this).attr("src", "./public/images/mute.svg"); self.stopListen(); } else { $(this).attr("src", "./public/images/sound.svg"); self.startListen(); } }); //查看红点图片 this.$container.find("#pictureBtn").click(function () { this.$pictureDialog.css("display", "block"); this.$pictureDialog.find("#totalPicNumber").html(this.imageBuffer.length); var html = ""; for (var i = 0; i < this.imageBuffer.length; i++) { var timeStr = ""; var time = (this.alarmTime - (this.startTime + this.imageBuffer[i].t)) / 1000; if (time >= 0) { timeStr = `触发前${time}秒`; } else { timeStr = `触发后${Math.abs(time)}秒`; } if (i === 0) { firstTimeStr = timeStr; } html += `
  • ${timeStr}
  • `; } this.$pictureDialog.find("#pictureList").html(html); //默认显示第一张大图 this.currentPictureIndex = 0; var firstHtml = ` ${firstTimeStr}`; this.$pictureDialog.find("#currentPictureBox").html(firstHtml); this.$pictureDialog.find("#pictureList li").eq(0).css("border", "2px solid blue"); //切换显示当前图片 var self = this; this.$pictureDialog.find("#pictureList li").click(function () { self.currentPictureIndex = $(this).index(); $(this).parent().find("li").css("border", "2px solid #DDD"); $(this).css("border", "2px solid blue"); var src = $(this).find("img").attr("src"); var timeStr = $(this).find("span").html(); self.$pictureDialog.find("#currentPictureBox img").attr("src", src); self.$pictureDialog.find("#currentPictureBox span").html(timeStr); self.$pictureDialog.find("#currentPicNumber").html(self.currentPictureIndex + 1); }); }.bind(this)); //上一张 this.$pictureDialog.find("#prePicBtn").click(function () { if (this.currentPictureIndex === 0) { return; } this.currentPictureIndex = this.currentPictureIndex - 1; this.$pictureDialog.find("#pictureList li").css("border", "2px solid #DDD"); this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).css("border", "2px solid blue"); var src = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("img").attr("src"); var timeStr = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("span").html(); this.$pictureDialog.find("#currentPictureBox img").attr("src", src); this.$pictureDialog.find("#currentPictureBox span").html(timeStr); this.$pictureDialog.find("#currentPicNumber").html(this.currentPictureIndex + 1); var top = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).offset().top; var height = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).height(); if (top - height < 0) { this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).get(0).scrollIntoView(); } }.bind(this)); //下一张 this.$pictureDialog.find("#nextPicBtn").click(function () { if (this.currentPictureIndex === this.imageBuffer.length - 1) { return; } this.currentPictureIndex = this.currentPictureIndex + 1; this.$pictureDialog.find("#pictureList li").css("border", "2px solid #DDD"); this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).css("border", "2px solid blue"); var src = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("img").attr("src"); var timeStr = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("span").html(); this.$pictureDialog.find("#currentPictureBox img").attr("src", src); this.$pictureDialog.find("#currentPictureBox span").html(timeStr); this.$pictureDialog.find("#currentPicNumber").html(this.currentPictureIndex + 1); var top = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).offset().top; var height = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).height(); var containerHeight = this.$pictureDialog.find("#pictureList").height(); if (top + height > containerHeight) { this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).get(0).scrollIntoView(false); } }.bind(this)); //首页 this.$pictureDialog.find("#firstPicBtn").click(function () { if (this.currentPictureIndex === 0) { return; } this.currentPictureIndex = 0; this.$pictureDialog.find("#pictureList li").css("border", "2px solid #DDD"); this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).css("border", "2px solid blue"); var src = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("img").attr("src"); var timeStr = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("span").html(); this.$pictureDialog.find("#currentPictureBox img").attr("src", src); this.$pictureDialog.find("#currentPictureBox span").html(timeStr); this.$pictureDialog.find("#currentPicNumber").html(this.currentPictureIndex + 1); this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).get(0).scrollIntoView(); }.bind(this)); //末页 this.$pictureDialog.find("#lastPicBtn").click(function () { if (this.currentPictureIndex === this.imageBuffer.length - 1) { return; } this.currentPictureIndex = this.imageBuffer.length - 1; this.$pictureDialog.find("#pictureList li").css("border", "2px solid #DDD"); this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).css("border", "2px solid blue"); var src = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("img").attr("src"); var timeStr = this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).find("span").html(); this.$pictureDialog.find("#currentPictureBox img").attr("src", src); this.$pictureDialog.find("#currentPictureBox span").html(timeStr); this.$pictureDialog.find("#currentPicNumber").html(this.currentPictureIndex + 1); this.$pictureDialog.find("#pictureList li").eq(this.currentPictureIndex).get(0).scrollIntoView(false); }.bind(this)); //导出图片 this.$pictureDialog.find("#exportBtn").click(function () { for (var i = 0; i < this.imageBuffer.length; i++) { var time = this.startTime + this.imageBuffer[i].t; time = moment(time).format("YYYY_MM_DD_HH_mm_ss_SSS"); var a = document.createElement('a'); a.href = this.imageBuffer[i].d; a.download = time + ".png"; document.body.appendChild(a); a.click(); document.body.removeChild(a); } }.bind(this)); //图片浏览-全屏 this.$pictureDialog.find("#pictureDialogFullScreenBtn").click(function () { if (!this.pictureFullScreenFlag) { this.pictureFullScreenFlag = true; this.$pictureDialog.find("#pictureDialogFullScreenBtn").attr("src", "./public/images/fullscreen-exit2.svg"); } else { this.pictureFullScreenFlag = false; this.$pictureDialog.find("#pictureDialogFullScreenBtn").attr("src", "./public/images/fullscreen2.svg"); } if (this.pictureFullScreenFlag) { this.$pictureDialog.css({ width: "100%", height: "100%", top: 0, left: 0 }); } else { this.$pictureDialog.css({ width: "66%", height: "70%", top: "10%", left: "17%" }); } }.bind(this)); //图片浏览-关闭 this.$pictureDialog.find("#pictureDialogCloseBtn").click(function () { this.$pictureDialog.css("display", "none"); this.$pictureDialog.find("#pictureList").html(""); this.$pictureDialog.find("#currentPictureBox").html(""); }.bind(this)); this.canvas = this.$container.find("#videoscreen")[0]; this.image = this.$container.find("#imgscreen")[0]; } Player.prototype.initCMSParserWorker = function () { var self = this; this.cmsParserWorker = new Worker("public/player/cmsparser.js"); this.cmsParserWorker.onmessage = function (evt) { var objData = evt.data; switch (objData.t) { case kCMSHeaderRes: self.onCMSHeaderInfo(objData.t1, objData.v, objData.a, objData.i, objData.s, objData.at); break; case kFinishDownload: self.onDownloadFinish(objData.s); break; case kImageFrame: self.onImageFrame(objData); break; case kCmsPartHeader: self.onCmsPartHeader(objData); break; case kVideoFrame: if (!self.isGetRealSize) { self.isGetRealSize = true; self.videoWidth = objData.w; self.videoHeight = objData.h; self.yLength = self.videoWidth * self.videoHeight; self.uvLength = (self.videoWidth / 2) * (self.videoHeight / 2); } self.onVideoFrame(objData); break; case kAudioFrame: self.onAudioFrame(objData); break; } if (objData.err) { self.$container.find("#errMsg").html(objData.err); self.$container.find("#errMsg").css("display", "block"); } } }; Player.prototype.play = function (url, isLive, alarmTime, isRedVideo) { console.log("Player.prototype.play ", url) // window.alert("加载成功"); var ret = { e: 0, m: "Success" }; if (isRedVideo) { this.isRedVideo = isRedVideo; } var success = true; if (this.playerState == playerStatePlaying) { ret = { e: -1, m: "Invalid url" }; success = false; this.logger.logError("video is playing."); return ret; } if (!url) { ret = { e: -2, m: "Invalid url" }; success = false; this.logger.logError("[ER] playVideo error, url empty."); return ret; } if (!this.cmsParserWorker) { ret = { e: -4, m: "CMSParserWorker not initialized" }; success = false; this.logger.logError("[ER] CMSParserWorker not initialized."); return ret; } this.$container.find("#videoToolBar").css("display", "flex"); this.liveUrl = url; this.isLive = isLive; if (alarmTime) { if (typeof alarmTime === "string") { this.alarmTime = Number(alarmTime); } else { this.alarmTime = alarmTime; } } //时间进度条 if (this.isLive) { this.$container.find("#playProgressBar").css("display", "none"); } else { this.$container.find("#playProgressBar").css("display", "block"); } this.cmsParserWorker.postMessage({ t: kOpenDecoderReq }); this.displayLoop(); this.webglPlayer = new WebGLPlayer(this.canvas, { preserveDrawingBuffer: false }); this.cmsParserWorker.postMessage({ t: isLive ? kRequestLiveReq : kRequestHeaderReq, u: url, r: this.isRedVideo // add by ramon }); if (this.isLive && !this.cmsTalk) { this.cmsTalk = new CmsTalk() } return ret; }; Player.prototype.resume = function () { //debugger if (this.playerState == playerStatePausing) { this.pauseDownload = false; this.playerState = playerStatePlaying; if (this.isLive) { if (this.liveUrl) { this.cmsParserWorker.postMessage({ t: kOpenDecoderReq }); this.cmsParserWorker.postMessage({ t: kRequestLiveReq, u: this.liveUrl, r: false }); } } else { if (!this.isRedVideo) { if (this.DownloadFinish) { this.flushRate = 0; this.currentFrameIndex = 0; //从头开始播放 this.currentVideots = 0; this.isListeningFirst = false; } else { this.flowControl = false; this.cmsParserWorker.postMessage({ t: kResumeGetUrlReq }); } } } //恢复声音播放 if (this.isListening) { if (!this.pcmPlayer) { this.pcmPlayer = new PCMPlayer({ encoding: "16bitInt", channels: 1, sampleRate: 44100, flushingTime: 5000 }); } this.pcmPlayer.resume(); } } } Player.prototype.pause = function () { if (this.playerState == playerStatePlaying) { this.pauseDownload = true; this.playerState = playerStatePausing; if (this.isLive) { this.cmsParserWorker.postMessage({ t: kCloseDecoderReq }); } else { this.cmsParserWorker.postMessage({ t: kPauseGetUrlReq }); } //暂停声音 this.isListeningFirst = false; if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; } } } Player.prototype.skip = function (time) { if (!this.isLive && !this.isReviewing) { if (this.type === "video") { for (var i = 0; i < this.videoBuffer.length; i++) { if (this.videoBuffer[i].s == time) { this.flushRate = 0; this.currentFrameIndex = i; //暂停声音 this.isListeningFirst = false; if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; } this.pcmPlayer = new PCMPlayer({ encoding: "16bitInt", channels: 1, sampleRate: 44100, flushingTime: 5000 }); this.pcmPlayer.resume(); break; } } } else { for (var i = 0; i < this.imageBuffer.length; i++) { if (this.imageBuffer[i].t == time) { this.flushRate = 0; this.currentFrameIndex = i; break; } } } } } Player.prototype.stop = function (flag) { this.logger.logInfo("Stop."); if (this.playerState == playerStateFinish) { var ret = { e: -1, m: "Not playing" }; return ret; } this.logger.logInfo("Closing decoder."); this.cmsParserWorker.postMessage({ t: kCloseDecoderReq }); //关闭worker if (true) { // modify by ramon old:flag this.cmsParserWorker.terminate(); this.cmsParserWorker = null; } this.webglPlayer = null; if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; this.logger.logInfo("Pcm player released."); } this.videoLoadFinish = false; this.isListening = false; this.pauseDownload = false; this.frameSize = 0; this.currentFrameIndex = 0; this.canvas = null; this.image = null; this.playerState = playerStateFinish; this.isGetRealSize = false; this.videoWidth = 0; this.videoHeight = 0; this.yLength = 0; this.uvLength = 0; this.videoBuffer = []; this.audioBuffer = []; this.imageBuffer = []; //清空容器内容 this.$container.html(""); this.$pictureDialog.remove(); if (this.cmsTalk) { this.cmsTalk.recClose(); // delete this.cmsTalk // this.cmsTalk = null } return 0; }; Player.prototype.fullscreen = function () { if (this.type === "video") { if (this.webglPlayer) { this.webglPlayer.fullscreen(); } } else if (this.type === "image") { this.$container.find("#imgscreen").css({ "position": "fixed", "z-index": "10", "top": 0, "left": 0 }); } }; Player.prototype.exitfullscreen = function () { if (this.type === "video") { if (this.webglPlayer) { this.webglPlayer.exitfullscreen(); } } else if (this.type === "image") { this.$container.find("#imgscreen").css({ "position": "static", "z-index": "auto", "top": "auto", "left": "auto" }); } }; Player.prototype.startTalk = function (callback) { this.isTalking = true; if (this.cmsTalk) this.cmsTalk.startTalk(this.talkUrl, callback) }; Player.prototype.stopTalk = function () { this.isTalking = false; if (this.cmsTalk) this.cmsTalk.stopTalk() }; Player.prototype.startListen = function () { this.isListening = true; if (!this.pcmPlayer) { this.pcmPlayer = new PCMPlayer({ encoding: "16bitInt", channels: 1, sampleRate: 44100, flushingTime: 5000 }); } this.pcmPlayer.resume(); }; Player.prototype.stopListen = function () { this.isListeningFirst = false; this.isListening = false; if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; } }; Player.prototype.displayLoop = function (timestamp) { //console.log("displayLoop timestamp:",timestamp); requestAnimationFrame(this.displayLoop.bind(this)); if (this.playerState == playerStateFinish || this.playerState == playerStatePausing) { if (this.isLive) { while (this.videoBuffer.length > 0) { this.videoBuffer.shift(); } while (this.audioBuffer.length > 0) { this.audioBuffer.shift(); } } return false; } if (this.isLive) { //实时视频 //视频流 if (this.videoBuffer.length > 0) { var videoFrame = this.videoBuffer[0]; if (this.displayVideoFrame(videoFrame)) { this.videoBuffer.shift(); } } //声音流 if (this.audioBuffer.length > 0) { var audioFrame = this.audioBuffer[0]; if (this.displayAudioFrame(audioFrame)) { this.audioBuffer.shift(); } } } else { //红点视频 if (this.type === "video") { //视频流 if (this.isRedVideo) { //console.log("displayLoop : isRedVideo :videoPartHeaders.length:",this.videoPartHeaders.length," -- videoBuffer:",this.videoBuffer.length); if (0 == this.displayInterval) { this.displayInterval = Math.round(1000 / this.videoRate) - 20; } if ((timestamp - this.diplayLastTick) >= this.displayInterval) { if (this.videoBuffer.length > 0) { var frame = this.videoBuffer.shift(); if (frame) { this.currentVideots = frame.s; //console.log("displayVideoFrame timestamp:",timestamp ," displayInterval:",this.displayInterval); this.displayVideoFrame(frame); this.updateTimeTrack(frame.s, false); } this.diplayLastTick = timestamp; } } if (this.videoBuffer.length < 20) { while (this.currentFrameIndex < this.videoPartHeaders.length) { var part = this.videoPartHeaders[this.currentFrameIndex]; // console.log(this.currentFrameIndex, part.type) if (part.type == 'a') { this.currentFrameIndex++ } else { this.cmsParserWorker.postMessage({ t: kDecodeVideo, index: this.currentFrameIndex++ }); break } } } //声音播放 if (this.isListening && this.audioBuffer.length > 0) { if (!this.isListeningFirst) { for (var i = 0; i < this.audioBuffer.length; i++) { // console.log("audioBuffer", this.audioBuffer[i].s, this.currentVideots) if (this.audioBuffer[i].s >= this.currentVideots - 60) { this.currentAudioIndex = i; if (!this.pcmPlayer) { this.pcmPlayer = new PCMPlayer({ encoding: "16bitInt", channels: 1, sampleRate: 44100, flushingTime: 5000 }); this.pcmPlayer.resume(); } this.displayAudioFrame(this.audioBuffer[i], true); break; } } this.isListeningFirst = true; } else { if (this.currentAudioIndex < this.audioBuffer.length - 1) { this.currentAudioIndex++; this.displayAudioFrame(this.audioBuffer[this.currentAudioIndex]); } } } //播放结束 if (this.isReviewing) { //循环播放红点画面 if (this.currentFrameIndex + 1 > this.alarmBlockEndFrameIndex) { this.currentFrameIndex = this.alarmBlockStartFrameIndex; this.currentVideots = this.videoBuffer[this.currentFrameIndex].s; if (this.isListening) { this.isListeningFirst = false; if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; } } } } else { //从头开始播放 if (this.frameSize > 0 && this.currentFrameIndex >= this.frameSize) { this.flushRate = 0; this.currentFrameIndex = 0; this.currentVideots = 0; this.isListeningFirst = false; //重复播放不会断累积缓冲,导致延时, 没找到如何清空缓存, if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; } } } } else { //普通录像 if (this.videoPartHeaders.length > 0) { if (0 == this.displayInterval) { this.displayInterval = Math.round(1000 / this.videoRate) - 20; } if ((timestamp - this.diplayLastTick) >= this.displayInterval) { if (this.videoBuffer.length > 0) { var frame = this.videoBuffer.shift(); if (frame) { this.currentVideots = frame.s; this.displayVideoFrame(frame); this.updateTimeTrack(frame.s, false); } this.diplayLastTick = timestamp; } } if (this.videoBuffer.length < 20) { while (this.currentFrameIndex < this.videoPartHeaders.length) { var part = this.videoPartHeaders[this.currentFrameIndex]; // console.log(this.currentFrameIndex, part.type) if (part.type == 'a') { this.currentFrameIndex++ } else { this.cmsParserWorker.postMessage({ t: kDecodeVideo, index: this.currentFrameIndex++ }); break } } } /////// flowControl add by ramon if ((this.currentFrameIndex < this.videoPartHeaders.length) && (!this.DownloadFinish)) { var buf_count = this.videoPartHeaders.length - this.currentFrameIndex; console.log("buf_count:", buf_count, " ", this.flowControl); if (buf_count > 400) { if (false == this.flowControl) { this.flowControl = true; this.cmsParserWorker.postMessage({ t: kPauseGetUrlReq }); console.log("------Pause GetUrlReq---------"); } } else if (buf_count < 200) { if (true == this.flowControl) { this.flowControl = false; this.cmsParserWorker.postMessage({ t: kResumeGetUrlReq }); console.log("------Resume GetUrlReq---------"); } } } //声音播放 if (this.isListening && this.audioBuffer.length > 0) { if (!this.isListeningFirst) { for (var i = 0; i < this.audioBuffer.length; i++) { // console.log("audioBuffer", this.audioBuffer[i].s, this.currentVideots) if (this.audioBuffer[i].s >= this.currentVideots - 60) { this.currentAudioIndex = i; if (!this.pcmPlayer) { this.pcmPlayer = new PCMPlayer({ encoding: "16bitInt", channels: 1, sampleRate: 44100, flushingTime: 5000 }); this.pcmPlayer.resume(); } this.displayAudioFrame(this.audioBuffer[i], true); break; } } this.isListeningFirst = true; } else { if (this.currentAudioIndex < this.audioBuffer.length - 1) { this.currentAudioIndex++; this.displayAudioFrame(this.audioBuffer[this.currentAudioIndex]); } } } if (this.frameSize > 0 && this.currentFrameIndex >= this.frameSize) { if (this.DownloadFinish) { //播放结束 if (this.isReviewing) { this.flushRate = 0; this.currentFrameIndex = 0; //从头开始播放 this.currentVideots = 0; this.isListeningFirst = false; //重复播放不会断累积缓冲,导致延时, 没找到如何清空缓存, if (this.pcmPlayer) { this.pcmPlayer.destroy(); this.pcmPlayer = null; } } else { if (!this.pauseDownload) { this.$container.find("#pauseBtn").attr("src", "./public/images/play.svg"); this.pause(); } } } } } // if (this.videoBuffer.length > 0) { // // console.log("this.videoBuffer.length:", this.videoBuffer.length); // var videoFrame = this.videoBuffer[0]; // if (this.displayVideoFrame(videoFrame)) { // this.videoBuffer.shift(); // } // if (this.videoBuffer.length > 400) { // if (false == this.flowControl) { // this.flowControl = true; // this.cmsParserWorker.postMessage({ // t: kPauseGetUrlReq // }); // //console.log("------Pause GetUrlReq---------"); // } // } else if (this.videoBuffer.length < 200) { // if (true == this.flowControl) { // this.flowControl = false; // this.cmsParserWorker.postMessage({ // t: kResumeGetUrlReq // }); // //console.log("------Resume GetUrlReq---------"); // } // } // } // //声音流 // if (this.audioBuffer.length > 0) { // var audioFrame = this.audioBuffer[0]; // if (this.displayAudioFrame(audioFrame)) { // this.audioBuffer.shift(); // } // } } } else { // 图片流 if (this.imageBuffer.length < 1) return if (this.flushRate > 0) { this.flushRate--; return } //console.log("图片流", this.imageBuffer.length, this.currentFrameIndex, this.isReviewing) var frame = this.imageBuffer[this.currentFrameIndex]; if (frame) { this.flushRate = Math.ceil(60 / this.imageRate); this.image.src = this.imageBuffer[this.currentFrameIndex].d; this.updateTimeTrack(this.imageBuffer[this.currentFrameIndex].t); this.currentFrameIndex++; } //播放结束 if (this.isReviewing) { //循环播放红点画面 if (this.currentFrameIndex + 1 > this.alarmBlockEndFrameIndex) { this.currentFrameIndex = this.alarmBlockStartFrameIndex; } } else { //从头开始播放 if (this.frameSize > 0 && this.currentFrameIndex >= this.frameSize) { this.flushRate = 0; this.currentFrameIndex = 0; } } } } }; Player.prototype.displayVideoFrame = function (frame) { if (this.playerState == playerStateFinish || this.playerState == playerStatePausing) { return false; } if (this.videoBuffer.length < 2 && this.pauseDownload) { this.pauseDownload = false; this.cmsParserWorker.postMessage({ t: kResumeGetUrlReq }); } if (this.webglPlayer) { var data = new Uint8Array(frame.d); //console.log("displayVideoFrame:",data.length); this.webglPlayer.renderFrame(data, this.videoWidth, this.videoHeight, this.yLength, this.uvLength); delete data; return true; } else { return false; } }; Player.prototype.displayAudioFrame = function (frame, flushcache) { if (this.playerState == playerStateFinish || this.playerState == playerStatePausing || !this.isListening) { return false; } if (this.audioBuffer.length < 2 && this.pauseDownload) { this.pauseDownload = false; this.cmsParserWorker.postMessage({ t: kResumeGetUrlReq }); } if (this.pcmPlayer) { this.pcmPlayer.play(new Uint8Array(frame.d), flushcache); return true; } else { return false; } } Player.prototype.onCMSHeaderInfo = function (videoType, videoTrack, audioTrack, imageTrack, startTime, alarmTime) { if (startTime && typeof startTime === "string") { startTime = Number(startTime); } if (alarmTime && typeof alarmTime === "string") { alarmTime = Number(alarmTime); } this.type = videoType; this.startTime = startTime; if (alarmTime) { this.alarmTime = alarmTime; } this.playerState = playerStatePlaying; if ((!this.isLive) && (!this.isRedVideo)) { // modify by ramon this.cmsParserWorker.postMessage({ t: kRequestBodyReq }); } this.$container.find(".videoToolBarIcon").css("display", "none"); if (this.type === "video") { this.$container.find("#imgscreen").css("display", "none"); if (this.isLive) { this.$container.find(".liveVideo").css("display", "inline-block"); } else { this.$container.find(".redVideo").css("display", "inline-block"); } if (videoTrack) { this.videoWidth = videoTrack.width; this.videoHeight = videoTrack.height; this.videoRate = videoTrack.rate; this.yLength = this.videoWidth * this.videoHeight; this.uvLength = (this.videoWidth / 2) * (this.videoHeight / 2); this.flushRate = Math.round(60 / this.videoRate); } if (audioTrack) { this.pcmPlayer = new PCMPlayer({ encoding: "16bitInt", channels: 1, sampleRate: 44100, flushingTime: 5000 }); } } else if (this.type === "image") { this.$container.find("#imgscreen").css("display", "block"); if (this.isLive) { this.$container.find(".liveImg").css("display", "inline-block"); } else { this.$container.find(".redImg").css("display", "inline-block"); } if (imageTrack) { this.imageWidth = imageTrack.width; this.imageHeight = imageTrack.height; // this.imageRate = imageTrack.rate; this.imageRate = 3; this.flushRate = Math.ceil(60 / this.imageRate); } } } Player.prototype.onDownloadFinish = function (size) { // if (this.type === "video") { // this.frameSize = this.videoBuffer.length; // } else { this.frameSize = size; // } this.DownloadFinish = true; } Player.prototype.onImageFrame = function (frame) { var encodeData = this.arrayBufferToBase64(frame.d); var imageData = "data:image/jpeg;base64," + encodeData; var data = { d: imageData, t: frame.s }; this.imageBuffer.push(data); //当前获取到流的相对时间 this.updateTimeTrack(data.t, true); }; Player.prototype.arrayBufferToBase64 = function (buffer) { var binary = ''; for (var i = 0; i < buffer.length; i++) { binary += String.fromCharCode(buffer[i]); } // for (var i = 0; i < buffer.length; i++) { // for (var j = 0; j < buffer[i].length; j++) { // binary += String.fromCharCode(buffer[i][j]); // } // } return window.btoa(binary); } Player.prototype.onCmsPartHeader = function (part) { if (this.isLive) { while (this.videoPartHeaders.length > 10) { this.videoPartHeaders.shift(); } } this.videoPartHeaders.push(part); if (part.type != 'a') this.updateTimeTrack(part.ts, true); }; Player.prototype.onVideoFrame = function (frame) { if (this.isLive) { while (this.videoBuffer.length > 10) { this.videoBuffer.shift(); } } this.videoBuffer.push(frame); // this.updateTimeTrack(frame.s, true); }; Player.prototype.onAudioFrame = function (frame) { if (this.isLive) { while (this.audioBuffer.length > 10) { this.audioBuffer.shift(); } } this.audioBuffer.push(frame); // console.log("onAudioFrame", this.audioBuffer.length) } //红点视频-更新时间进度 Player.prototype.updateTimeTrack = function (currentTime, loadBuffer) { if (this.isLive) { return; } var self = this; if (loadBuffer) { //时间刻度 var cursorNum = this.$container.find("#videoTimeTrack").find("li").length; if ((Math.floor(currentTime / 1000) + 1) > cursorNum) { var time = moment(this.startTime).add(Math.floor(currentTime / 1000), "seconds").format("HH:mm:ss"); if (cursorNum === 0) { var t = currentTime; } else if (cursorNum === 1) { var t = this.preCurrentTime; } else { var t = this.preCurrentTime2; } this.preCurrentTime2 = currentTime; this.$container.find("#videoTimeTrack").append("
  • "); this.$container.find("#timeProgress").append("
  • "); } var cursorNum2 = this.$container.find("#videoTimeTrack").find("li").length; this.$container.find("#videoTimeTrack").find("li").css("width", (100 / cursorNum2) + "%"); this.$container.find("#timeProgress").find("li").css("width", (100 / cursorNum2) + "%"); this.$container.find("#timeProgress li").unbind("click").click(function () { var t = $(this).attr("t"); self.skip(t); }); //红点视频范围 if (this.startTime + currentTime >= this.alarmTime) { this.$container.find("#alarmblock").css("display", "block"); var per = (4000 / currentTime) * 100; this.$container.find("#alarmblock").css("width", per + "%"); var left = ((this.alarmTime - 2000 - this.startTime) / currentTime) * 100; this.$container.find("#alarmblock").css("left", left + "%"); } this.preCurrentTime = currentTime; } else { //播放进度条 var index2 = 0; this.$container.find("#timeProgress li").each(function (index) { var time = $(this).attr("t"); if (index < self.$container.find("#timeProgress li").length - 1) { var time2 = self.$container.find("#timeProgress li").eq(index + 1).attr("t"); if (currentTime >= time && currentTime < time2) { index2 = index; return false; } } else { if (currentTime >= time) { index2 = index; return false; } } }); var left = this.$container.find("#videoTimeTrack").find("li").eq(index2).position().left; if (index2 < this.$container.find("#timeProgress li").length - 1) { this.$container.find("#timeTrack").css("left", left - 10); } else { var lastTimeTrack = this.$container.find("#timeProgress").find("li").eq(index2).attr("t"); if (Math.floor(currentTime / 1000) > Math.floor(lastTimeTrack / 1000)) { var lastTimeWidth = this.$container.find("#videoTimeTrack").find("li").eq(index2).width(); this.$container.find("#timeTrack").css("left", left + lastTimeWidth - 10); } else { this.$container.find("#timeTrack").css("left", left - 10); } } } }