近段对海康iOS二次开发时的一些实践和踩过的坑做一些关键总结,其目的是希望有类似需求的小伙伴们能取其精华,去其糟粕,快速上手开发,起到引导借鉴作用。
1.环境配置以及SDK导入
-
先将需要的静态库和系统框架导入工程中
-
根据海康提供的案例Demo,将以下文件导入到工程中
-
配置环境
-
文件引入
将调用海康SDK的VC后缀改为.mm 来支持C
2.网络配置
// 1.初始化SDK,调用网络SDK其他函数的前提 true表示成功 false表示失败
// 调用函数:NET_DVR_Init
BOOL bRet = NET_DVR_Init();
if (!bRet)
{
NSLog(@"设备登录失败");
}
// 2.配置网络异常回调
NET_DVR_SetExceptionCallBack_V30(0, NULL, g_fExceptionCallBack, NULL);
// 2.1网络异常回调方法
void g_fExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
{
NSLog(@"g_fExceptionCallBack Type[0x%x], UserID[%d], Handle[%d]", dwType, lUserID, lHandle);
}
// 3.开启日志记录(可选)
NET_DVR_SetLogToFile(3, (char*)pDir, true);
3.登录操作
// 1.将登录信息(IP、端口、登录账号、密码)存入DeviceInfo的实例对象,该对象是登录
DeviceInfo *deviceInfo = [[DeviceInfo alloc] init];
deviceInfo.chDeviceAddr = iP;
deviceInfo.nDevicePort = [port integerValue];
deviceInfo.chLoginName = usrName;
deviceInfo.chPassWord = password;
// 2.配置设备参数,此时可配置可不配置,登录成功后即可获取设备信息
NET_DVR_DEVICEINFO_V30 logindeviceInfo = {0};
// 3.登录设备,NET_DVR_Login_V30返回-1代表登录失败,其他数字表示用户ID(具有唯一性)
// 注意:返回-1可通过NET_DVR_GetLastError或NET_DVR_GetErrorMsg获取错误码或错误信息
m_lUserID = NET_DVR_Login_V30((char*)[deviceInfo.chDeviceAddr UTF8String],
deviceInfo.nDevicePort,
(char*)[deviceInfo.chLoginName cStringUsingEncoding:enc],
(char*)[deviceInfo.chPassWord UTF8String],
&logindeviceInfo);
// 4.登录成功后,存储模拟通道起始通道号和模拟通道个数,通道个数代表该IP下具有设备个数
// 注意:后续的云台操作和显示视频图像个数需要分别通过通道号和通道个数进行配置或创建
g_iStartChan = logindeviceInfo.byStartChan;
g_iPreviewChanNum = logindeviceInfo.byChanNum;
4.登出操作
// m_lUserID为登录时调用NET_DVR_Login_V30返回的UserId
NET_DVR_Logout(m_lUserID);
4.在线预览
// 1.配置预览参数
NET_DVR_PREVIEWINFO struPreviewInfo = {0};
// 设置通道:起始通道号为第一台设备,随后递增1,可通过上文g_iStartChan和g_iPreviewChanNum进行设置
struPreviewInfo.lChannel = iStartChan + iIndex;
// 码流类型
struPreviewInfo.dwStreamType = 1;
// 取流方式:阻塞取流
struPreviewInfo.bBlocked = 1;
// pView即要展示的UIView的实例对象
struPreviewInfo.hPlayWnd = pView;
// 2.开始进行预览 返回-1表示预览失败 其他数字表示当前播放数据识别号,具有唯一性
// 说明:g_structHandle为一个结构体,用于存储播放相关的具体参数
g_structHandle[iIndex].iPreviewID = NET_DVR_RealPlay_V40(iUserID, &struPreviewInfo, NULL, NULL);
// 3.配置数据响应回调
if(!NET_DVR_SetStandardDataCallBack(g_structHandle[iIndex].iPreviewID, g_fStdDataCallBack, iIndex))
{
// 返回错误信息
return -1;
}
// 4.实现回调 目的是为了取流并将接受的事实数据显示UIView上
void CALLBACK g_fStdDataCallBack(LONG lReadHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, DWORD pUser)
{
HANDLE_STRUCT *pHandle = &g_structHandle[0];
switch(dwDataType)
{
// 第一段视频流的操作
case NET_DVR_SYSHEAD:
// 先查看通道是否被占用
if(pHandle->iPlayPort != -1)
{
break;
}
// 如果没有,获取播放库通道号
if(!PlayM4_GetPort(&pHandle->iPlayPort))
{
break;
}
// 如果有数据
if(dwBufSize > 0)
{
// 设置流播放模式 默认实时流模式
if(!PlayM4_SetStreamOpenMode(pHandle->iPlayPort, STREAME_REALTIME))
{
NSLog(@"PlayM4_SetStreamOpenMode failed:%d", PlayM4_GetLastError(pHandle->iPlayPort));
break;
}
// 打开流,设置播放通道号 文件头数据 文件头长度 播放器存放数据流缓冲区大小
if(!PlayM4_OpenStream(pHandle->iPlayPort, pBuffer, dwBufSize, 2*1024*1024))
{
NSLog(@"PlayM4_OpenStream failed:%d", PlayM4_GetLastError(pHandle->iPlayPort));
break;
}
// 异步主线程开启播放
dispatch_async(dispatch_get_main_queue(), ^{
if(!PlayM4_Play(pHandle->iPlayPort, pHandle->pView))
{
NSLog(@"PlayM4_Play fail");
}
});
}
break;
default:
// 后续数据处理只需要判断是否有数据且通道号是否已被占用
if(dwBufSize > 0 && pHandle->iPlayPort != -1)
{
// 输入数据流
if(!PlayM4_InputData(pHandle->iPlayPort, pBuffer, dwBufSize))
{
NSLog(@"PlayM4_InputData failed:%d", PlayM4_GetLastError(pHandle->iPlayPort));
break;
}
}
}
}
5.停止预览
// 传入参数为开始预览调用NET_DVR_RealPlay_V40返回的PreviewID
BOOL isSuc = NET_DVR_StopRealPlay(iPreviewID)
if(!isSuc){
NSLog(@"操作失败,错误信息为:%s",NET_DVR_GetErrorMsg());
}
6.云台操作
1.每一个云台操作都是开始和结束成对出现,千万不可只开始无结束,因操作独占资源,结果为其他操作无法响应
2.云台操作分预览时操作和非预览时操作,下文将对预览时操作和非预览时操作进行逐一介绍
// 以一种云台操作为例,其他云台操作以此类推
/*****非预览时操作,此操作也可在预览时使用*****/
// 1.判断是否已登录并成功获取UserID,返回错误信息
if (m_lUserID < 0) {
// 输出错误信息
return;
}
// 2.云台抬头操作。
// 第二个参数为设备通道号,代表具体某个设备
// 第三个参数为动作类型 这里的操作是抬头 可根据宏列表选填
BOOL isSuc = NET_DVR_PTZControl_Other(m_lUserID, g_iStartChan, TILT_UP, 0)
// 2.1.返回BOOL判断操作是否成功,失败时提示用户。
if(!isSuc){
NSLog(@"操作失败,错误信息为:%s",NET_DVR_GetErrorMsg());
}
// 3.结束操作
BOOL isEndSuc = NET_DVR_PTZControl_Other(m_lUserID, g_iStartChan, TILT_UP, 1)
if(!isEndSuc){
NSLog(@"操作失败,错误信息为:%s",NET_DVR_GetErrorMsg());
}
/*****预览时操作*****/
// 1.判断是否已登录并成功获取UserID,返回错误信息
if (m_lUserID < 0) {
// 输出错误信息
return;
}
// 2.判断是否正在进行预览
if (iPreviewID < 0) {
// 输出错误信息
return;
}
// 3.若已登录,并在预览,进行监控设备抬头操作,第二个参数为设备通道号,代表具体某个设备。
BOOL isSuc = NET_DVR_PTZControlDVR(g_iStartChan, TILT_UP, 1)
// 3.1.返回BOOL判断操作是否成功,失败时提示用户。
if(!isSuc){
NSLog(@"操作失败,错误信息为:%s",NET_DVR_GetErrorMsg());
}
// 4.结束操作
BOOL isEndSuc = NET_DVR_PTZControlDVR(g_iStartChan, TILT_UP, 0)
if(!isEndSuc){
NSLog(@"操作失败,错误信息为:%s",NET_DVR_GetErrorMsg());
}