ZLMediaKit/tests/DeviceHK/DeviceHK.cpp

268 lines
8.7 KiB
C++
Raw Normal View History

2017-05-11 11:26:45 +08:00
/*
2017-09-27 16:20:30 +08:00
* MIT License
2017-05-11 11:26:45 +08:00
*
2017-09-27 16:20:30 +08:00
* Copyright (c) 2016 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
2017-05-11 11:26:45 +08:00
*/
#ifdef ENABLE_HKDEVICE
#include "DeviceHK.h"
#include "Util/TimeTicker.h"
#include "Util/MD5.h"
namespace ZL {
namespace DEV {
#define HK_APP_NAME "live"
DeviceHK::DeviceHK() {
InfoL << endl;
static onceToken token( []() {
NET_DVR_Init();
NET_DVR_SetDVRMessageCallBack_V31([](LONG lCommand,NET_DVR_ALARMER *pAlarmer,char *pAlarmInfo,DWORD dwBufLen,void* pUser){
WarnL<<pAlarmInfo;
return TRUE;
},NULL);
}, []() {
NET_DVR_Cleanup();
});
}
DeviceHK::~DeviceHK() {
InfoL << endl;
}
void DeviceHK::connectDevice(const connectInfo &info, const connectCB& cb, int iTimeOut) {
NET_DVR_USER_LOGIN_INFO loginInfo;
NET_DVR_DEVICEINFO_V40 loginResult;
//login info
strcpy(loginInfo.sDeviceAddress, info.strDevIp.c_str());
loginInfo.wPort = info.ui16DevPort;
strcpy(loginInfo.sUserName, info.strUserName.c_str());
strcpy(loginInfo.sPassword, info.strPwd.c_str());
//callback info
typedef function< void(LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo)> hkLoginCB;
loginInfo.bUseAsynLogin = TRUE;
weak_ptr<Device> weakSelf = shared_from_this();
loginInfo.pUser = new hkLoginCB([weakSelf,cb](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo ) {
//TraceL<<lUserID<<" "<<dwResult<<" "<<lpDeviceInfo->sSerialNumber;
connectResult result;
if(dwResult==TRUE) {
result.strDevName=(char *)(lpDeviceInfo->sSerialNumber);
result.ui16ChnStart=lpDeviceInfo->byStartChan;
result.ui16ChnCount=lpDeviceInfo->byChanNum;
auto _strongSelf=weakSelf.lock();
if(_strongSelf) {
auto strongSelf=dynamic_pointer_cast<DeviceHK>(_strongSelf);
strongSelf->onConnected(lUserID,lpDeviceInfo);
}
} else {
WarnL<<"connect deviceHK failed:"<<NET_DVR_GetLastError();
}
cb(dwResult==TRUE,result);
});
loginInfo.cbLoginResult = [](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo , void* pUser) {
auto *fun=static_cast<hkLoginCB *>(pUser);
(*fun)(lUserID,dwResult,lpDeviceInfo);
delete fun;
};
NET_DVR_SetConnectTime(iTimeOut * 1000, 3);
NET_DVR_Login_V40(&loginInfo, &loginResult);
}
void DeviceHK::disconnect(const relustCB& cb) {
m_mapChannels.clear();
if (m_i64LoginId >= 0) {
NET_DVR_Logout(m_i64LoginId);
m_i64LoginId = -1;
Device::onDisconnected(true);
}
}
void DeviceHK::addChannel(int iChn, bool bMainStream) {
DevChannel::Ptr channel( new DevChannelHK(m_i64LoginId, (char *) m_deviceInfo.sSerialNumber, iChn, bMainStream));
m_mapChannels[iChn] = channel;
}
void DeviceHK::delChannel(int chn) {
m_mapChannels.erase(chn);
}
void DeviceHK::onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo) {
m_i64LoginId = lUserID;
m_deviceInfo = *lpDeviceInfo;
Device::onConnected();
}
void DeviceHK::addAllChannel(bool bMainStream) {
InfoL << endl;
for (int i = 0; i < m_deviceInfo.byChanNum; i++) {
addChannel(m_deviceInfo.byStartChan + i, bMainStream);
}
}
DevChannelHK::DevChannelHK(int64_t i64LoginId, const char* pcDevName, int iChn, bool bMainStream) :
DevChannel(HK_APP_NAME,(StrPrinter<<MD5(pcDevName).hexdigest()<<"_"<<iChn<<endl).data()),
m_i64LoginId(i64LoginId) {
InfoL << endl;
NET_DVR_PREVIEWINFO previewInfo;
previewInfo.lChannel = iChn; //通道号
previewInfo.dwStreamType = bMainStream ? 0 : 1; // 码流类型0-主码流1-子码流2-码流33-码流4 等以此类推
previewInfo.dwLinkMode = 1; // 0TCP方式,1UDP方式,2多播方式,3 - RTP方式4-RTP/RTSP,5-RSTP/HTTP
previewInfo.hPlayWnd = 0; //播放窗口的句柄,为NULL表示不播放图象
previewInfo.byProtoType = 0; //应用层取流协议0-私有协议1-RTSP协议
previewInfo.dwDisplayBufNum = 1; //播放库播放缓冲区最大缓冲帧数范围1-50置0时默认为1
previewInfo.bBlocked = 0;
m_i64PreviewHandle = NET_DVR_RealPlay_V40(m_i64LoginId, &previewInfo,
[](LONG lPlayHandle,DWORD dwDataType,BYTE *pBuffer,DWORD dwBufSize,void* pUser) {
DevChannelHK *self=reinterpret_cast<DevChannelHK *>(pUser);
if(self->m_i64PreviewHandle!=(int64_t)lPlayHandle) {
return;
}
self->onPreview(dwDataType,pBuffer,dwBufSize);
}, this);
if (m_i64PreviewHandle == -1) {
throw std::runtime_error( StrPrinter << "设备[" << pcDevName << "/" << iChn << "]开始实时预览失败:"
<< NET_DVR_GetLastError() << endl);
}
}
DevChannelHK::~DevChannelHK() {
InfoL << endl;
if (m_i64PreviewHandle >= 0) {
NET_DVR_StopRealPlay(m_i64PreviewHandle);
m_i64PreviewHandle = -1;
}
if (m_iPlayHandle >= 0) {
PlayM4_StopSoundShare(m_iPlayHandle);
PlayM4_Stop(m_iPlayHandle);
m_iPlayHandle = -1;
}
}
void DevChannelHK::onPreview(DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize) {
//TimeTicker1(-1);
switch (dwDataType) {
case NET_DVR_SYSHEAD: { //系统头数据
if (!PlayM4_GetPort(&m_iPlayHandle)) { //获取播放库未使用的通道号
WarnL << "PlayM4_GetPort:" << NET_DVR_GetLastError();
break;
}
if (dwBufSize > 0) {
if (!PlayM4_SetStreamOpenMode(m_iPlayHandle, STREAME_REALTIME)) { //设置实时流播放模式
WarnL << "PlayM4_SetStreamOpenMode:" << NET_DVR_GetLastError();
break;
}
if (!PlayM4_OpenStream(m_iPlayHandle, pBuffer, dwBufSize,
1024 * 1024)) { //打开流接口
WarnL << "PlayM4_OpenStream:" << NET_DVR_GetLastError();
break;
}
PlayM4_SetDecCallBackMend(m_iPlayHandle,
[](int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2) {
DevChannelHK *chn=reinterpret_cast<DevChannelHK *>(nUser);
if(chn->m_iPlayHandle!=nPort) {
return;
}
chn->onGetDecData(pBuf,nSize,pFrameInfo);
}, this);
if (!PlayM4_Play(m_iPlayHandle, 0)) { //播放开始
WarnL << "PlayM4_Play:" << NET_DVR_GetLastError();
break;
}
InfoL << "设置解码器成功!" << endl;
//打开音频解码, 需要码流是复合流
if (!PlayM4_PlaySoundShare(m_iPlayHandle)) {
WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError();
break;
}
}
}
break;
case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据)
if (dwBufSize > 0 && m_iPlayHandle != -1) {
if (!PlayM4_InputData(m_iPlayHandle, pBuffer, dwBufSize)) {
WarnL << "PlayM4_InputData:" << NET_DVR_GetLastError();
break;
}
}
}
break;
case NET_DVR_AUDIOSTREAMDATA: { //音频数据
}
break;
case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息
}
break;
default:
break;
}
}
void DevChannelHK::onGetDecData(char* pBuf, int nSize, FRAME_INFO* pFrameInfo) {
//InfoL << pFrameInfo->nType;
switch (pFrameInfo->nType) {
case T_YV12: {
if (!m_bVideoSeted) {
m_bVideoSeted = true;
VideoInfo video;
video.iWidth = pFrameInfo->nWidth;
video.iHeight = pFrameInfo->nHeight;
video.iFrameRate = pFrameInfo->nFrameRate;
initVideo(video);
}
char *yuv[3];
int yuv_len[3];
yuv_len[0] = pFrameInfo->nWidth;
yuv_len[1] = pFrameInfo->nWidth / 2;
yuv_len[2] = pFrameInfo->nWidth / 2;
int dwOffset_Y = pFrameInfo->nWidth * pFrameInfo->nHeight;
yuv[0] = pBuf;
yuv[2] = yuv[0] + dwOffset_Y;
yuv[1] = yuv[2] + dwOffset_Y / 4;
inputYUV(yuv, yuv_len, pFrameInfo->nStamp);
}
break;
case T_AUDIO16: {
if (!m_bAudioSeted) {
m_bAudioSeted = true;
AudioInfo audio;
audio.iChannel = pFrameInfo->nWidth;
audio.iSampleBit = pFrameInfo->nHeight;
audio.iSampleRate = pFrameInfo->nFrameRate;
initAudio(audio);
}
inputPCM(pBuf, nSize, pFrameInfo->nStamp);
}
break;
default:
break;
}
}
} /* namespace DEV */
} /* namespace ZL */
#endif //ENABLE_HKDEVICE