海康iOS二次开发操作流程

近段对海康iOS二次开发时的一些实践和踩过的坑做一些关键总结,其目的是希望有类似需求的小伙伴们能取其精华,去其糟粕,快速上手开发,起到引导借鉴作用。

1.环境配置以及SDK导入

  1. 先将需要的静态库和系统框架导入工程中


    库导入
  2. 根据海康提供的案例Demo,将以下文件导入到工程中


    文件导入
  3. 配置环境


    配置1
配置1
  1. 文件引入
    将调用海康SDK的VC后缀改为.mm 来支持C


    后缀改为.mm
文件引入

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());
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,464评论 6 517
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 95,033评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 169,078评论 0 362
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,979评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,001评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,584评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,085评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,023评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,555评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,626评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,769评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,439评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,115评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,601评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,702评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,191评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,781评论 2 361

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,715评论 18 139
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,786评论 0 15
  • 如果你是跟孩子玩这个游戏 孩子会认识这些干果吗? 如果你不仅仅是让孩子认识这些干果 你还会有什么目的?
    毛作东阅读 199评论 0 1
  • 压着4月的尾巴,再次来到简书写东西,距离上次已经接近5个月。 昨天晚上看了《后来的我们》,在酒店房间小晓问见清:我...
    你不懂我一直在阅读 513评论 1 1
  • “尤梦,我这次真的要结婚了,真的!”眼前的女生吸了一口咖啡接着说到“以前真的都是玩的,看我手上的戒指,这次都订婚了...
    江南烟雨还有你阅读 332评论 3 3