/** * Created by wangweijie5 on 2016/12/2. */ // 错误码 const PLAYM4_PARA_OVER = 0; // 参数错误 const PLAYM4_OK = 1; //正确 const PLAYM4_ORDER_ERROR = 2; // 调用接口顺序错误 const PLAYM4_TIMER_ERROR = 3; // 创建多媒体时钟错误 const PLAYM4_DEC_VIDEO_ERROR = 4; // 视频设备错误 const PLAYM4_DEC_AUDIO_ERROR = 5; // 音频设备错误 const PLAYM4_ALLOC_MEMORY_ERROR = 6; // 申请内存失败 const PLAYM4_OPEN_FILE_ERROR = 7; // 打开文件失败 const PLAYM4_BUF_OVER = 11; // 缓存溢出 const PLAYM4_SYS_NOT_SUPPORT = 16; // 不支持 const PLAYM4_NEED_MORE_DATA = 31; // 需要更多数据才能解析 const PLAYM4_NEED_NEET_LOOP = 35; //丢帧需要下个循环 const PLAYM4_BUF_WILL_OVER = 36; //C层缓存即将满,需触发解I帧 const PLAYM4_NOT_KEYFRAME = 48; // 非关键帧 const PLAYM4_WORKER_ERROR = 60; // WORKER错误 const PLAYM4_CREATE_RENDERER_ERROR = 61; // 创建渲染句柄失败 const PLAYM4_LOAD_UNFINISHED = 62; // js文件未加载完成 const PLAYM4_GET_VOLUME_ERROR = 63; // 获取音频音量失败 const PLAYM4_ITYPE_DECODE_ERROR = 100; //定位后送进来的第一帧I帧解码失败 const PLAYM4_FIRST_FRAME_NOT_ICURRENT = 101; //定位后送进来的第一帧不是定位帧所在的I帧(Ni>Mp) // 加密类型 const SECRET_NONE = 0; // 不加密 const SECRET_AES = 1; // AES 加密 // 流模式 const STREAM_REALTIME = 0; // 实时流 const STREAM_FILE = 1; // 文件流 // 解码类型 const DECODE_ALL = 0; // 全解 const DECODE_VIDEO_KEYFRAME = 1; // 只解关键帧 // 缓存帧数 const BUFFER_MAXNUM_ONEBYONE = 15; // 帧进上限缓存数 const BUFFER_MINNUM_ONEBYONE = 8; // 帧进下限缓存数 const BUFFER_NUM_NORMAL = 1; // 正常缓存数 const BUFFER_NUM_AUDIO = 50; // 音频存储25帧播放一次 const BUFFER_MAXNUM_YUV = 5; // YUV最大缓存帧数 const YUV_SKIP_NUM = 2; // YUV跳帧间隔 // const BUFFER_NODE_NUM = 20; // 输入缓存节点数 // const BUFFER_MAX_SIZE = 800*1024; // 最大缓存 const BUFFER_MAX_SIZE = 5 * 1024 * 1024; // 最大缓存 const BUFFER_MIN_SIZE = 100;//最小缓存 const BUFFER_INPUT_SIZE = 1024*20; // 一次送入数据大小 // const BUFFER_FAST_INPUT_SIZE = 10000; // 快放一次送入数据大小 const WRITE_AUD_ENCODE_NUM = 200; //一次写编码音频帧总帧数 const WRITE_AUD_PCM_NUM = 100; //一次写PCM数据 const WRITE_VID_YUV_NUM = 20; //一次写YUV数据 const WRITE_VID_RAW_NUM = 100;//一次写裸数据 // 电子放大区域 const WRITE_RTP_NUM =200; //写RTP数据 //解码回调帧信息 var DECODE_INFO_YUV = { "width": 0, "height": 0, "frameNum": 0, "yuvData": null }; //显示回调帧信息 var DISPLAY_INFO_YUV = { "width": 0, "height": 0, "frameNum": 0, "yuvData": null }; //音频PCM回调信息 var DECODE_INFO_PCM = { "sampleRate": 0, "channel": 0, "bitsPerSample": 0, "length": 0, "pcmData": null }; // xx.js加载标识 var bAudioRenderLoad = false; var bSuperRenderLoad = false; // 回调函数参数对象 var CALLBACK_PARAMETER = { "id": null, "cmd": null, "data": null, "errorCode": 0, "status": null }; //定义类 JSPlayCtrl export class JSPlayCtrl { constructor(path, callBack, winId) { // 路径 if (path != null && path !== undefined && typeof (path) === "string") { this.szBasePath = path; } else { return PLAYM4_PARA_OVER; } // 加载回调 if (callBack && typeof (callBack) === "function") { this.fnCallBack = callBack; } else { return PLAYM4_PARA_OVER; } // 解码 Worker this.decodeWorker = null; // 开启流类型 this.streamOpenMode = null; this.bOpenStream = false; // 音频渲染 this.audioRenderer = null; this.aAudioBuffer = []; this.iAudioBufferSize = 0; this.Volume = 0; // 视频渲染库 this.oSuperRender = null; this.aVideoFrameBuffer = []; //YUV数据 this.YUVBufferSize = BUFFER_NUM_NORMAL; this.szOSDTime = null; //打印日志 //JS层log打印开关 this.bJSPrintLog = false; //下载YUV数据 this.bWriteYUVData = false; this.iYUV10size = 0;//YUV帧数 this.aVideoYUVBuffer = []; //下载PCM数据 this.bWritePCMData = false; this.iAudioBuffer500Size = 0; this.aAudioPCMBuffer = []; //下载裸数据 this.bWriteRawData = false; this.iRawDataSize = 0; this.aRawDataBuffer = []; //下载RTP数据 this.bWriteRTPData = true; this.iRTPDataSize = 0; this.aRTPDataBuffer = []; this.downloadRTP =false; this.rtpNum=0; // 播放音视频标识 this.bPlaySound = false; this.bPlay = false; this.bPause = false; this.bOnebyOne = false; this.bPlayRateChange = false; // this.bAudioTypeSupport = true; this.audioNum = 0; this.videoNum = 0; //帧进步长 this.FrameForwardLen = 1; //纯音频播放标识 this.bOnlyPlaySound = false; //是否使用裁剪宽高标识 this.bVideoCropInfo = false; // 回调函数 this.dataCallBackFun = null; // 截图回调函数 this.YUVBufSizeCBFun = null; // YUV缓存大小回调函数 this.DecCallBackFun = null;//解码回调函数 this.DisplayCallBackFun = null; //显示回调函数 this.PCMCallBackFun = null;//PCM数据回调 this.DecInfoYUV = DECODE_INFO_YUV; //解码回调数据 this.DisplayInfoYUV = DISPLAY_INFO_YUV; //显示回调数据 this.DecInfoPCM = DECODE_INFO_PCM;//音频PCM回调数据 // 图像宽高 this.nWidth = 0; this.nHeight = 0; //图像的裁剪信息 this.nSPSCropLeft=0; this.nSPSCropRight=0; this.nSPSCropTop=0; this.nSPSCropBottom=0; // 画布ID this.sCanvasId = null; // 显示图像数据缓存 this.aDisplayBuf = null; // 页面是否激活 this.bVisibility = true; // 解码类型 this.nDecFrameType = DECODE_ALL; // 电子放大 this.iCanvasWidth = 0; // canvas宽 this.iCanvasHeight = 0; // canvas高 this.iZoomNum = 0; // 放大次数 this.iRatio_x = 1; // X方向比率 this.iRatio_y = 1; // Y方向比率 this.stDisplayRect = { "top": 0, "left": 0, "right": 0, "bottom": 0 }; // 上一次电子放大区域 this.bDisRect = false; this.stYUVRect = { "top": 0, "left": 0, "right": 0, "bottom": 0 }; // 映射到YUV上区域 this.aInputDataLens = []; // 送入缓存数据长度列表 /***********性能不足解决方案************/ this.aInputDataBuffer = []; // 送入数据的缓存 this.bIsGetYUV = false; // 获取YUV数据 this.bIsFirstFrame = true; // 第一帧数据 this.iInputMaxBufSize = BUFFER_MAX_SIZE; // 输入最大缓存大小 this.bIsInput = false; // 输入数据 this.bIsInputBufOver = false; // 输入缓存溢出 this.bIsInputBufWillOver = false;//C层缓存将要溢出 this.iInputDataLen = BUFFER_INPUT_SIZE; // 输入数据长度 var that = this; // 保存this, 在onmessage回调中使用 this.errorCode = PLAYM4_OK; this.loopNum = 0; // 回调设置 this.setCallBack = function (that, cmd, data, errorCode, status) { // 回调函数参数 var callBackParameter = CALLBACK_PARAMETER; callBackParameter.id = winId; callBackParameter.cmd = cmd; callBackParameter.data = data; callBackParameter.errorCode = errorCode; callBackParameter.status = status; that.fnCallBack(callBackParameter); }; // 加载音频渲染js文件 if (!bAudioRenderLoad) { bAudioRenderLoad = true; var script_audio = document.createElement("script"); script_audio.type = "text/javascript"; script_audio.src = that.szBasePath + "AudioRenderer.js"; var head_audio = document.getElementsByTagName('head')[0]; head_audio.appendChild(script_audio); script_audio.onload = script_audio.onreadystatechange = function () { if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { if (this.bJSPrintLog) { console.log(">>>JS AudioRenderer.js load finish!"); } } }; } // 加载视频渲染js文件 if (!bSuperRenderLoad) { bSuperRenderLoad = true; var script_vedio = document.createElement("script"); script_vedio.type = "text/javascript"; script_vedio.src = that.szBasePath + "SuperRender_10.js"; var head_vedio = document.getElementsByTagName('head')[0]; head_vedio.appendChild(script_vedio); script_vedio.onload = script_vedio.onreadystatechange = function () { if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { if (this.bJSPrintLog) { console.log(">>>JS SuperRender_10.js load finish!"); } } }; } this.convertErrorCode = function (nErrorCode) { switch (nErrorCode) { case 1: return PLAYM4_OK; case 98: return PLAYM4_PARA_OVER; default: return nErrorCode; } }; // ArrayBuffer复制 this.arrayBufferCopy = function (srcArrayBuf) { var length = srcArrayBuf.byteLength; var destBuf = new Uint8Array(length); var srcBuf = new Uint8Array(srcArrayBuf); var i = 0; for (i = 0; i < length; i++) { destBuf[i] = srcBuf[i]; } return destBuf; }; // 送入数据 this.inputDataFun = function () { var aReadBuf; var aSendBuf; var iSize = 0; that.bIsGetYUV = false; // 如果解析解码缓存溢出,则停止送入数据,直到缓存空闲后继续送入 if (that.bIsInputBufOver || that.bIsInputBufWillOver) { aReadBuf = new Uint8Array(1); aSendBuf = new Uint8Array(aReadBuf); var message = {'command': "InputData", 'data': aSendBuf.buffer, 'dataSize': 0}; that.decodeWorker.postMessage(message, [message.data]); } else { if ((that.bPlay && (!that.bPause || that.bOnebyOne)) || this.bOnlyPlaySound) { //播放或单帧前进时,往worker送流 while (that.aInputDataLens.length > 0) { iSize += that.aInputDataLens.shift(); if (iSize > that.iInputDataLen) { break; } } aReadBuf = that.aInputDataBuffer.splice(0, iSize); aSendBuf = new Uint8Array(aReadBuf); var message = {'command': "InputData", 'data': aSendBuf.buffer, 'dataSize': iSize}; that.decodeWorker.postMessage(message, [message.data]); } } aReadBuf = null; aSendBuf = null; }; this.getPic = function (callBack, command) { if (this.decodeWorker == null || this.oSuperRender == null) { return PLAYM4_ORDER_ERROR; } if (!this.bPlay) { return PLAYM4_ORDER_ERROR; } if (callBack && typeof (callBack) === "function") { this.dataCallBackFun = callBack; } else { return PLAYM4_PARA_OVER; } // 映射到原图位置信息 if (0 === this.iZoomNum) { this.stYUVRect.left = 0; this.stYUVRect.top = 0; this.stYUVRect.right = 0; this.stYUVRect.bottom = 0; } else { if (0 === this.iCanvasWidth || 0 === this.iCanvasHeight) { this.stYUVRect.left = 0; this.stYUVRect.top = 0; this.stYUVRect.right = 0; this.stYUVRect.bottom = 0; } else { var ratio_x = this.nWidth / this.iCanvasWidth; var ratio_y = this.nHeight / this.iCanvasHeight; this.stYUVRect.left = Math.round(this.stDisplayRect.left * ratio_x); this.stYUVRect.top = Math.round(this.stDisplayRect.top * ratio_y); this.stYUVRect.right = Math.round(this.stDisplayRect.right * ratio_x); this.stYUVRect.bottom = Math.round(this.stDisplayRect.bottom * ratio_y); } // 宽高必须大于32 if ((this.stYUVRect.right - this.stYUVRect.left) < 32 || (this.stYUVRect.bottom - this.stYUVRect.top) < 32) { return PLAYM4_PARA_OVER; } } // 数据转换 if (this.aDisplayBuf == null) { return PLAYM4_ORDER_ERROR; } var buf = this.arrayBufferCopy(this.aDisplayBuf); // 往 Worker 送数据 var message = { 'command': command, 'data': buf.buffer, 'width': this.nWidth, 'height': this.nHeight, 'rect': this.stYUVRect }; this.decodeWorker.postMessage(message, [message.data]); return PLAYM4_OK; }; this.createWorker = function (self) { // 加载Worker if (window.Worker) { // 判断浏览器是否支持 Worker if (this.decodeWorker == null) { // 创建解码 Worker this.decodeWorker = new Worker(that.szBasePath + "DecodeWorker.js"); if (self.bJSPrintLog) { console.log(">>>JSPlayV1.1 createWorker success!"); } if (this.decodeWorker == null) { return PLAYM4_WORKER_ERROR; } } // 接收 message this.decodeWorker.onmessage = function (evt) { var typeName = null; var eventData = evt.data; switch (eventData.function) { case "printLog": console.log("print JSPlayerSDK log failed"); break; case "loaded": typeName = "loaded"; self.setCallBack(self, "loaded", 0, 0, true); break; case "SetStreamOpenMode": typeName = "SetStreamOpenMode"; break; case "OpenStream": typeName = "OpenStream"; if (1 === eventData.errorCode) { that.bOpenStream = true; return; } break; case "InputData": typeName = "InputData"; // 解析解码缓存溢出 if (eventData.errorCode === PLAYM4_BUF_OVER) { that.bIsInputBufOver = true; console.log("yff inputBuffer over set key frame \n"); if(that.nDecFrameType!= DECODE_VIDEO_KEYFRAME) { that.PlayM4_SetDecodeFrameType(DECODE_VIDEO_KEYFRAME);//本地流功能测试,很容易送流过快,导致触发解I帧 } //that.inputDataFun(); } if (eventData.errorCode === PLAYM4_BUF_WILL_OVER) { that.bIsInputBufWillOver = true; //console.log("C buffer will over, C sourceRemain:"+eventData.sourceRemain); //that.inputDataFun(); } // 解析解码缓存空闲(inputdata接口不会返回need more data) if (eventData.errorCode === PLAYM4_NEED_MORE_DATA) { //console.log(">>>JS inputdata need more data \n"); that.bIsInputBufOver = false; that.bIsInputBufWillOver = false; if (that.aInputDataLens.length > 0 && that.bIsInput) { that.inputDataFun(); that.bIsInput = false; } else { that.bIsGetYUV = true; } //console.log(">>> js inputdata need more data,aInputDataLens.length:"+that.aInputDataLens.length+" bIsGetYUV:"+that.bIsGetYUV+",bIsInput:"+that.bIsInput) } break; case "GetFrameData": typeName = "GetFrameData"; if (!that.bOnlyPlaySound) { if (eventData.data != null && eventData.frameInfo != null) { // 获取图像宽高 var width = eventData.frameInfo.width; var height = eventData.frameInfo.height; } if (!that.bPlay) { return; } that.errorCode = eventData.errorCode; //送数据策略,连续送5次后中断 if (!that.bIsFirstFrame && (eventData.errorCode === PLAYM4_NEED_MORE_DATA || eventData.errorCode === PLAYM4_NEED_NEET_LOOP)) { if(eventData.errorCode === PLAYM4_NEED_MORE_DATA) { that.bIsInputBufOver = false; that.bIsInputBufWillOver = false; } //送数据策略 if(that.loopNum > 5) { that.bIsGetYUV = true; that.loopNum =0; }else{ //setTimeout(that.inputDataFun(), 5); that.inputDataFun(); that.loopNum++;//连续送数据计数 } //console.log("loopNum:"+that.loopNum); break; }else if (that.bIsInputBufOver || that.bIsInputBufWillOver) { // 解析缓存溢出 that.inputDataFun(); } else { if (eventData.type === "videoType") { if (that.aInputDataLens.length > 0 && that.bIsInput) { that.inputDataFun(); that.bIsInput = false; } else { that.bIsGetYUV = true; } that.bIsFirstFrame = false; } } } // web页面激活时才缓存音视频数据 if (that.bVisibility) { if (PLAYM4_OK === eventData.errorCode) { switch (eventData.type) { case "videoType": if (eventData.data == null || eventData.frameInfo == null) { return PLAYM4_PARA_OVER; } //显示回调 if (that.DecCallBackFun != null) { that.DecInfoYUV.height = eventData.frameInfo.height; that.DecInfoYUV.width = eventData.frameInfo.width; that.DecInfoYUV.frameNum = eventData.frameInfo.frameNum; that.DecInfoYUV.yuvData = new Uint8Array(eventData.data); that.DecCallBackFun(that.DecInfoYUV) } that.bIsFirstFrame = false; //处理视频数据 self.nWidth = eventData.frameInfo.width; self.nHeight = eventData.frameInfo.height; self.nSPSCropLeft=eventData.frameInfo.cropLeft; self.nSPSCropRight=eventData.frameInfo.cropRight; self.nSPSCropTop=eventData.frameInfo.cropTop; self.nSPSCropBottom=eventData.frameInfo.cropBottom; var oVideoFrameInfo = new Object(); oVideoFrameInfo.data = eventData.data; oVideoFrameInfo.osdTime = eventData.osd; oVideoFrameInfo.nWidth = eventData.frameInfo.width; oVideoFrameInfo.nHeight = eventData.frameInfo.height; oVideoFrameInfo.frameNum = eventData.frameInfo.frameNum; oVideoFrameInfo.timeStamp = eventData.frameInfo.timeStamp; //打印10帧YUV视频 if (self.bWriteYUVData) { var bufferPackage = new Uint8Array(eventData.data); var iIndexBuffer = self.aVideoYUVBuffer.length; for (var i = 0, iLen = bufferPackage.length; i < iLen; i++) { self.aVideoYUVBuffer[iIndexBuffer + i] = bufferPackage[i]; } self.iYUV10size++; bufferPackage = null; } if (self.bWriteYUVData && self.iYUV10size >= WRITE_VID_YUV_NUM) { var YUVbuffer = new Uint8Array(self.aVideoYUVBuffer); self.downloadFile(YUVbuffer, "videoYUV.data"); self.aVideoYUVBuffer.splice(0, self.aVideoYUVBuffer.length);//清空PCM缓存 self.bWriteYUVData = false; self.iYUV10size = 0; YUVbuffer = null; } /*******打印结束*****/ self.aVideoFrameBuffer.push(oVideoFrameInfo); oVideoFrameInfo = null; // 如果YUV缓存大于阈值时进行抽帧显示,防止内存快速增长导致浏览器崩溃 var iYUVNum = self.aVideoFrameBuffer.length; if (iYUVNum > BUFFER_MAXNUM_YUV) { // 非单帧模式下进行该处理 // YUV缓存超过BUFFER_MAXNUM_YUV个节点后隔YUV_SKIP_NUM个帧播一帧 if (!self.bOnebyOne) { self.aVideoFrameBuffer.splice(0, YUV_SKIP_NUM); } } // 单帧 if (self.bOnebyOne) { // 缓存满,通知上层停止送流 if (self.aVideoFrameBuffer.length >= BUFFER_MAXNUM_ONEBYONE) { self.setCallBack(self, "OnebyOne", 0, 0, false); // 下次直接从缓存读取数据 self.bIsFirstFrame = true; break; } } break; case "audioType": if ((self.bPlaySound && !self.bPlayRateChange) || that.bOnlyPlaySound) { //音频PCM回调 if (that.PCMCallBackFun != null) { that.DecInfoPCM.sampleRate = eventData.frameInfo.samplesPerSec; that.DecInfoPCM.channel = eventData.frameInfo.channels; that.DecInfoPCM.bitsPerSample = eventData.frameInfo.bitsPerSample; that.DecInfoPCM.pcmData = new Uint8Array(eventData.data); that.DecInfoPCM.length = that.DecInfoPCM.pcmData.length; that.PCMCallBackFun(that.DecInfoPCM) } //处理音频数据 var bufferPackage = new Uint8Array(eventData.data); var iIndexBuffer = self.aAudioBuffer.length; for (var i = 0, iLen = bufferPackage.length; i < iLen; i++) { self.aAudioBuffer[iIndexBuffer + i] = bufferPackage[i]; } self.iAudioBufferSize++; bufferPackage = null; //打印10帧PCM音频 if (self.bWritePCMData) { var bufferPackage = new Uint8Array(eventData.data); var iIndexBuffer = self.aAudioPCMBuffer.length; for (var i = 0, iLen = bufferPackage.length; i < iLen; i++) { self.aAudioPCMBuffer[iIndexBuffer + i] = bufferPackage[i]; } console.log("audio_type num:"+self.iAudioBuffer500Size+", len:"+bufferPackage.length); self.iAudioBuffer500Size++; bufferPackage = null; } if (self.bWritePCMData && self.iAudioBuffer500Size >= WRITE_AUD_PCM_NUM) { var PCMbuffer = new Uint8Array(self.aAudioPCMBuffer); self.downloadFile(PCMbuffer, "audioPCM.data"); self.aAudioPCMBuffer.splice(0, self.aAudioPCMBuffer.length);//清空PCM缓存 self.bWritePCMData = false; self.iAudioBuffer500Size = 0; PCMbuffer = null; } /********打印结束*****/ // 储存25帧播放一次 if (self.iAudioBufferSize >= BUFFER_NUM_AUDIO) { // 播放 self.audioRenderer.Play(self.aAudioBuffer, self.aAudioBuffer.length, eventData.frameInfo); self.aAudioBuffer.splice(0, self.aAudioBuffer.length); self.aAudioBuffer.length = 0; self.iAudioBufferSize = 0; } } break; case "privateType": break; default: break; } } } break; case "GetRawData": typeName = "GetRawData"; /********打印10帧裸数据*****/ if (self.bWriteRawData) { var bufferRawPackage = new Uint8Array(eventData.data); var iIndexRawBuffer = self.aRawDataBuffer.length; for (var i = 0, iLen = bufferRawPackage.length; i < iLen; i++) { self.aRawDataBuffer[iIndexRawBuffer + i] = bufferRawPackage[i]; } self.iRawDataSize++; bufferRawPackage = null; } if (self.bWriteRawData && self.iRawDataSize >= WRITE_VID_RAW_NUM) { var RAWbuffer = new Uint8Array(self.aRawDataBuffer); self.downloadFile(RAWbuffer, "rawBuffer.data"); self.aRawDataBuffer.splice(0, self.aRawDataBuffer.length);//清空PCM缓存 self.bWriteRawData = false; self.iRawDataSize = 0; RAWbuffer = null; } /********打印结束*****/ break; case "PlaySound": typeName = "PlaySound"; break; case "GetJPEG": typeName = "GetJPEG"; if (eventData.errorCode !== PLAYM4_OK) { console.log("GetJPEG ErrorParam"); return; } // 获取图像宽高 var pJpegData = eventData.data; self.dataCallBackFun(pJpegData); break; case "GetBMP": typeName = "GetBMP"; if (eventData.errorCode !== PLAYM4_OK) { console.log("GetBMP ErrorParam"); return; } // 获取图像宽高 var pBmpData = eventData.data; self.dataCallBackFun(pBmpData); break; default: break; } //如果返回错误码该如何处理 // 回调方式返回错误码 if ("GetFrameData" !== typeName) { self.setCallBack(self, typeName, 0, self.convertErrorCode(eventData.errorCode), true); } else { if (PLAYM4_SYS_NOT_SUPPORT === eventData.errorCode || PLAYM4_FIRST_FRAME_NOT_ICURRENT === eventData.errorCode || PLAYM4_ITYPE_DECODE_ERROR === eventData.errorCode || PLAYM4_NOT_KEYFRAME === eventData.errorCode) { self.setCallBack(self, typeName, 0, self.convertErrorCode(eventData.errorCode), true); } } }; } }; this.createWorker(that); // 视频渲染 this.draw = function () { if (that.bPlay) { if (!that.bPause || that.bOnebyOne) { // that.bPause:true 暂停 requestAnimationFrame(that.draw); var iYUVNum = that.aVideoFrameBuffer.length; if (that.YUVBufSizeCBFun != null) { that.YUVBufSizeCBFun(iYUVNum); } if (that.bOnebyOne) { // 缓存不够,通知上层开始送流 if (iYUVNum <= BUFFER_MINNUM_ONEBYONE) { that.setCallBack(that, "OnebyOne", 0, PLAYM4_NEED_MORE_DATA, true); } if (iYUVNum <= that.FrameForwardLen + 1) { that.setCallBack(that, "OnebyOne", 0, PLAYM4_NEED_MORE_DATA, true); return; } else { var frameForwardLen = that.FrameForwardLen; while (frameForwardLen > 1) { var framevuffer = that.aVideoFrameBuffer.shift(); frameForwardLen--; } } that.bOnebyOne = false; } if (iYUVNum > 0) { var oVideoFrameInfo = that.aVideoFrameBuffer.shift(); that.aDisplayBuf = oVideoFrameInfo.data; var displayBuf = new Uint8Array(that.aDisplayBuf); if(that.bVideoCropInfo) { that.oSuperRender.SR_DisplayFrameData(oVideoFrameInfo.nWidth, oVideoFrameInfo.nHeight, displayBuf,oVideoFrameInfo.nWidth- that.nSPSCropLeft - that.nSPSCropRight,oVideoFrameInfo.nHeight- that.nSPSCropTop - that.nSPSCropBottom); } else { that.oSuperRender.SR_DisplayFrameData(oVideoFrameInfo.nWidth, oVideoFrameInfo.nHeight, displayBuf,oVideoFrameInfo.nWidth,oVideoFrameInfo.nHeight); } if (that.DisplayCallBackFun != null) { that.DisplayInfoYUV.height = oVideoFrameInfo.nHeight; that.DisplayInfoYUV.width = oVideoFrameInfo.nWidth; that.DisplayInfoYUV.frameNum = oVideoFrameInfo.frameNum; that.DisplayInfoYUV.yuvData = new Uint8Array(displayBuf); that.DisplayCallBackFun(that.DisplayInfoYUV) } displayBuf = null; // 当前OSD时间 that.szOSDTime = oVideoFrameInfo.osdTime; oVideoFrameInfo = null; } else { that.setCallBack(that, "Play", 0, PLAYM4_NEED_MORE_DATA, true); } } } else { if (!that.bPlay) { // 停止播放清空视频帧和音频帧数据缓存 that.aVideoFrameBuffer.splice(0, that.aVideoFrameBuffer.length); that.aAudioBuffer.splice(0, that.aAudioBuffer.length); } } }; } /** * @synopsis 根据帧号进行精确定位 * @param nFrameNum [IN] 定位帧号 * @param playType [IN] 定位后是否继续播放。true为继续播放,false为暂停播放 */ PlayM4_SetCurrentFrameNum(nFrameNum, playType) { return PLAYM4_SYS_NOT_SUPPORT; } /** * @synopsis 播放库打印日志开关 * @param downloadFlag [IN] true为打开日志,false为关闭日志 * @returns 返回错误码 */ PlayM4_OpenPlayerSDKPrintLog(downloadFlag) { if (downloadFlag === true) { this.bJSPrintLog = true; this.decodeWorker.postMessage({'command': "printLog", 'data': downloadFlag}); } else { this.bJSPrintLog = false; this.decodeWorker.postMessage({'command': "printLog", 'data': downloadFlag}); } return PLAYM4_OK; } /** * @synopsis 下载YUV数据开关 */ PlayM4_DownloadYUVdata() { this.bWriteYUVData = true; return PLAYM4_OK; } /** * @synopsis 下载PCM数据开关 */ PlayM4_DownloadPCMdata() { this.bWritePCMData = true; return PLAYM4_OK; } /** * @synopsis 设置解码回调 * @param DecCBFun [IN] 解码回调函数 * @returns 返回错误码 */ PlayM4_SetDecCallBack(DecCBFun) { if (DecCBFun && typeof (DecCBFun) === "function") { this.DecCallBackFun = DecCBFun; return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 设置显示回调 * @param DecCBFun [IN] 显示回调函数 * @returns 返回错误码 */ PlayM4_SetDisplayCallBack(DisplayCBFun) { if (DisplayCBFun && typeof (DisplayCBFun) === "function") { this.DisplayCallBackFun = DisplayCBFun; return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 设置音频PCM数据回调 * @param DecCBFun [IN] 音频回调函数 * @returns 返回错误码 */ PlayM4_SetPCMCallBack(PCMCBFun) { if (PCMCBFun && typeof (PCMCBFun) === "function") { this.PCMCallBackFun = PCMCBFun; return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 设置开启流播放模式 * * @param nMode [IN] 打开方式 * * @returns 状态码 */ PlayM4_SetStreamOpenMode(nMode) { if (nMode == null || nMode === undefined) { return PLAYM4_PARA_OVER; } if (nMode !== STREAM_REALTIME && nMode !== STREAM_FILE) { return PLAYM4_PARA_OVER; } this.streamOpenMode = nMode; return PLAYM4_OK; } PlayM4_DownloadRTPData(downloadFlag) { this.downloadRTP=downloadFlag; } PlayM4_SetVideoCropInfo(nFlag) { if (nFlag == null || nFlag === undefined) { return PLAYM4_PARA_OVER; } if (typeof (nFlag) !== "boolean") { return PLAYM4_PARA_OVER; } this.bVideoCropInfo = nFlag; return PLAYM4_OK; } /** * @synopsis 实时流、回放流时字节头开流 * * @param pFileHeadBuf 文件头缓存数据 * @param nSize 文件头缓存大小 * @param nBufPoolSize 流缓存大小 * * @returns 状态码 */ PlayM4_OpenStream(pFileHeadBuf, nSize, nBufPoolSize) { if (this.bJSPrintLog) { console.log(">>>JS PlayM4_OpenStream nSysTime:" + (new Date().getMonth() + 1) + "-" + new Date().getDate() + " " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds() + "." + new Date().getMilliseconds()); } if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if(this.downloadRTP) { var apRTPHeadData = new Uint8Array(pFileHeadBuf.buffer); this.DownloadRTPData(apRTPHeadData); console.log("write 40 hik head"); } if (pFileHeadBuf == null || nSize <= 0 || nBufPoolSize <= 0) { return PLAYM4_PARA_OVER; } // 单帧后恢复回放,清除状态值 this.bPlay = false; this.bPause = false; this.bOnebyOne = false; this.bIsFirstFrame = true; this.bIsGetYUV = false; this.bIsInput = false; // 往 Worker 送数据 this.decodeWorker.postMessage({'command': "SetStreamOpenMode", 'data': this.streamOpenMode}); // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "OpenStream", 'data': pFileHeadBuf, 'dataSize': nSize, 'bufPoolSize': nBufPoolSize }); this.bOpenStream = true; return PLAYM4_OK; } /** * @synopsis 关闭流 * * @returns 状态码 */ PlayM4_CloseStream() { if (this.decodeWorker === null || this.bOpenStream === false) { return PLAYM4_ORDER_ERROR; } this.bOnlyPlaySound = false; this.PlayM4_Stop(); // 往 Worker 送数据 this.decodeWorker.postMessage({'command': "CloseStream"}); if (this.oSuperRender !== null) { // 释放渲染资源 this.oSuperRender.SR_Destroy(); this.oSuperRender = null; } if (this.audioRenderer !== null) { // 释放渲染资源 this.audioRenderer.Stop(); this.audioRenderer = null; } // 清空缓存 this.aAudioBuffer.splice(0, this.aAudioBuffer.length); this.aVideoFrameBuffer.splice(0, this.aVideoFrameBuffer.length); this.aInputDataBuffer.splice(0, this.aInputDataBuffer.length); this.aInputDataLens.splice(0, this.aInputDataLens.length); this.aVideoYUVBuffer.splice(0, this.aVideoYUVBuffer.length); this.aAudioPCMBuffer.splice(0, this.aAudioPCMBuffer.length); this.aRawDataBuffer.splice(0, this.aRawDataBuffer.length); this.bOpenStream = false; this.iAudioBufferSize = 0; this.szOSDTime = null; return PLAYM4_OK; } /** * @synopsis 销毁,关闭worker * * @returns 状态码 */ PlayM4_Destroy() { if (this.decodeWorker === null) { return PLAYM4_OK; } this.PlayM4_CloseStream(); this.decodeWorker.terminate(); // 停止 Worker 工作 this.decodeWorker = null; return PLAYM4_OK; } /** * @synopsis 实时流、回放流送数据 * * @param dataBuf [IN] 输入数据缓存 * @param nSize [IN] 输入数据大小 * * @returns 状态码 */ PlayM4_InputData(dataBuf, nSize) { //if (this.decodeWorker === null || this.bOpenStream === false) { // return PLAYM4_ORDER_ERROR; // } //console.log(">>>JSPlaySDKInterface.js PlayM4_InputData nSize:"+nSize+",bIsGetYUV:"+this.bIsGetYUV+",bIsInput:"+this.bIsInput); var iInputBufLen = this.aInputDataBuffer.length; // 结束送流标识位[0x01, 0x02, 0x03, 0x04] if (nSize === 4) { var aBuf = new Uint8Array(dataBuf.buffer); if (aBuf[0] === 0x01 && aBuf[1] === 0x02 && aBuf[2] === 0x03 && aBuf[3] === 0x04) { if (this.bIsFirstFrame) { // 直接往 Worker 送数据 this.inputDataFun(); } else { if (this.bIsGetYUV) { this.inputDataFun(); } else { this.bIsInput = true; } } aBuf = null; return PLAYM4_OK; } } // 超出设置的缓存阈值,返回错误码(缓存溢出) if (iInputBufLen + nSize > this.iInputMaxBufSize) { console.log("input over"); //this.inputDataFun(); if (this.bIsGetYUV) { this.inputDataFun(); } else { this.bIsInput = true; } return PLAYM4_BUF_OVER; } // 写入缓存,添加4字节头 var tempBuf = null; var iDataLen = nSize; switch (this.streamOpenMode) { case STREAM_FILE: tempBuf = new Uint8Array(dataBuf.buffer); if(this.downloadRTP) { this.DownloadRTPData(tempBuf); this.rtpNum++; console.log("STREAM_FILE psNUm:"+this.rtpNum); } this.aInputDataLens.push(nSize); break; case STREAM_REALTIME: // 加4字节长度信息 iDataLen = nSize + 4; var a32 = new Uint32Array([nSize]); var a8 = new Uint8Array(a32.buffer); tempBuf = new Uint8Array(iDataLen); tempBuf.set(a8, 0); tempBuf.set(dataBuf, 4); if(this.downloadRTP) { this.DownloadRTPData(tempBuf); this.rtpNum++; console.log("STREAM_REALTIME rtpNUm:"+this.rtpNum); } a32 = null; a8 = null; this.aInputDataLens.push(nSize + 4); break; default: return PLAYM4_SYS_NOT_SUPPORT; } for (var i = 0; i < iDataLen; i++) { this.aInputDataBuffer[iInputBufLen + i] = tempBuf[i]; } if((!this.bPlay&&!this.bOnlyPlaySound) || this.decodeWorker === null || this.bOpenStream === false) { return PLAYM4_OK; } tempBuf = null; if (this.bOnlyPlaySound) { //直接送音频帧,一个RTP包一个音频帧 this.inputDataFun(); } else { if (this.bIsFirstFrame) { // 首帧直接往 Worker 送数据 this.inputDataFun(); } else { if (this.bIsGetYUV) { this.inputDataFun(); } else { this.bIsInput = true; } } } return PLAYM4_OK; } DownloadRTPData(rtpData) { if (this.bWriteRTPData) { var bufferPackage = new Uint8Array(rtpData); var iIndexBuffer = this.aRTPDataBuffer.length; for (var i = 0, iLen = bufferPackage.length; i < iLen; i++) { this.aRTPDataBuffer[iIndexBuffer + i] = bufferPackage[i]; } this.iRTPDataSize++; bufferPackage = null; } if (this.bWriteRTPData && this.iRTPDataSize >= WRITE_RTP_NUM) { console.log("download"+WRITE_RTP_NUM+"RTPdata"); var RTPbuffer = new Uint8Array(this.aRTPDataBuffer); this.downloadFile(RTPbuffer, "RTP.data"); this.aRTPDataBuffer.splice(0, this.aRTPDataBuffer.length);//清空YUV缓存 //this.bWriteRTPData = false; 应注释,修复再次调用无法下载数据的问题 this.iRTPDataSize = 0; this.rtpNum=0; this.downloadRTP=false; RTPbuffer = null; } } /** * @synopsis 开启播放 * * @param canvasID [IN] 窗口id * * @returns 状态码 */ PlayM4_Play(canvasID) { if (this.decodeWorker === null) { return PLAYM4_ORDER_ERROR; } //canvasID传入为null,则表示只送入纯音频js播放库进行播放 if (this.bJSPrintLog) { console.log(">>>JS PlayM4_Play canvasID: " + canvasID); } if (canvasID === null) { //console.log(">>>>>>>>> PlayM4_Play 2-1 nSysTime:" + (new Date().getMonth()+1) + "-" + new Date().getDate() + " " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds() + "." + new Date().getMilliseconds()); this.bOnlyPlaySound = true; //console.log("fzj---------------------------------true"); // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "OnlyPlaySound" }); this.sCanvasId = null; } else { if (typeof (canvasID) !== "string") { return PLAYM4_PARA_OVER; } if (this.bOnebyOne) { this.bPlayRateChange = false; this.bOnebyOne = false; this.bPause = false; this.draw(); } if (this.bPlay) { return PLAYM4_OK; } // 创建视频渲染句柄 if (this.oSuperRender == null) { this.oSuperRender = new SuperRender(canvasID, this.szBasePath); if (this.oSuperRender == null) { return PLAYM4_CREATE_RENDERER_ERROR; } } this.sCanvasId = canvasID; // 初始化 this.bPlay = true; this.bPause = false; this.bOnebyOne = false; // 关闭声音 // this.bPlaySound = false; this.bPlayRateChange = false; this.bOnlyPlaySound = false; this.draw(); //console.log(">>>>>>>>> PlayM4_Play 2-2 nSysTime:" + (new Date().getMonth()+1) + "-" + new Date().getDate() + " " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds() + "." + new Date().getMilliseconds()); } // 创建音频渲染句柄 if (this.audioRenderer == null) { this.audioRenderer = new AudioRenderer(); if (this.audioRenderer == null) { return PLAYM4_CREATE_RENDERER_ERROR; } } this.decodeWorker.postMessage({ 'command': "Play" }); //console.log(">>>>>>>>> PlayM4_Play 3 nSysTime:" + (new Date().getMonth()+1) + "-" + new Date().getDate() + " " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds() + "." + new Date().getMilliseconds()); return PLAYM4_OK; } /** * @synopsis 停止播放 * * @returns 状态码 */ PlayM4_Stop() { if (this.decodeWorker == null || this.oSuperRender == null) { return PLAYM4_ORDER_ERROR; } if (!this.bPlay) { return PLAYM4_ORDER_ERROR; } // 关闭声音 if (this.bPlaySound) { this.PlayM4_StopSound(); this.bPlaySound = true; } this.bPlay = false; this.bOnebyOne = false; this.bPause = false; // 关闭电子放大 this.oSuperRender.SR_SetDisplayRect(null); this.iZoomNum = 0; this.bDisRect = false; // 画布置黑 if(this.bVideoCropInfo) { this.oSuperRender.SR_DisplayFrameData(this.nWidth, this.nHeight, null,this.nWidth- this.nSPSCropLeft - this.nSPSCropRight,this.nHeight- this.nSPSCropTop - this.nSPSCropBottom); } else { this.oSuperRender.SR_DisplayFrameData(this.nWidth, this.nHeight, null,this.nWidth,this.nHeight); } // let oldCanvas = document.getElementById(this.sCanvasId); // if (oldCanvas) { // this.clonedCanvas = oldCanvas.cloneNode(true); // 克隆节点 // this.clonedCanvasParentNode = oldCanvas.parentNode; // oldCanvas.parentNode.removeChild(oldCanvas); // this.clonedCanvasParentNode.replaceChild(this.clonedCanvas, oldCanvas); // } return PLAYM4_OK; } /** * @synopsis 播放速率 * * @param nPlayRate [IN] 倍率 * * @returns 状态码 */ PlayM4_PlayRate(nPlayRate) { if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if (nPlayRate === 1) { this.bPlayRateChange = false; } else { this.bPlayRateChange = true; } if (nPlayRate < 1) { nPlayRate = 1; } this.iInputDataLen = nPlayRate * BUFFER_INPUT_SIZE; this.decodeWorker.postMessage({ 'command': "PlayRate", 'playRate':nPlayRate }); return PLAYM4_OK; } /** * @synopsis 暂停播放 * * @param pause [IN] 暂停/恢复标识 * * @returns 状态码 */ PlayM4_Pause(pause) { if (this.decodeWorker == null || this.oSuperRender == null) { return PLAYM4_ORDER_ERROR; } if (!this.bPlay) { return PLAYM4_ORDER_ERROR; } if (this.bOnebyOne) { return PLAYM4_ORDER_ERROR; } if (this.bPause == pause) { return PLAYM4_ORDER_ERROR; } if (typeof (pause) !== "boolean") { return PLAYM4_PARA_OVER; } this.bPause = pause; // this.bOnebyOne = false; // 下次直接从缓存读取数据 this.bIsFirstFrame = true; if (pause) { if (this.bPlaySound) { this.PlayM4_StopSound(); this.bPlaySound = true; } } else { if (this.bPlaySound) { this.PlayM4_PlaySound(); } this.draw(); } return PLAYM4_OK; } /** * @synopsis 帧进 * * @returns 状态码 */ PlayM4_OneByOne(stepLength) { if (this.decodeWorker == null || this.oSuperRender == null) { return PLAYM4_ORDER_ERROR; } if (!this.bPlay) { return PLAYM4_ORDER_ERROR; } if (stepLength > 10 || stepLength <= 0) { return PLAYM4_PARA_OVER; } if (!stepLength) { stepLength = 1; } this.iInputDataLen = BUFFER_INPUT_SIZE; this.FrameForwardLen = stepLength; this.bPause = true; this.bOnebyOne = true; //this.bPlaySound = false; // 单帧模式下关闭声音 //this.bPlayRateChange = true; this.bIsFirstFrame = true; this.draw(); return PLAYM4_OK; } /** * @synopsis 开启声音 * * @param iWndNum [IN] 窗口号 * * @returns 状态码 */ PlayM4_PlaySound(iWndNum) { if (this.decodeWorker === null || this.bOpenStream === false) { return PLAYM4_ORDER_ERROR; } // // 判断音频格式是否支持,如果不支持返回状态码 // if (!this.bAudioTypeSupport) { // return PLAYM4_SYS_NOT_SUPPORT; // } // 最大支持16路 if (iWndNum < 0 || iWndNum > 16) { return PLAYM4_PARA_OVER; } // 创建音频渲染句柄 if (this.audioRenderer == null) { this.audioRenderer = new AudioRenderer(); if (this.audioRenderer == null) { return PLAYM4_CREATE_RENDERER_ERROR; } } // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "PlaySound" }); // 设置当前窗口号 this.audioRenderer.SetWndNum(iWndNum); if(this.Volume !== 0) { this.audioRenderer.SetVolume(this.Volume); } this.audioRenderer.oAudioContext.resume(); this.bPlaySound = true; return PLAYM4_OK; } /** * @synopsis 关闭声音 * * @returns */ PlayM4_StopSound() { if (this.decodeWorker == null || this.audioRenderer == null) { return PLAYM4_ORDER_ERROR; } if (!this.bPlaySound) { return PLAYM4_ORDER_ERROR; } this.decodeWorker.postMessage({ 'command': "StopSound" }); this.bPlaySound = false; return PLAYM4_OK; } /** * @synopsis 设置解码后缓存 * * @param nNum [IN] 显示缓存节点数 * * @returns 状态码 */ PlayM4_SetDisplayBuf(nNum) { if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if (nNum <= 0) { return PLAYM4_PARA_OVER; } this.YUVBufferSize = nNum; return PLAYM4_OK; } /** * @synopsis 设置解密秘钥 * * @param nKeyType [IN] 密钥类型 * @param pSecretKey [IN] 密钥缓存 * @param nKeyLen [IN] 密钥缓存大小 * * @returns 状态码 */ PlayM4_SetSecretKey(nKeyType, pSecretKey, nKeyLen) { if (this.decodeWorker == null || this.bOpenStream === false) { return PLAYM4_ORDER_ERROR; } if (pSecretKey == null) { return PLAYM4_PARA_OVER; } if (SECRET_AES === nKeyType) { if (128 === nKeyLen) { if (pSecretKey == null || pSecretKey === undefined) { return PLAYM4_PARA_OVER; } } else { return PLAYM4_PARA_OVER; } } else if (SECRET_NONE === nKeyType) { } else { return PLAYM4_PARA_OVER; } // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "SetSecretKey", 'data': pSecretKey, 'nKeyType': nKeyType, 'nKeyLen': nKeyLen }); return PLAYM4_OK; } /** * @synopsis 设置要解码的帧类型.默认正常解码,当前只支持全解和只解码I帧 * * @param nFrameType [IN] 帧类型 * * @returns 状态码 */ PlayM4_SetDecodeFrameType(nFrameType) { console.log("PlayM4_SetDecodeFrameType nFrameType:"+nFrameType); if (this.decodeWorker == null || this.oSuperRender == null) { return PLAYM4_ORDER_ERROR; } if (nFrameType !== DECODE_ALL && nFrameType !== DECODE_VIDEO_KEYFRAME) { return PLAYM4_PARA_OVER; } if (this.bJSPrintLog) { console.log(">>>JS PlayM4_SetDecodeFrameType :"+nFrameType); } this.nDecFrameType = nFrameType; // 往 Worker 送数据 this.decodeWorker.postMessage({'command': "SetDecodeFrameType", 'data': nFrameType}); return PLAYM4_OK; } /** * @synopsis 设置跳I帧间隔(调用前需要设置 setDecodeFrameType(1)只解关键帧,否则返回错误码 2) * * @param nInterval [IN] 跳I帧间隔 * * @returns 状态码 */ PlayM4_SetIFrameDecInterval(nInterval) { if (this.nDecFrameType !== DECODE_VIDEO_KEYFRAME) { return PLAYM4_ORDER_ERROR; } if (nInterval < 0) { return PLAYM4_PARA_OVER; } // 往 Worker 送数据 this.decodeWorker.postMessage({'command': "SetIFrameDecInterval", 'data': nInterval}); return PLAYM4_OK; } /** * @synopsis 设置丢帧模式 * * @param nInterval [IN] 丢帧模式 * * @returns 状态码 */ PlayM4_SetLostFrameMode(nLostMode) { if (nLostMode < 0 || nLostMode > 1) { return PLAYM4_PARA_OVER; } // 往 Worker 送数据 this.decodeWorker.postMessage({'command': "SetLostFrameMode", 'data': nLostMode}); return PLAYM4_OK; } /** * @synopsis 电子放大 * * @param diplayRect [IN] 显示区域 * @param bEnable [IN] 是否显示 * * @returns 状态码 */ PlayM4_SetDisplayRegion(diplayRect, bEnable) { if (this.decodeWorker === null || this.bPlay === false || this.oSuperRender === null) { return PLAYM4_ORDER_ERROR; } if (this.canvasId === null) { return PLAYM4_ORDER_ERROR; } if (bEnable === true) { if (diplayRect === null || diplayRect === undefined) { return PLAYM4_PARA_OVER; } // 判断放大区域参数 if (typeof diplayRect.left === "number" && typeof diplayRect.top === "number" && typeof diplayRect.right === "number" && typeof diplayRect.bottom === "number") { if (diplayRect.right < 0 || diplayRect.left < 0 || diplayRect.top < 0 || diplayRect.bottom < 0) { return PLAYM4_PARA_OVER; } var iLeft = diplayRect.left; var iRight = diplayRect.right; var iTop = diplayRect.top; var iBottom = diplayRect.bottom; // 获取画布大小 var oRect = document.getElementById(this.sCanvasId).getBoundingClientRect(); this.iCanvasWidth = oRect.width; this.iCanvasHeight = oRect.height; /*区域宽高必须不小于16且不大于图像宽高*/ /*modify.2018.7.6经过测试区域宽高可以大于分辨率*/ if (iRight - iLeft < 16 || iBottom - iTop < 16 || iRight - iLeft > this.iCanvasWidth || iBottom - iTop > this.iCanvasHeight) { return PLAYM4_PARA_OVER; } // 获取画布大小 /*var oRect = document.getElementById(this.sCanvasId).getBoundingClientRect(); this.iCanvasWidth = oRect.width; this.iCanvasHeight = oRect.height;*/ if (this.iZoomNum !== 0) { iLeft = Math.round(iLeft / this.iRatio_x) + this.stDisplayRect.left; iTop = Math.round(iTop / this.iRatio_y) + this.stDisplayRect.top; iRight = Math.round(iRight / this.iRatio_x) + this.stDisplayRect.left; iBottom = Math.round(iBottom / this.iRatio_y) + this.stDisplayRect.top; } // 电子放大 this.stDisplayRect = { "top": iTop, "left": iLeft, "right": iRight, "bottom": iBottom }; // 开启电子放大 this.oSuperRender.SR_SetDisplayRect(this.stDisplayRect); this.bDisRect = true; // 电子放大选择区域大小 var nCropWidth = iRight - iLeft; var nCropHeight = iBottom - iTop; // 计算放大比率 this.iRatio_x = this.iCanvasWidth / nCropWidth; this.iRatio_y = this.iCanvasHeight / nCropHeight; // this.iZoomNum++; } else { return PLAYM4_PARA_OVER; } } else { // 关闭电子放大 this.oSuperRender.SR_SetDisplayRect(null); this.iZoomNum = 0; this.bDisRect = false; } // 如果暂停、单帧、快慢放情况,电子放大后需要刷新一帧 if (this.bPause || this.bOnebyOne || this.bPlayRateChange) { if(this.bVideoCropInfo) { this.oSuperRender.SR_DisplayFrameData(this.nWidth, this.nHeight, (new Uint8Array(this.aDisplayBuf)),this.nWidth- this.nSPSCropLeft - this.nSPSCropRight,this.nHeight- this.nSPSCropTop - this.nSPSCropBottom);} else { this.oSuperRender.SR_DisplayFrameData(this.nWidth, this.nHeight, (new Uint8Array(this.aDisplayBuf)),this.nWidth,this.nHeight); } } return PLAYM4_OK; } /** * @synopsis 抓取BMP图 * * @param callBack [IN] 数据回调函数 * * @returns 状态码 */ PlayM4_GetBMP(callBack) { return this.getPic(callBack, "GetBMP"); } /** * @synopsis 抓取JPEG图 * * @param callBack [IN] 数据回调函数 * * @returns 状态码 */ PlayM4_GetJPEG(callBack) { return this.getPic(callBack, "GetJPEG"); } /** * @synopsis 设置音量 * * @param volume [IN] 音量 * * @returns 状态码 */ PlayM4_SetVolume(volume) { if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if (this.audioRenderer == null) { return PLAYM4_ORDER_ERROR; } //增加volume === ""兼容框内容什么都不填的情况 if (volume < 0 || volume > 100 || volume === "") { return PLAYM4_PARA_OVER; } //保存音量 this.Volume = volume; this.audioRenderer.SetVolume(volume); return PLAYM4_OK; } /** * @synopsis 获取音量 * * @param callBack [IN] 音量回调函数 * * @returns 状态码 */ PlayM4_GetVolume(callBack) { if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if (this.audioRenderer == null) { return PLAYM4_ORDER_ERROR; } if (callBack && typeof (callBack) === "function") { var volume = this.audioRenderer.GetVolume(); if (volume === null) { return PLAYM4_GET_VOLUME_ERROR; } else { //修改逻辑解决设置获取音量不一致的问题 callBack(volume); return PLAYM4_OK; } } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 获取OSD时间信息 * * @param callBack [IN] 获取OSD时间信息回调函数 * * @returns 状态码 */ PlayM4_GetOSDTime(callBack) { if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if (!this.bPlay) { return PLAYM4_ORDER_ERROR; } if (callBack && typeof (callBack) === "function") { callBack(this.szOSDTime); return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 当前页面状态 * * @param visibility [IN] 页面状态 * * @returns 状态码 */ PlayM4_IsVisible(visibility) { this.bVisibility = visibility; return PLAYM4_OK; } /** * @synopsis 获取SDK版本信息 * * @returns 状态码 */ PlayM4_GetSdkVersion() { return "070400003"; } /** * @synopsis 获取build日期 * * @returns 状态码 */ PlayM4_GetBuildDate() { return "20221121"; } /** * @synopsis 获取输入缓存大小 * * @returns 返回输入缓存大小 */ PlayM4_GetInputBufSize() { return this.aInputDataBuffer.length; } /** * @synopsis 设置输入缓存大小 * * @returns 设置输入缓存大小 */ PlayM4_SetInputBufSize(iInputBufSize) { if (iInputBufSize > 0) { this.iInputMaxBufSize = iInputBufSize; console.log(">>JSBufferSize SetInputBufSize:"+this.iInputMaxBufSize); return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 获取YUV缓存大小 * * @returns 返回YUV缓存大小 */ PlayM4_GetYUVBufSize() { return this.aVideoFrameBuffer.length; } /** * @synopsis 获取一帧图像分辨率 * * @param callBack [IN] 获取一帧图像分辨率回调函数 * * @returns 状态码 */ PlayM4_GetFrameResolution(callBack) { if (this.decodeWorker == null) { return PLAYM4_ORDER_ERROR; } if (callBack && typeof (callBack) === "function") { callBack(this.nWidth, this.nHeight); return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 获取YUV缓存大小 * * @returns 返回YUV缓存大小 */ PlayM4_RegisterYUVBufSizeCB(callback) { if (callback && typeof (callback) === "function") { this.YUVBufSizeCBFun = callback; return PLAYM4_OK; } else { return PLAYM4_PARA_OVER; } } /** * @synopsis 注销YUV缓存大小回调 * * @returns */ PlayM4_UnRegisterYUVBufSizeCB() { if (this.YUVBufSizeCBFun != null) { this.YUVBufSizeCBFun = null; } return PLAYM4_OK; } /** * @synopsis 画布置透明 * * @returns 状态码 */ PlayM4_ClearCanvas() { if (this.oSuperRender == null) { return PLAYM4_ORDER_ERROR; } // 画布置黑 if(this.bVideoCropInfo) { this.oSuperRender.SR_DisplayFrameData(this.nWidth, this.nHeight, null,this.nWidth- this.nSPSCropLeft - this.nSPSCropRight,this.nHeight- this.nSPSCropTop - this.nSPSCropBottom); } else { this.oSuperRender.SR_DisplayFrameData(this.nWidth, this.nHeight, null,this.nWidth,this.nHeight); } return PLAYM4_OK; } /** * @synopsis 释放输入码流缓存 * * @returns 状态码 */ PlayM4_ReleaseInputBuffer() { if (this.aInputDataBuffer === null) { return PLAYM4_ORDER_ERROR; } // 释放缓存 this.aInputDataBuffer.splice(0, this.aInputDataBuffer.length); this.aInputDataLens.splice(0, this.aInputDataLens.length); return PLAYM4_OK; } /** * @synopsis 获取解码帧类型 * * @returns 返回解码帧类型 */ PlayM4_GetDecodeFrameType() { return this.nDecFrameType; } /** * @synopsis 设置编码层断帧 * * @returns 错误码 */ PlayM4_SetDemuxModel(nIdemuxType,bTrue) { // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "SetDemuxModel", 'nIdemuxType': nIdemuxType, 'bTrue': bTrue }); return PLAYM4_OK; } /** * @synopsis 设置跳过错误数据 * * @returns 错误码 */ PlayM4_SkipErrorData(bSkip) { // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "SkipErrorData", 'bSkip': bSkip }); return PLAYM4_OK; } /** * @synopsis 设置解码差错隐藏等级 * * @returns 错误码 */ PlayM4_SetDecodeERC(nLevel) { // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "SetDecodeERC", 'nLevel': nLevel }); return PLAYM4_OK; } /** * @synopsis 设置降噪等级 * * @returns 错误码 */ PlayM4_SetANRParam(nEnable,nANRLevel) { // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "SetANRParam", 'nEnable': nEnable, 'nANRLevel':nANRLevel, }); return PLAYM4_OK; } /** * @synopsis 设置重采样 * * @returns 错误码 */ PlayM4_SetResampleValue(nEnable,resampleValue) { // 往 Worker 送数据 this.decodeWorker.postMessage({ 'command': "SetResampleValue", 'nEnable': nEnable, 'resampleValue':resampleValue, }); return PLAYM4_OK; } /** * @synopsis 下载文件 * * @param {object} oData 数据 File对象或者Blob对象或者ArrayBuffer对象 * @param {string} szName 下载文件名 * @returns {none} 无返回 */ downloadFile(oData, szName) { let oBlob = oData; if (!(oData instanceof Blob || oData instanceof File)) { oBlob = new Blob([oData]); } var szFileUrl = window.URL.createObjectURL(oBlob); var oLink = window.document.createElement("a"); oLink.href = szFileUrl; oLink.download = szName; var oClick = document.createEvent("MouseEvents"); oClick.initEvent("click", true, true); oLink.dispatchEvent(oClick); } }