let SDKModule; const VIDEO_FRAME_SUB_TYPE_I = 0; //I帧 const VIDEO_FRAME_SUB_TYPE_P = 1; //P帧 const VIDEO_FRAME_SUB_TYPE_B = 2; //B帧 const VIDEO_FRAME_SUB_TYPE_SMART_I = 18; //智能I帧 const VIDEO_FRAME_SUB_TYPE_SMART_P = 19; //智能P帧 const VIDEO_FRAME_SUB_TYPE_SMART_I_NORENDER = 20; //智能I帧,但不显示 const ENCODE_TYPE_VIDEO_HI_H264 = 2; //海思H.264编码格式 const ENCODE_TYPE_VIDEO_MY_H264 = 4; //公司H.264编码格式 const ENCODE_TYPE_VIDEO_STD_H264 = 8; //标准H.264编码格式 const ENCODE_TYPE_VIDEO_H265 = 12; //H.265编码格式 const DATA_RECORD_MP4 = 5; //录制MP4格式 const SP_STREAM_TYPE_DHSTD = 8; //dav编码格式 const STREAM_TYPE_SVC = 13; //H.264 SVC编码格式 const SP_STREAM_TYPE_FLV = 18; //flv编码格式 const ENCRYPT_UNKOWN = 0; //未知加密类型 const ENCRYPT_AES = 1; //AES加密类型,16进制数组格式 const ENCRYPT_AES256 = 2; //AES256加密类型,16进制数组格式 const ENCRYPT_AES_STRING_FORMAT = 3; //AES加密类型,字符串格式 const CACHE_MODE_OFF = 0; //关闭实时流自适应缓冲模式 const ADAPTIVE_CACHE = 1; //自适应缓冲 const REALTIME_FIRST = 2; //实时优先 const FLUENCY_FIRST = 3; //流畅优先 const FRAME_SCENE_POINTS_INFOR_SIZE = 144; // 景物点信息单组信息长度 /* IVS类型 */ var IVS_TYPE = { IVSINFOTYPE_PRESETPOS : 1, IVSINFOTYPE_MOTINTRKS : 2, IVSINFOTYPE_MOTINTRKS_EX : 3, IVSINFOTYPE_LIGHT : 4, // 光照 IVSINFOTYPE_RAWDATA : 5, // jason数据 IVSINFOTYPE_TRACK : 6, // 智能分析信息 IVSINFOTYPE_TRACK_EX_B0 : 7, // 智能结构化数据信息 IVSINFOTYPE_MOTIONFRAME : 9, IVSINFOTYPE_VIDEO_CONCENTRATION : 10, IVSINFOTYPE_OVERLAY_PIC : 11, // 叠加图片帧 IVSINFOTYPE_OSD_INFO : 12, // OSD辅助帧 IVSINFOTYPE_GPS_INFO : 13, // GPS辅助帧 IVSINFOTYPE_TAGGING_INFO : 14, // 景物点信息标注帧,辅助帧(0x13) IVSINFOTYPE_TRACK_A1 : 15, // NVR浓缩信息轨迹点 IVSINFOTYPE_DATA_WITH_LARGE_AMOUNT : 16, IVSINFOTYPE_TRACK_A1_EX : 17, // NVR浓缩信息轨迹点(扩展) IVSINFOTYPE_DATA_WITH_WATER_LEVEL_MONITOR : 18, //水位检测水位尺信息帧(0x17) IVSINFOTYPE_INTELFLOW : 19, // 智能客流量 IVSINFOTYPE_DATA_WITH_SOUND_DECIBEL : 20, //声音警报分贝值信息帧(0x18) IVSINFOTYPE_DATA_WITH_SMART_MOTION : 21, //智能动检信息帧(0x19) IVSINFOTYPE_DHOP_SMART : 22, //开放平台智能帧(0x14) IVSINFOTYPE_TRAFFIC_LIGHT : 23, //交通信号灯(红绿灯)辅助帧(0x1D) IVSINFOTYPE_PTZ_LOCATION : 24, //云台位置帧(0x21) }; var DRAW_TYPE = { DRAW_JSON : 0, DRAW_TRACK : 1, DRAW_ALARM : 2, DRAW_RULE : 3, DRAW_MOVE_CHECK : 7, DRAW_TEST : 9, DRAW_WEB_RULE : 11, DRAW_WEB_ALARM : 12, DRAW_FLOW_INFO : 13, DRAW_TRACKEX2 : 14, DRAW_WUXI235_TRACKEX2 : 15, DRAW_TRACKEXA1 : 16, DRAW_TRACKEX2_TYPE_HUMAN : 17, DRAW_TRACKEX2_TYPE_VEHICLE : 18, DRAW_TRACKEX2_TYPE_NONMOTOR : 19, DRAW_TRACKEX2_TYPE_SHOPPRESENCE : 20, DRAW_TRACKEX2_TYPE_FLOWBUSINESS : 21, DRAW_INTELFLOW : 22, DRAW_SMARTMOTION : 23, DRAW_DHOPSMART : 24, DRAW_DATA_WITH_LARGE_AMOUNT : 25,//大数据量帧 DRAW_TRACKEX2_TYPE_BAG : 26, DRAW_RULE_HIGHWAY_LANES : 27, //高速车道线 DRAW_WATER_LEVEL_MONITOR : 28, //水位尺 DRAW_END : 29 }; //DHOP元素类型 var IVS_DHOP_ElEMENT_TYPE = { EM_DHOP_CIRCLE : 1, EM_DHOP_BrokenLine : 2, EM_DHOP_POLYGON : 3, EM_DHOP_TEXT : 4 }; importScripts('libplay.js'); addEventListener('message', receiveMessage, false); Module.onRuntimeInitialized = function(){ m_bLoadSuccess = true; var msgType = 'LoadSuccess'; sendMessage(m_nPlayPort, msgType, null); } var m_bPlayback = 0; var m_bSupportH264MSE = false; var m_bSupportH265MSE = false; var m_nCanvasWidth = 1920; var m_nCanvasHeight = 1080; var m_nPlayPort = 0; var jsInputData = null; var jsInputDataAry = null; var jsFrameBuf = null; var jsFrameInfo = null; let dataView = null; var jsBuf = null; var jsFrameBodyData = null; var jsBufY = null; var jsBufU = null; var jsBufV = null; var jsYuvDataY = null; var jsYuvDataU = null; var jsYuvDataV = null; var jsRecordFrameBuf = null; var jsRecordFrameInfo = null; var dataViewRecord = null; let ivsBuf = null; let ivsDataArray = null; let ivsDataView = null; var m_nWidth = 0; var m_nHeight = 0; var m_nPreWidth = 0; var m_nPreHeight = 0; var m_bSmartEncode = 0; var m_nVideoEncodeType = 0; var m_bLoadSuccess = false; var m_bDecryptionResult = false; var m_nTotalStreamLength = 0; function receiveMessage(event) { if (!m_bLoadSuccess) { return; } var message = event.data; switch (message.nType) { //初始化 case 'Init': m_bPlayback = message.option.bPlayback; m_bSupportH264MSE = message.option.bSupportH264MSE; m_bSupportH265MSE = message.option.bSupportH265MSE; m_nCanvasWidth = message.option.nCanvasWidth; m_nCanvasHeight = message.option.nCanvasHeight; Init(); break; //送流 case 'InputData': InputData(message.pData); break; //打开智能绘制 case 'OpenIVSDraw': OpenIVSDraw(); break; //关闭智能绘制 case 'CloseIVSDraw': CloseIVSDraw(); break; //开始码流录制 case 'StartRecord': StartRecord(message.nRecordType); break; //停止码流录制 case 'StopRecord': StopRecord(); break; //设置播放速度 case 'SetPlaySpeed': SetPlaySpeed(message.nSpeed); break; //设置OSD叠加 case 'SetYUVOSDInfoEx': SetYUVOSDInfoEx(message.OSDInfo); break; case 'GetOriginalKeyCallBack': GetOriginalKey(message.playToken, message.playTokenKey, message.deviceID); break; case 'SetWebSecurityKey': SetWebSecurityKey(message.nDecryptType, message.nFrameType, message.strKey, message.stStreamInfo); break; //设置解密秘钥 case 'SetSecurityKey': SetSecurityKey(message.nEncryptType, message.szKey, message.nKeyLen, message.szKeyId, message.nKeyIdLen); break; //设置是否支持硬解码标记 case 'SetSupportWebMSE': m_bSupportH264MSE = message.bSupportH264MSE; m_bSupportH265MSE = message.bSupportH265MSE; SetSupportWebMSE(m_bSupportH264MSE, m_bSupportH265MSE); //暂停播放 case 'Pause': Pause(message.bPause); break; //抓图 case 'CatchPic': CatchPic(); break; //停止播放 case 'Stop': Stop(); break; case 'setPrintLogLevel': SetPrintLogLevel(message.nLogLevel); break; default: break; } } function Init() { //获取PlaySDK空闲端口号 var jsPort = Module._malloc(1); var jsPortAry = new Uint8Array(Module.HEAPU8.buffer, jsPort, 1); Module._PLAY_GetFreePort(jsPortAry.byteOffset); m_nPlayPort = jsPortAry[0]; jsPortAry = null; Module._free(jsPort); //设置播放窗口宽高属性 Module._PLAY_ViewResolutionChanged(m_nPlayPort, m_nCanvasWidth, m_nCanvasHeight, 0); //设置实时流模式 var nRet = Module._PLAY_SetStreamOpenMode(m_nPlayPort, m_bPlayback); nRet = Module._PLAY_OpenStream(m_nPlayPort, 0, 0, 10*1024*1024); nRet = Module._PLAY_SetSupportWebMSE(m_nPlayPort, m_bSupportH264MSE, m_bSupportH265MSE); nRet = Module._PLAY_Play(m_nPlayPort, 1); if (nRet) { //向C++层申请一块wasm内存,用于接收码流 jsInputData = Module._malloc(5*1024*1024); jsInputDataAry = new Uint8Array(Module.HEAPU8.buffer, jsInputData, 5*1024*1024); var msgType = 'InitSuccess'; sendMessage(m_nPlayPort, msgType, null); } } function InputData(data) { m_nTotalStreamLength += data.length; if(jsInputDataAry) { jsInputDataAry.set(data); var nRet = Module._PLAY_InputData(m_nPlayPort, jsInputDataAry.byteOffset, data.length); var i = 0; } } function OpenIVSDraw() { Module._PLAY_RenderPrivateData(m_nPlayPort, 1, 0); } function CloseIVSDraw() { Module._PLAY_RenderPrivateData(m_nPlayPort, 0, 0); } function StartRecord(nRecordType) { Module._PLAY_StartDataRecord(m_nPlayPort, 0, nRecordType); } function StopRecord() { Module._PLAY_StopDataRecord(m_nPlayPort); } function SetPlaySpeed(nSpeed) { Module._PLAY_SetPlaySpeed(m_nPlayPort, nSpeed); } function SetYUVOSDInfoEx(OSDInfo) { if (0 == m_nCanvasWidth || 0 == m_nCanvasHeight) { return; } let nOsdCount = OSDInfo.osdCount; let nStuOsdInfoSize = 18376;//单个YUV_OSD_INFO_EX结构体18376字节 const OsdDataInfoPtr = Module._malloc(nStuOsdInfoSize); let arrayFormat = new Uint8Array(Module.HEAPU8.buffer); for (let i = 0; i < nStuOsdInfoSize; i ++) { arrayFormat[OsdDataInfoPtr + i] = 0; } Module.HEAPU8[OsdDataInfoPtr + 0] = 1;//是否是私有字体 let strFontPath = "Font.bin"; let nSequence = 0; strFontPath.split('').forEach((char, nIndex) => { let nValue = char.charCodeAt(0); arrayFormat[OsdDataInfoPtr + nSequence + 1] = nValue; nSequence++; }); Module.HEAP32[OsdDataInfoPtr/4 + 65] = nOsdCount; for (let i = 0; i < nOsdCount; i ++) { let nPointX = OSDInfo.osdList[i].pointX / m_nCanvasWidth * m_nWidth; let nPointY = OSDInfo.osdList[i].pointY / m_nCanvasHeight * m_nHeight; Module.HEAP32[OsdDataInfoPtr/4 + 66 + 564/4 * i] = nPointX;// 旋转点像素x位置 Module.HEAP32[OsdDataInfoPtr/4 + 67 + 564/4 * i] = nPointY;// 旋转点像素y位置 Module.HEAP32[OsdDataInfoPtr/4 + 68 + 564/4 * i] = OSDInfo.osdList[i].colorR;// osd叠加颜色r,范围0-255 Module.HEAP32[OsdDataInfoPtr/4 + 69 + 564/4 * i] = OSDInfo.osdList[i].colorG;// osd叠加颜色g,范围0-255 Module.HEAP32[OsdDataInfoPtr/4 + 70 + 564/4 * i] = OSDInfo.osdList[i].colorB;// osd叠加颜色b,范围0-255 Module.HEAP32[OsdDataInfoPtr/4 + 71 + 564/4 * i] = OSDInfo.osdList[i].colorA;// osd叠加透明度,范围0-255 nSequence = 0; //JS默认采用UTF-16编码,需要先转为UTF-8编码 let UTF8Array = UTF16ToUTF8(OSDInfo.osdList[i].strOsdData); for(let j = 0; j < UTF8Array.length; j++) { arrayFormat[(OsdDataInfoPtr + nSequence + 288 + 564 * i) >> 0] = UTF8Array[j];// osd数据,使用utf-8编码 nSequence++; } Module.HEAP32[OsdDataInfoPtr/4 + 200 + 564/4 * i] = OSDInfo.osdList[i].fontX;// 字体宽度, 使用私有字体时无效 Module.HEAP32[OsdDataInfoPtr/4 + 201 + 564/4 * i] = OSDInfo.osdList[i].fontY;// 字体高度, 最大512 Module.HEAP32[OsdDataInfoPtr/4 + 202 + 564/4 * i] = OSDInfo.osdList[i].rotateAngle;// 旋转角度,范围0-359度 Module.HEAPU8[OsdDataInfoPtr + 812 + 564 * i] = OSDInfo.osdList[i].coordinate8192;// 8192坐标系, 0表示像素坐标x,y基于码流分辨率, 1表示基于8192坐标系 } Module._PLAY_SetYUVOSDInfoEx(m_nPlayPort, OsdDataInfoPtr); Module._free(OsdDataInfoPtr); } function GetOriginalKey(playToken, playTokenKey, deviceID) { var arrPlayToken = Module.intArrayFromString(playToken).concat(0);//add '\0' var playTokenPtr = Module._malloc(arrPlayToken.length);//采用声明的c函数 _malloc Module.HEAPU8.set(arrPlayToken, playTokenPtr);//复制字符串内容 var arrPlayTokenKey = Module.intArrayFromString(playTokenKey).concat(0); var playTokenKeyPtr = Module._malloc(arrPlayTokenKey.length); Module.HEAPU8.set(arrPlayTokenKey, playTokenKeyPtr); var arrDeviceID = Module.intArrayFromString(deviceID).concat(0); var deviceIDPtr = Module._malloc(arrDeviceID.length); Module.HEAPU8.set(arrDeviceID, deviceIDPtr); var outKeyPtr = Module._malloc(256); var outKeyLengthPtr = Module._malloc(4); var nRet = Module._PLAY_GetOriginalKey(m_nPlayPort, playTokenPtr, playTokenKeyPtr, deviceIDPtr, outKeyPtr, outKeyLengthPtr); var outKeyLength = Module.HEAP32[outKeyLengthPtr >>2]; var outKeyTmp = ""; if ((1 == nRet) && (outKeyLength <= 256)) { var jsKeyBuf = new ArrayBuffer(outKeyLength); var jsKeyData = new Uint8Array(jsKeyBuf); jsKeyData.set(Module.HEAPU8.subarray(outKeyPtr, outKeyPtr + outKeyLength)); outKeyTmp = ArrayBufferToString(jsKeyBuf); } Module._free(playTokenPtr);//释放内存 Module._free(playTokenKeyPtr); Module._free(deviceIDPtr); Module._free(outKeyPtr); Module._free(outKeyLengthPtr); var outKeyParam = { nRet: nRet, outKey: outKeyTmp, }; var msgType = 'GetOriginalKeyCallBack'; var msgData = { nRet: nRet, outKey: outKeyTmp, } sendMessage(m_nPlayPort, msgType, msgData); } function SetWebSecurityKey(nDecryptType, nFrameType, strKey, stStreamInfo) { var arrStrKey = Module.intArrayFromString(strKey).concat(0); var strKeyPtr = Module._malloc(arrStrKey.length); Module.HEAPU8.set(arrStrKey, strKeyPtr); var arrSdpInfo = Module.intArrayFromString(stStreamInfo.sdpInfo).concat(0); var sdpInfoPtr = Module._malloc(arrSdpInfo.length); Module.HEAPU8.set(arrSdpInfo, sdpInfoPtr); var arrUserName = Module.intArrayFromString(stStreamInfo.strUserName).concat(0); var userNamePtr = Module._malloc(arrUserName.length); Module.HEAPU8.set(arrUserName, userNamePtr); var arrPassWord = Module.intArrayFromString(stStreamInfo.strPassWord).concat(0); var passWordPtr = Module._malloc(arrPassWord.length); Module.HEAPU8.set(arrPassWord, passWordPtr); const stStreamInfoPtr = Module._malloc(16);//4:uint32的字节大小 Module.HEAP32[stStreamInfoPtr/4 + 0] = sdpInfoPtr; Module.HEAP32[stStreamInfoPtr/4 + 1] = userNamePtr; Module.HEAP32[stStreamInfoPtr/4 + 2] = passWordPtr; Module.HEAP32[stStreamInfoPtr/4 + 3] = stStreamInfo.nSsrc; Module._PLAY_SetWebSecurityKey(m_nPlayPort, nDecryptType, nFrameType, strKeyPtr, stStreamInfoPtr); Module._free(strKeyPtr);//释放内存 Module._free(sdpInfoPtr); Module._free(userNamePtr); Module._free(passWordPtr); Module._free(stStreamInfoPtr); } function SetSecurityKey(nEncryptType, szKey, nKeyLen, szKeyId, nKeyIdLen) { var nRet = 1; var strKey = Module._malloc(49); var arrayKey = new Uint8Array(Module.HEAPU8.buffer); var nSequence = 0; if (ENCRYPT_AES == nEncryptType) { //逐字节的形式去内存中设置值,直接修改wasm内存数据 szKey.forEach((value, nIndex) => { arrayKey[(strKey + nSequence) >> 0] = value; nSequence++; }); } else if(ENCRYPT_AES256 == nEncryptType) { var szKeyIdTmp = new Uint8Array(16); ; //协议规定ENCRYPT_AES256对应的枚举值为1 arrayKey[(strKey + nSequence) >> 0] = 1; nSequence++; if (0 == nKeyIdLen) { for(var i = 0; i < 16; i++) { szKeyIdTmp[i] = 0x00; } nKeyIdLen = 16; szKeyId = szKeyIdTmp; } //拼接上key ID,逐字节的形式去内存中设置值,直接修改wasm内存数据 szKeyId.forEach((value, nIndex) => { arrayKey[(strKey + nSequence) >> 0] = value; nSequence++; }); //拼接上key,逐字节的形式去内存中设置值,直接修改wasm内存数据 szKey.forEach((value, nIndex) => { arrayKey[strKey + nSequence] = value; nSequence++; }); nKeyLen = 1 + nKeyLen + nKeyIdLen; szKeyIdTmp = null; } else if(ENCRYPT_AES_STRING_FORMAT == nEncryptType) { szKey.split('').forEach((char, nIndex) => { arrayKey[(strKey + nSequence) >> 0] = char.charCodeAt(0); nSequence++; }); } nRet = Module._PLAY_SetSecurityKey(m_nPlayPort, strKey, nKeyLen); Module._free(strKey); return nRet; } function SetSupportWebMSE(bSupportH264MSE, bSupportH265MSE) { Module._PLAY_SetSupportWebMSE(m_nPlayPort, bSupportH264MSE, bSupportH265MSE); } function Pause(bPause) { Module._PLAY_Pause(m_nPlayPort, bPause); } function CatchPic() { var nSize = m_nWidth * m_nHeight * 3/2; var pJpegBuf = Module._malloc(nSize); var pJpegBufArr = new Uint8Array(Module.HEAPU8.buffer, pJpegBuf, nSize); var pJpegSize = Module._malloc(4); var pJpegSizeArr = new Uint8Array(Module.HEAPU8.buffer, pJpegSize, 4); //获取当前图像编码后的jpeg图片数据 Module._PLAY_GetPicJPEG(m_nPlayPort, pJpegBufArr.byteOffset, nSize, pJpegSizeArr.byteOffset, 100); //C++内存数据拷贝至JS内存 var nDataSize = (pJpegSizeArr[3] << 24) + (pJpegSizeArr[2] << 16) + (pJpegSizeArr[1] << 8) + pJpegSizeArr[0]; var pOutJpegBuf = new ArrayBuffer(nDataSize); var pOutJpegBufArr = new Uint8Array(pOutJpegBuf); pOutJpegBufArr.set(Module.HEAPU8.subarray(pJpegBufArr.byteOffset, pJpegBufArr.byteOffset + nDataSize)); var msgType = 'CatchPicCallBack'; var msgData = { buffer: pOutJpegBufArr } sendMessage(m_nPlayPort, msgType, msgData); Module._free(pJpegBuf); Module._free(pJpegSize); pJpegBufArr = null; pJpegSizeArr = null; pOutJpegBuf= null; pOutJpegBufArr = null; } function Stop() { var nRet = Module._PLAY_Stop(m_nPlayPort); if (0 == nRet) { return; } nRet = Module._PLAY_CloseStream(m_nPlayPort); jsInputDataAry = null; Module._free(jsInputData); jsFrameBuf = null; jsFrameInfo = null; dataView = null; jsBufY = null; jsBufU = null; jsBufV = null; jsYuvDataY = null; jsYuvDataU = null; jsYuvDataV = null; jsRecordFrameBuf = null; jsRecordFrameInfo = null; dataViewRecord = null; m_nTotalStreamLength = 0; } function SetPrintLogLevel(nLogLevel) { Module._PLAY_SetPrintLogLevel(nLogLevel); } function cPlusVisibleDecCallBack(nPort, pBufY, pBufU, pBufV, nSize, pFrameInfo) { var stuFrameInfo = {}; stuFrameInfo.nTotalStreamLength = m_nTotalStreamLength; if(!jsFrameInfo) { jsFrameBuf = new ArrayBuffer(292);//通过二进制对象分配一块连续内存 jsFrameInfo = new Uint8Array(jsFrameBuf);//二进制对象绑定到视图,通过视图对内存进行读写操作 dataView = new DataView(jsFrameBuf); } jsFrameInfo.set(Module.HEAPU8.subarray(pFrameInfo, pFrameInfo + 292));//c中的内存拷贝到刚分配的js内存中 //帧类型 stuFrameInfo.nFrameType = dataView.getInt32(0, true); //帧序号 stuFrameInfo.nFrameID = dataView.getInt32(4, true); //帧子类型 stuFrameInfo.nFrameSubType = dataView.getInt32(56, true); //帧时间 stuFrameInfo.nYear = dataView.getUint16(40, true); stuFrameInfo.nMonth = dataView.getUint16(42, true); stuFrameInfo.nDay = dataView.getUint16(46, true); stuFrameInfo.nHour = dataView.getUint16(48, true); stuFrameInfo.nMinute = dataView.getUint16(50, true); stuFrameInfo.nSecond = dataView.getUint16(52, true); var msgData = {}; //视频 if (1 == stuFrameInfo.nFrameType) { //剩余缓冲数据量 stuFrameInfo.nRemainData = dataView.getInt32(36, true); //抽帧标记 stuFrameInfo.bThrowFrame = dataView.getUint8(120, true); if (0 == stuFrameInfo.bThrowFrame) { //编码类型 stuFrameInfo.nEncodeType = dataView.getInt32(108, true); //码流类型 stuFrameInfo.nStreamType = dataView.getInt32(112, true); //时间戳 stuFrameInfo.nTimeStamp = dataView.getUint32(8, true); //图像宽度 stuFrameInfo.nWidth = dataView.getInt32(12, true); m_nWidth = stuFrameInfo.nWidth; //图像高度 stuFrameInfo.nHeight = dataView.getInt32(16, true); m_nHeight = stuFrameInfo.nHeight; //视频帧率 stuFrameInfo.nFrameRate = dataView.getInt32(20, true); //图像跨距 stuFrameInfo.nStride = dataView.getInt32(116, true); //vui句法中视频三原色 stuFrameInfo.nColorPrimaries = dataView.getUint8(124, true); //vui句法中视频信号转换函数 stuFrameInfo.nColorTransfer = dataView.getUint8(125, true); //vui中视频颜色空间 stuFrameInfo.nColorSpace = dataView.getUint8(126, true); //颜色范围 0:yuv范围16-235,对应 TV; 1:yuv范围0-255, 对应 PC stuFrameInfo.bColorFull = dataView.getUint8(127, true); if ((ENCODE_TYPE_VIDEO_HI_H264 == stuFrameInfo.nEncodeType) || (ENCODE_TYPE_VIDEO_MY_H264 == stuFrameInfo.nEncodeType) || (ENCODE_TYPE_VIDEO_STD_H264 == stuFrameInfo.nEncodeType)) { //H.264编码类型 m_nVideoEncodeType = 1; } else if(12 == stuFrameInfo.nEncodeType) { //H.265编码类型 m_nVideoEncodeType = 2; } //智能I/P帧 if ((VIDEO_FRAME_SUB_TYPE_SMART_I == stuFrameInfo.nFrameSubType) || (VIDEO_FRAME_SUB_TYPE_SMART_P == stuFrameInfo.nFrameSubType) || (VIDEO_FRAME_SUB_TYPE_SMART_I_NORENDER == stuFrameInfo.nFrameSubType)) { //Smart H.264或者Smart H.265 m_bSmartEncode = 1; } else if(0 == stuFrameInfo.nFrameSubType) { m_bSmartEncode = 0; } //非Smart H.264/H.265码流,若浏览器支持MSE硬解码则采用硬解码 //SVC码流不支持硬解码 if ((((1 == m_nVideoEncodeType) && (true == m_bSupportH264MSE)) || ((2 == m_nVideoEncodeType) && (true == m_bSupportH265MSE))) && !m_bSmartEncode && (STREAM_TYPE_SVC != stuFrameInfo.nStreamType)) { //读取码流裸数据 jsBuf = new ArrayBuffer(nSize);//通过二进制对象分配一块连续内存 jsFrameBodyData = new Uint8Array(jsBuf);//二进制对象绑定到视图,通过视图对内存进行读写操作 jsFrameBodyData.set(Module.HEAPU8.subarray(pBufY, pBufY + nSize));//c中的内存拷贝到刚分配的js内存中 msgData = { pBufY: jsFrameBodyData, pBufU: null, pBufV: null, nSize: nSize, stuFrameInfo: stuFrameInfo, } } else { if((0 == pBufY) || (0 == pBufU) || (0 == pBufV)) { return; } if (m_nWidth != m_nPreWidth || m_nHeight != m_nPreHeight) { m_nPreWidth = m_nWidth; m_nPreHeight = m_nHeight; jsBufY = null; jsBufU = null; jsBufV = null; jsYuvDataY = null; jsYuvDataU = null; jsYuvDataV = null; jsBufY = new ArrayBuffer(m_nWidth * m_nHeight);//通过二进制对象分配一块连续内存 jsYuvDataY = new Uint8Array(jsBufY);//二进制对象绑定到视图,通过视图对内存进行读写操作 jsBufU = new ArrayBuffer(m_nWidth * m_nHeight / 4); jsYuvDataU = new Uint8Array(jsBufU); jsBufV = new ArrayBuffer(m_nWidth * m_nHeight / 4); jsYuvDataV = new Uint8Array(jsBufV); } var h = 0; //将C++层YUV解码数据Y分量数据拷贝至JS层内存中 for(h = 0; h < stuFrameInfo.nHeight; h++) { jsYuvDataY.set(Module.HEAPU8.subarray((pBufY + h * stuFrameInfo.nStride), (pBufY + h * stuFrameInfo.nStride) + stuFrameInfo.nWidth), h * stuFrameInfo.nWidth);//c中的内存拷贝到刚分配的js内存中 } //将C++层YUV解码数据U分量数据拷贝至JS层内存中 for(h = 0; h < stuFrameInfo.nHeight / 2; h++) { jsYuvDataU.set(Module.HEAPU8.subarray((pBufU + h * stuFrameInfo.nStride/2), (pBufU + h * stuFrameInfo.nStride/2) + stuFrameInfo.nWidth/2), h * stuFrameInfo.nWidth/2);//c中的内存拷贝到刚分配的js内存中 } //将C++层YUV解码数据V分量数据拷贝至JS层内存中 for(h = 0; h < stuFrameInfo.nHeight / 2; h++) { jsYuvDataV.set(Module.HEAPU8.subarray((pBufV + h * stuFrameInfo.nStride/2), (pBufV + h * stuFrameInfo.nStride/2) + stuFrameInfo.nWidth/2), h * stuFrameInfo.nWidth/2);//c中的内存拷贝到刚分配的js内存中 } msgData = { pBufY: jsYuvDataY, pBufU: jsYuvDataU, pBufV: jsYuvDataV, nSize: nSize, stuFrameInfo: stuFrameInfo, } } } else { msgData = { pBufY: null, pBufU: null, pBufV: null, nSize: 0, stuFrameInfo: stuFrameInfo, } } } else if(2 == stuFrameInfo.nFrameType)//音频帧 { //总通道数 stuFrameInfo.nTotalChannel = dataView.getInt32(68, true); //当前通道 stuFrameInfo.nCurChannel = dataView.getInt32(72, true); //暂不支持双通道音频播放 if (stuFrameInfo.nCurChannel > 0) { return; } //采样位数 stuFrameInfo.nBits = dataView.getInt32(28, true); //采样率 stuFrameInfo.nSamples = dataView.getInt32(32, true); //声道数 stuFrameInfo.nAudioChnNum = dataView.getInt32(24, true); var AudioBuf = new ArrayBuffer(nSize); var UI8AudioData = new Uint8Array(AudioBuf); //将C++层解码后的pcm音频数据拷贝至JS层内存 UI8AudioData.set(Module.HEAPU8.subarray(pBufY, pBufY + nSize)); msgData = { pBufY: UI8AudioData, pBufU: null, pBufV: null, nSize: nSize, stuFrameInfo: stuFrameInfo, } } var msgType = 'VisibleDecCallBack'; sendMessage(nPort, msgType, msgData); jsBuf = null; jsFrameBodyData = null; } /* * C++层AES解密回调。 * * @param[in] nPort 端口号 * @param[in] nFrameID 视频帧序号 * @param[in] bSuccess 是否解密成功 */ function cDigitalSignCallBack(nPort, nFrameID, bSuccess) { m_bDecryptionResult = bSuccess; var msgType = 'DecryptionResultCallBack'; var msgData = { bSuccess: bSuccess } sendMessage(nPort, msgType, msgData); } /* * C++层码流录制回调,回调至JS层进行数据存储 * * @param[in] nPort 端口号 * @param[in] pData 码流数据 * @param[in] nDataLen 数据长度 * @param[in] nOffset 偏移量 * @param[in] pFrameInfo 码流信息 */ function cRecordDataCallBack(nPort, pData, nDataLen, nOffset, pFrameInfo) { var stuFrameInfo = {}; if (!jsRecordFrameInfo) { jsRecordFrameBuf = new ArrayBuffer(292); //通过二进制对象分配一块连续内存 jsRecordFrameInfo = new Uint8Array(jsRecordFrameBuf); //二进制对象绑定到视图,通过视图对内存进行读写操作 dataViewRecord = new DataView(jsRecordFrameBuf); } jsRecordFrameInfo.set(Module.HEAPU8.subarray(pFrameInfo, pFrameInfo + 292)); //c中的内存拷贝到刚分配的js内存中 //帧类型 stuFrameInfo.nFrameType = dataViewRecord.getInt32(0, true); //帧序号 stuFrameInfo.nFrameID = dataViewRecord.getInt32(4, true); //帧子类型 stuFrameInfo.nFrameSubType = dataViewRecord.getInt32(56, true); //视频帧 if (1 == stuFrameInfo.nFrameType) { //编码类型 stuFrameInfo.nEncodeType = dataViewRecord.getInt32(68, true); //码流类型 stuFrameInfo.nStreamType = dataViewRecord.getInt32(72, true); //时间戳 stuFrameInfo.nTimeStamp = dataViewRecord.getUint32(8, true); //帧时间 stuFrameInfo.nYear = dataViewRecord.getUint16(40, true); stuFrameInfo.nMonth = dataViewRecord.getUint16(42, true); stuFrameInfo.nDay = dataViewRecord.getUint16(46, true); stuFrameInfo.nHour = dataViewRecord.getUint16(48, true); stuFrameInfo.nMinute = dataViewRecord.getUint16(50, true); stuFrameInfo.nSecond = dataViewRecord.getUint16(52, true); } var bufRecord = new ArrayBuffer(nDataLen); var arrayRecord = new Uint8Array(bufRecord); arrayRecord.set(Module.HEAPU8.subarray(pData, pData + nDataLen)); var msgType = 'RecordDataCallBack'; var msgData = { pRecordData: arrayRecord, nLen: nDataLen, Offset: nOffset, stuFrameInfo: stuFrameInfo, } sendMessage(nPort, msgType, msgData); bufRecord = null; arrayRecord = null; } function cIVSDrawDataCallBack(nPort, pBuf, nType, nLen, nReallen) { //帧序号为-1时不绘制 if(-1 == nReallen) { return; } var pParseredBuf = null; ivsBuf = new ArrayBuffer(nLen);//通过二进制对象分配一块连续内存 ivsDataArray = new Uint8Array(ivsBuf);//二进制对象绑定到视图,通过视图对内存进行读写操作 ivsDataArray.set(Module.HEAPU8.subarray(pBuf, pBuf + nLen)); ivsDataView = new DataView(ivsDataArray.buffer); if (IVS_TYPE.IVSINFOTYPE_INTELFLOW == nType) {//智能客流量 var stuIntelflowInfo = {}; stuIntelflowInfo.NumberStat = ivsDataView.getUint16(0, true);//大类业务方案 stuIntelflowInfo.nIntelFlowPlanNum = ivsDataView.getUint16(2, true);//智能客流规则数量(最大不会超过32个) var pIntelFlowPlan = ivsDataView.getUint32(4, true); let IntelFlowPlanBuf = new ArrayBuffer(12); let IntelFlowPlanArray = new Uint8Array(IntelFlowPlanBuf); let IntelFlowPlanView = new DataView(IntelFlowPlanBuf); stuIntelflowInfo.pIntelFlowPlan = new Array(stuIntelflowInfo.nIntelFlowPlanNum); for (let i = 0; i < stuIntelflowInfo.nIntelFlowPlanNum; i++) { IntelFlowPlanArray.set(Module.HEAPU8.subarray(pIntelFlowPlan + i * 12, pIntelFlowPlan + i * 12 + 12)); //解析智能客流规则 stuIntelflowInfo.pIntelFlowPlan[i] = {}; stuIntelflowInfo.pIntelFlowPlan[i].PlanId = IntelFlowPlanView.getUint16(0, true);//规则ID stuIntelflowInfo.pIntelFlowPlan[i].RuleType = IntelFlowPlanView.getUint16(2, true);//规则类型 stuIntelflowInfo.pIntelFlowPlan[i].RegionNum = IntelFlowPlanView.getUint16(8, true);//区域数目 var pRegion = IntelFlowPlanView.getUint32(4, true); let RegionBuf = new ArrayBuffer(12); let RegionArray = new Uint8Array(RegionBuf); let RegionView = new DataView(RegionBuf); stuIntelflowInfo.pIntelFlowPlan[i].pRegion = new Array(stuIntelflowInfo.pIntelFlowPlan[i].RegionNum); for (let j = 0; j < stuIntelflowInfo.pIntelFlowPlan[i].RegionNum; j++) { RegionArray.set(Module.HEAPU8.subarray(pRegion + j * 12, pRegion + j * 12 + 12)); stuIntelflowInfo.pIntelFlowPlan[i].pRegion[j] = {}; stuIntelflowInfo.pIntelFlowPlan[i].pRegion[j].RegionId = RegionView.getUint16(0, true);//区域ID stuIntelflowInfo.pIntelFlowPlan[i].pRegion[j].State = RegionView.getUint16(2, true);//状态:离开or进入 stuIntelflowInfo.pIntelFlowPlan[i].pRegion[j].PeopleNum = RegionView.getUint32(4, true);//人数 } } pParseredBuf = stuIntelflowInfo; } else if (IVS_TYPE.IVSINFOTYPE_DHOP_SMART == nType) {//DHOP开放平台智能帧 var stuObjDHOP = {}; stuObjDHOP.nId = ivsDataView.getUint32(0, true);//对象ID stuObjDHOP.wCustom = ivsDataView.getUint16(4, true);//自定义值 stuObjDHOP.chState = ivsDataView.getUint8(6, true);//对象状态 stuObjDHOP.chCount = ivsDataView.getUint8(7, true);//元素个数 //解析DHOP元素 var pElement = ivsDataView.getUint32(8, true); let elementBuf = new ArrayBuffer(12); let elementDataArray = new Uint8Array(elementBuf); let elementDataView = new DataView(elementBuf); stuObjDHOP.pElement = new Array(stuObjDHOP.chCount); for (var i = 0; i < stuObjDHOP.chCount; i++) { elementDataArray.set(Module.HEAPU8.subarray(pElement + i * 12, pElement + i * 12 + 12)); //解析DHOP元素类型 stuObjDHOP.pElement[i] = {}; stuObjDHOP.pElement[i].nStructType = elementDataView.getUint32(0, true); stuObjDHOP.pElement[i].nStructLength = elementDataView.getUint32(4, true); var pStruct = elementDataView.getUint32(8, true); let structBuf = new ArrayBuffer(stuObjDHOP.pElement[i].nStructLength); let structArray = new Uint8Array(structBuf); let structDataView = new DataView(structBuf); structArray.set(Module.HEAPU8.subarray(pStruct, pStruct + stuObjDHOP.pElement[i].nStructLength)); stuObjDHOP.pElement[i].pStruct = {}; if (IVS_DHOP_ElEMENT_TYPE.EM_DHOP_CIRCLE == stuObjDHOP.pElement[i].nStructType) { stuObjDHOP.pElement[i].pStruct.chType = structDataView.getUint8(0, true);//子类型0x3 stuObjDHOP.pElement[i].pStruct.chWidth = structDataView.getUint8(1, true);//线宽,单位px stuObjDHOP.pElement[i].pStruct.chStyle = structDataView.getUint8(2, true);//样式 stuObjDHOP.pElement[i].pStruct.wRadius = structDataView.getUint16(4, true);//半径 stuObjDHOP.pElement[i].pStruct.positionCircle = {};//圆心坐标 stuObjDHOP.pElement[i].pStruct.positionCircle.x = structDataView.getUint16(8, true); stuObjDHOP.pElement[i].pStruct.positionCircle.y = structDataView.getUint16(10, true); stuObjDHOP.pElement[i].pStruct.chLineA = structDataView.getUint8(12, true);//边框线条颜色(ARGB) stuObjDHOP.pElement[i].pStruct.chLineR = structDataView.getUint8(13, true); stuObjDHOP.pElement[i].pStruct.chLineG = structDataView.getUint8(14, true); stuObjDHOP.pElement[i].pStruct.chLineB = structDataView.getUint8(15, true); stuObjDHOP.pElement[i].pStruct.chRegA = structDataView.getUint8(16, true);//区域填充颜色(ARGB) stuObjDHOP.pElement[i].pStruct.chRegR = structDataView.getUint8(17, true); stuObjDHOP.pElement[i].pStruct.chRegG = structDataView.getUint8(18, true); stuObjDHOP.pElement[i].pStruct.chRegB = structDataView.getUint8(19, true); } else if(IVS_DHOP_ElEMENT_TYPE.EM_DHOP_BrokenLine == stuObjDHOP.pElement[i].nStructType) { stuObjDHOP.pElement[i].pStruct.chType = structDataView.getUint8(0, true);//子类型0x2 stuObjDHOP.pElement[i].pStruct.chCount = structDataView.getUint8(1, true);//端点个数 stuObjDHOP.pElement[i].pStruct.chWidth = structDataView.getUint8(2, true);//线宽,单位px stuObjDHOP.pElement[i].pStruct.chStyle = structDataView.getUint8(3, true);//样式 stuObjDHOP.pElement[i].pStruct.chLineA = structDataView.getUint8(4, true);//边框线条颜色(ARGB) stuObjDHOP.pElement[i].pStruct.chLineR = structDataView.getUint8(5, true); stuObjDHOP.pElement[i].pStruct.chLineG = structDataView.getUint8(6, true); stuObjDHOP.pElement[i].pStruct.chLineB = structDataView.getUint8(7, true); //端点坐标 var pPoints = null; let pointsBuf = null; let pointsDataArray = null; let pointsDataView = null; if (stuObjDHOP.pElement[i].pStruct.chCount > 0) { stuObjDHOP.pElement[i].pStruct.pPoints = new Array(stuObjDHOP.pElement[i].pStruct.chCount); pPoints = structDataView.getUint32(8, true); pointsBuf = new ArrayBuffer(4); pointsDataArray = new Uint8Array(pointsBuf); pointsDataView = new DataView(pointsBuf); } for(var j = 0; j < stuObjDHOP.pElement[i].pStruct.chCount; j++) { pointsDataArray.set(Module.HEAPU8.subarray(pPoints + j*4, pPoints + j*4 + 4)); stuObjDHOP.pElement[i].pStruct.pPoints[j] = {}; stuObjDHOP.pElement[i].pStruct.pPoints[j].x = pointsDataView.getUint16(0, true); stuObjDHOP.pElement[i].pStruct.pPoints[j].y = pointsDataView.getUint16(2, true); } } else if(IVS_DHOP_ElEMENT_TYPE.EM_DHOP_POLYGON == stuObjDHOP.pElement[i].nStructType) { stuObjDHOP.pElement[i].pStruct.chType = structDataView.getUint8(0, true);//子类型0x3 stuObjDHOP.pElement[i].pStruct.chCount = structDataView.getUint8(1, true);//端点个数 stuObjDHOP.pElement[i].pStruct.chWidth = structDataView.getUint8(2, true);//线宽,单位px stuObjDHOP.pElement[i].pStruct.chStyle = structDataView.getUint8(3, true);//样式 stuObjDHOP.pElement[i].pStruct.chLineA = structDataView.getUint8(4, true);//边框线条颜色(ARGB) stuObjDHOP.pElement[i].pStruct.chLineR = structDataView.getUint8(5, true); stuObjDHOP.pElement[i].pStruct.chLineG = structDataView.getUint8(6, true); stuObjDHOP.pElement[i].pStruct.chLineB = structDataView.getUint8(7, true); stuObjDHOP.pElement[i].pStruct.chRegA = structDataView.getUint8(8, true);//区域填充颜色(ARGB) stuObjDHOP.pElement[i].pStruct.chRegR = structDataView.getUint8(9, true); stuObjDHOP.pElement[i].pStruct.chRegG = structDataView.getUint8(10, true); stuObjDHOP.pElement[i].pStruct.chRegB = structDataView.getUint8(11, true); //端点坐标 var pPoints = null; let pointsBuf = null; let pointsDataArray = null; let pointsDataView = null; if (stuObjDHOP.pElement[i].pStruct.chCount > 0) { stuObjDHOP.pElement[i].pStruct.pPoints = new Array(stuObjDHOP.pElement[i].pStruct.chCount); pPoints = structDataView.getUint32(12, true); pointsBuf = new ArrayBuffer(4); pointsDataArray = new Uint8Array(pointsBuf); pointsDataView = new DataView(pointsBuf); } for(var j = 0; j < stuObjDHOP.pElement[i].pStruct.chCount; j++) { pointsDataArray.set(Module.HEAPU8.subarray(pPoints + j*4, pPoints + j*4 + 4)); stuObjDHOP.pElement[i].pStruct.pPoints[j] = {}; stuObjDHOP.pElement[i].pStruct.pPoints[j].x = pointsDataView.getUint16(0, true); stuObjDHOP.pElement[i].pStruct.pPoints[j].y = pointsDataView.getUint16(2, true); } } else if(IVS_DHOP_ElEMENT_TYPE.EM_DHOP_TEXT == stuObjDHOP.pElement[i].nStructType) { stuObjDHOP.pElement[i].pStruct.chType = structDataView.getUint8(0, true);//子类型0x4 stuObjDHOP.pElement[i].pStruct.chCharset = structDataView.getUint8(1, true);//编码方式 stuObjDHOP.pElement[i].pStruct.stringPos = {};//字符坐标 stuObjDHOP.pElement[i].pStruct.stringPos.x = structDataView.getUint16(4, true); stuObjDHOP.pElement[i].pStruct.stringPos.y = structDataView.getUint16(6, true); stuObjDHOP.pElement[i].pStruct.chLineA = structDataView.getUint8(8, true);//字体颜色(ARGB) stuObjDHOP.pElement[i].pStruct.chLineR = structDataView.getUint8(9, true); stuObjDHOP.pElement[i].pStruct.chLineG = structDataView.getUint8(10, true); stuObjDHOP.pElement[i].pStruct.chLineB = structDataView.getUint8(11, true); stuObjDHOP.pElement[i].pStruct.chFontSize = structDataView.getUint8(12, true);//字体大小,单位px stuObjDHOP.pElement[i].pStruct.chFontAlign = structDataView.getUint8(13, true);//对齐方式 stuObjDHOP.pElement[i].pStruct.wTxtLen = structDataView.getUint16(14, true);//字符长度 var pString = structDataView.getUint32(16, true); var stringBuf = new ArrayBuffer(stuObjDHOP.pElement[i].pStruct.wTxtLen); var stringDataArray = new Uint8Array(stringBuf); var stringDataView = new DataView(stringBuf); stringDataArray.set(Module.HEAPU8.subarray(pString, pString + stuObjDHOP.pElement[i].pStruct.wTxtLen)); stuObjDHOP.pElement[i].pStruct.stringDataArray = stringDataArray; } } //解析DHOP信息内容 stuObjDHOP.nInfoLen = ivsDataView.getUint16(12, true);//信息长度 if (stuObjDHOP.nInfoLen > 0) { var pInfo = ivsDataView.getUint32(16, true); let infoBuf = new ArrayBuffer(nInfoLen); let infoDataArray = new Uint8Array(infoBuf); infoDataArray.set(Module.HEAPU8.subarray(pInfo, pInfo + nInfoLen)); stuObjDHOP.pInfo = infoDataArray; } pParseredBuf = stuObjDHOP; } else if (IVS_TYPE.IVSINFOTYPE_TAGGING_INFO == nType)//景物点信息标注帧 { let dataView = new DataView(ivsBuf); let tagInfoNum = nLen/FRAME_SCENE_POINTS_INFOR_SIZE; let tagInfos = []; for (let tagInfoIndex = 0; tagInfoIndex < tagInfoNum; tagInfoIndex++) { var tagInfo = {}; let Stride = FRAME_SCENE_POINTS_INFOR_SIZE * tagInfoIndex; //编号 tagInfo.nIndex = dataView.getInt32(Stride + 0, true); //景物点x坐标 tagInfo.xPoint = dataView.getUint16(Stride + 4, true); //景物点y坐标 tagInfo.yPoint = dataView.getUint16(Stride + 6, true); //一级名称 var jsNameBuf = new ArrayBuffer(64); jsNameBuf = ivsBuf.slice(Stride + 8); tagInfo.strName = ArrayBufferToStringAutoClip(jsNameBuf); //使能标记 tagInfo.enable = dataView.getInt8(Stride + 72, true); //标签类型 tagInfo.titleType = dataView.getInt8(Stride + 73, true); //标签属性 tagInfo.titleAttribute = dataView.getInt8(Stride + 74, true); tagInfo.sharpType = dataView.getInt8(Stride + 75, true); tagInfo.polygonNum = dataView.getInt8(Stride + 76, true); tagInfo.polygon = []; //与上一个中间空了三字节 for(let i = 0;i< tagInfo.polygonNum*2;i+=2) { tagInfo.polygon[i] ={x: dataView.getInt8(Stride + 79 + 2*i, true), y: dataView.getInt8(Stride + 79 + 2*(i+1), true)}; } tagInfos[tagInfoIndex] = tagInfo; jsNameBuf = null; } var msgType = 'ARTagInfoCallback'; var msgData = { tagInfo: tagInfos, } sendMessage(nPort, msgType, msgData); pParseredBuf = ivsDataArray; dataView = null; } else { pParseredBuf = ivsDataArray; } var msgType = 'IVSDataCallBack'; var msgData = { pBuf: pParseredBuf, nType: nType, nLen: nLen, nReallen: nReallen, } sendMessage(nPort, msgType, msgData); } function sendMessage(nPort, msgType, msgData) { var event = { nPort: nPort, msgType: msgType, msgData: msgData, }; postMessage(event); } function ArrayBufferToString(buffer, encoding = 'utf-8') { const decoder = new TextDecoder(encoding); return decoder.decode(buffer); } function ArrayBufferToStringAutoClip(buffer, encoding = 'utf-8') { const decoder = new TextDecoder(encoding); const uint8Array = new Uint8Array(buffer); let i = 0; while (i < uint8Array.length) { if (uint8Array[i] === 0) { break; } i++; } return decoder.decode(buffer.slice(0,i)); } function UTF16ToUTF8(UTF16Str) { var UTF8Arr = []; var byteSize = 0; for (var i = 0; i < UTF16Str.length; i++) { //获取字符Unicode码值 var code = UTF16Str.charCodeAt(i); //如果码值是1个字节的范围,则直接写入 if (code >= 0x00 && code <= 0x7f) { byteSize += 1; UTF8Arr.push(code); //如果码值是2个字节以上的范围,则按规则进行填充补码转换 } else if (code >= 0x80 && code <= 0x7ff) { byteSize += 2; UTF8Arr.push((192 | (31 & (code >> 6)))); UTF8Arr.push((128 | (63 & code))) } else if ((code >= 0x800 && code <= 0xd7ff) || (code >= 0xe000 && code <= 0xffff)) { byteSize += 3; UTF8Arr.push((224 | (15 & (code >> 12)))); UTF8Arr.push((128 | (63 & (code >> 6)))); UTF8Arr.push((128 | (63 & code))) } else if(code >= 0x10000 && code <= 0x10ffff) { byteSize += 4; UTF8Arr.push((240 | (7 & (code >> 18)))); UTF8Arr.push((128 | (63 & (code >> 12)))); UTF8Arr.push((128 | (63 & (code >> 6)))); UTF8Arr.push((128 | (63 & code))) } } return UTF8Arr }