You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
9.5KB

  1. /*
  2. * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
  3. *
  4. * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
  5. *
  6. * Use of this source code is governed by MIT license that can be found in the
  7. * LICENSE file in the root of the source tree. All contributing project authors
  8. * may be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifdef ENABLE_HKDEVICE
  11. #include "DeviceHK.h"
  12. #include "Util/TimeTicker.h"
  13. #include "Util/MD5.h"
  14. namespace mediakit {
  15. #define HK_APP_NAME "live"
  16. DeviceHK::DeviceHK() {
  17. InfoL << endl;
  18. static onceToken token( []() {
  19. NET_DVR_Init();
  20. NET_DVR_SetDVRMessageCallBack_V31([](LONG lCommand,NET_DVR_ALARMER *pAlarmer,char *pAlarmInfo,DWORD dwBufLen,void* pUser){
  21. WarnL<<pAlarmInfo;
  22. return TRUE;
  23. },NULL);
  24. }, []() {
  25. NET_DVR_Cleanup();
  26. });
  27. }
  28. DeviceHK::~DeviceHK() {
  29. InfoL << endl;
  30. }
  31. void DeviceHK::connectDevice(const connectInfo &info, const connectCB& cb, int iTimeOut) {
  32. NET_DVR_USER_LOGIN_INFO loginInfo;
  33. NET_DVR_DEVICEINFO_V40 loginResult;
  34. //login info
  35. strcpy(loginInfo.sDeviceAddress, info.strDevIp.c_str());
  36. loginInfo.wPort = info.ui16DevPort;
  37. strcpy(loginInfo.sUserName, info.strUserName.c_str());
  38. strcpy(loginInfo.sPassword, info.strPwd.c_str());
  39. //callback info
  40. typedef function< void(LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo)> hkLoginCB;
  41. loginInfo.bUseAsynLogin = TRUE;
  42. weak_ptr<Device> weakSelf = shared_from_this();
  43. loginInfo.pUser = new hkLoginCB([weakSelf,cb](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo ) {
  44. //TraceL<<lUserID<<" "<<dwResult<<" "<<lpDeviceInfo->sSerialNumber;
  45. connectResult result;
  46. if(dwResult==TRUE) {
  47. result.strDevName=(char *)(lpDeviceInfo->sSerialNumber);
  48. result.ui16ChnStart=lpDeviceInfo->byStartChan;
  49. result.ui16ChnCount=lpDeviceInfo->byChanNum;
  50. auto _strongSelf=weakSelf.lock();
  51. if(_strongSelf) {
  52. auto strongSelf=dynamic_pointer_cast<DeviceHK>(_strongSelf);
  53. strongSelf->onConnected(lUserID,lpDeviceInfo);
  54. }
  55. } else {
  56. WarnL<<"connect deviceHK failed:"<<NET_DVR_GetLastError();
  57. }
  58. cb(dwResult==TRUE,result);
  59. });
  60. loginInfo.cbLoginResult = [](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo , void* pUser) {
  61. auto *fun=static_cast<hkLoginCB *>(pUser);
  62. (*fun)(lUserID,dwResult,lpDeviceInfo);
  63. delete fun;
  64. };
  65. NET_DVR_SetConnectTime(iTimeOut * 1000, 3);
  66. NET_DVR_Login_V40(&loginInfo, &loginResult);
  67. }
  68. void DeviceHK::disconnect(const relustCB& cb) {
  69. m_mapChannels.clear();
  70. if (m_i64LoginId >= 0) {
  71. NET_DVR_Logout(m_i64LoginId);
  72. m_i64LoginId = -1;
  73. Device::onDisconnected(true);
  74. }
  75. }
  76. void DeviceHK::addChannel(int iChn, bool bMainStream) {
  77. DevChannel::Ptr channel( new DevChannelHK(m_i64LoginId, (char *) m_deviceInfo.sSerialNumber, iChn, bMainStream));
  78. m_mapChannels[iChn] = channel;
  79. }
  80. void DeviceHK::delChannel(int chn) {
  81. m_mapChannels.erase(chn);
  82. }
  83. void DeviceHK::onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo) {
  84. m_i64LoginId = lUserID;
  85. m_deviceInfo = *lpDeviceInfo;
  86. Device::onConnected();
  87. }
  88. void DeviceHK::addAllChannel(bool bMainStream) {
  89. InfoL << endl;
  90. for (int i = 0; i < m_deviceInfo.byChanNum; i++) {
  91. addChannel(m_deviceInfo.byStartChan + i, bMainStream);
  92. }
  93. }
  94. DevChannelHK::DevChannelHK(int64_t i64LoginId, const char* pcDevName, int iChn, bool bMainStream) :
  95. DevChannel(HK_APP_NAME,(StrPrinter<<MD5(pcDevName).hexdigest()<<"_"<<iChn<<endl).data()),
  96. m_i64LoginId(i64LoginId) {
  97. InfoL << endl;
  98. NET_DVR_PREVIEWINFO previewInfo;
  99. previewInfo.lChannel = iChn; //通道号
  100. previewInfo.dwStreamType = bMainStream ? 0 : 1; // 码流类型,0-主码流,1-子码流,2-码流3,3-码流4 等以此类推
  101. previewInfo.dwLinkMode = 1; // 0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-RTP/RTSP,5-RSTP/HTTP
  102. previewInfo.hPlayWnd = 0; //播放窗口的句柄,为NULL表示不播放图象
  103. previewInfo.byProtoType = 0; //应用层取流协议,0-私有协议,1-RTSP协议
  104. previewInfo.dwDisplayBufNum = 1; //播放库播放缓冲区最大缓冲帧数,范围1-50,置0时默认为1
  105. previewInfo.bBlocked = 0;
  106. m_i64PreviewHandle = NET_DVR_RealPlay_V40(m_i64LoginId, &previewInfo,
  107. [](LONG lPlayHandle,DWORD dwDataType,BYTE *pBuffer,DWORD dwBufSize,void* pUser) {
  108. DevChannelHK *self=reinterpret_cast<DevChannelHK *>(pUser);
  109. if(self->m_i64PreviewHandle!=(int64_t)lPlayHandle) {
  110. return;
  111. }
  112. self->onPreview(dwDataType,pBuffer,dwBufSize);
  113. }, this);
  114. if (m_i64PreviewHandle == -1) {
  115. throw std::runtime_error( StrPrinter << "设备[" << pcDevName << "/" << iChn << "]开始实时预览失败:"
  116. << NET_DVR_GetLastError() << endl);
  117. }
  118. }
  119. DevChannelHK::~DevChannelHK() {
  120. InfoL << endl;
  121. if (m_i64PreviewHandle >= 0) {
  122. NET_DVR_StopRealPlay(m_i64PreviewHandle);
  123. m_i64PreviewHandle = -1;
  124. }
  125. if (m_iPlayHandle >= 0) {
  126. PlayM4_StopSoundShare(m_iPlayHandle);
  127. PlayM4_Stop(m_iPlayHandle);
  128. m_iPlayHandle = -1;
  129. }
  130. }
  131. void DevChannelHK::onPreview(DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize) {
  132. //TimeTicker1(-1);
  133. switch (dwDataType) {
  134. case NET_DVR_SYSHEAD: { //系统头数据
  135. if (!PlayM4_GetPort(&m_iPlayHandle)) { //获取播放库未使用的通道号
  136. WarnL << "PlayM4_GetPort:" << NET_DVR_GetLastError();
  137. break;
  138. }
  139. if (dwBufSize > 0) {
  140. if (!PlayM4_SetStreamOpenMode(m_iPlayHandle, STREAME_REALTIME)) { //设置实时流播放模式
  141. WarnL << "PlayM4_SetStreamOpenMode:" << NET_DVR_GetLastError();
  142. break;
  143. }
  144. if (!PlayM4_OpenStream(m_iPlayHandle, pBuffer, dwBufSize,
  145. 1024 * 1024)) { //打开流接口
  146. WarnL << "PlayM4_OpenStream:" << NET_DVR_GetLastError();
  147. break;
  148. }
  149. PlayM4_SetDecCallBackMend(m_iPlayHandle,
  150. [](int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2) {
  151. DevChannelHK *chn=reinterpret_cast<DevChannelHK *>(nUser);
  152. if(chn->m_iPlayHandle!=nPort) {
  153. return;
  154. }
  155. chn->onGetDecData(pBuf,nSize,pFrameInfo);
  156. }, this);
  157. if (!PlayM4_Play(m_iPlayHandle, 0)) { //播放开始
  158. WarnL << "PlayM4_Play:" << NET_DVR_GetLastError();
  159. break;
  160. }
  161. InfoL << "设置解码器成功!" << endl;
  162. //打开音频解码, 需要码流是复合流
  163. if (!PlayM4_PlaySoundShare(m_iPlayHandle)) {
  164. WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError();
  165. break;
  166. }
  167. }
  168. }
  169. break;
  170. case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据)
  171. if (dwBufSize > 0 && m_iPlayHandle != -1) {
  172. if (!PlayM4_InputData(m_iPlayHandle, pBuffer, dwBufSize)) {
  173. WarnL << "PlayM4_InputData:" << NET_DVR_GetLastError();
  174. break;
  175. }
  176. }
  177. }
  178. break;
  179. case NET_DVR_AUDIOSTREAMDATA: { //音频数据
  180. }
  181. break;
  182. case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息
  183. }
  184. break;
  185. default:
  186. break;
  187. }
  188. }
  189. void DevChannelHK::onGetDecData(char* pBuf, int nSize, FRAME_INFO* pFrameInfo) {
  190. //InfoL << pFrameInfo->nType;
  191. switch (pFrameInfo->nType) {
  192. case T_YV12: {
  193. if (!m_bVideoSeted) {
  194. m_bVideoSeted = true;
  195. VideoInfo video;
  196. video.iWidth = pFrameInfo->nWidth;
  197. video.iHeight = pFrameInfo->nHeight;
  198. video.iFrameRate = pFrameInfo->nFrameRate;
  199. initVideo(video);
  200. }
  201. char *yuv[3];
  202. int yuv_len[3];
  203. yuv_len[0] = pFrameInfo->nWidth;
  204. yuv_len[1] = pFrameInfo->nWidth / 2;
  205. yuv_len[2] = pFrameInfo->nWidth / 2;
  206. int dwOffset_Y = pFrameInfo->nWidth * pFrameInfo->nHeight;
  207. yuv[0] = pBuf;
  208. yuv[2] = yuv[0] + dwOffset_Y;
  209. yuv[1] = yuv[2] + dwOffset_Y / 4;
  210. inputYUV(yuv, yuv_len, pFrameInfo->nStamp);
  211. }
  212. break;
  213. case T_AUDIO16: {
  214. if (!m_bAudioSeted) {
  215. m_bAudioSeted = true;
  216. AudioInfo audio;
  217. audio.iChannel = pFrameInfo->nWidth;
  218. audio.iSampleBit = pFrameInfo->nHeight;
  219. audio.iSampleRate = pFrameInfo->nFrameRate;
  220. initAudio(audio);
  221. }
  222. inputPCM(pBuf, nSize, pFrameInfo->nStamp);
  223. }
  224. break;
  225. default:
  226. break;
  227. }
  228. }
  229. } /* namespace mediakit */
  230. #endif //ENABLE_HKDEVICE