ngswfx

ngswfx

2个粉丝

55

问答

1

专栏

40

资料

ngswfx  发布于  2016-04-19 23:02:09
采纳率 0%
55个问答
6007

各厂家NVR流 直接获取ARM_SDK项目

 
本帖最后由 ngswfx 于 2016-4-25 09:03 编辑

最近在做3520D解码,需要连接支持HB NVR录像机,和其他家的设备。

目前搞定的不多,主要由于厂商不公开技术,所以只能自己摸索。

最有意思的是天视通,竟然有基于ARM的SDK开发包,让我大跌眼睛。呵呵。所以天视通的设备直接就支持了。

至于IPC,直接使用RTSP以及Onvif等,支持起来只是自己努力即可解决的。但实际使用中,通常希望不去连接IPC,而是希望连接NVR,这样更有实际意义。
这主要由于,IPC地址可能和NVR不同,项目中,IPC数量庞大,如果都用IPC的IP地址添加到平台中,列表太大,NVR会方便一些,而且便于分类管理。
另外:由于NVR通常位于监控中心,网络带宽方面有优势,对系统影响小。

因为NVR资源配置会丰富一些,主要还是软件平台管理起来方便写。

但NVR嘛,海康,大华好说,好像支持RTSP方式取流,我还没实际测试,估计问题不大。


汉邦NVR不支持RTSP取流,厂家也没提供基于ARM的SDK。呵呵,只能自己研究,写一个了。

通过网络侦测windowsSDK发送的数据流,我也仿照发送,并根据实际流需求情况,改变通道号等信息。

好在,实验成功。HB目前基本完美连接。

有兴趣的朋友,可以用这个办法取流。

DH的也通过了,只不过过来的数据流特殊,有私有数据,目前还没有过滤成功(2016_4_27已经解决,方法见下文),所以解出来会花屏。谁能过滤,或者有过滤方法,可以告诉我,学习一下。

目前下阶段会考虑数据对比,就是把能解的流和原始流都保存,仔细对比研究,然后过滤。

HK的,主要登陆流程里面加密太多,对于这些信息的计算没有搞定,所以失败了。暂无法登陆,由于这个登陆号会存在一段时间,我先用windowsSDK得到登陆号,然后再让ARM使用,也能得到视频数据,也就是说,难度在获取4个字节的登陆号。


//////////////////项目最新进展2016_4_27 库大小70K左右:
HB,全设备兼容,包括DVR,NVR,IPC直连
DH,全设备兼容,包括DVR,NVR,IPC直连,最新NVR(2015.1.19号FIRMWARE)登陆方式有些区别,命令格式32字节命令+内容方式:
命令F4开头,后面第5字节为内容长度,其他字符都是0
内容实例如下:不同的连接过程,内容不同,下面的内容就是连接第4通道的主码流。
Method:GetParameterNames
        ParameterName:Dahua.Device.Network.Monitor.General
        channel:3   //从0开始
        state:1
        ConnectionID:270
        stream:0
HK:验证过不去,暂放弃,主要就是搞不顶那个登陆号。由于HK设备NVR,直接支持RTSP取所有通道流,项目实际使用暂不是问题。
////////////////////////////////
XM(雄迈):,估计问题不大,和大华类似,都是一堆内容串,仿照着发送即可。
//过滤掉原始数据中以0x000001ff开头数据后面20字节,导入解码器,这个是主码流。
//过滤掉原始数据中以0x000101ff开头数据后面20字节,导入解码器,这个是子码流。
//XM IPC已经OK,NVR需要实际验证
ZW(中维):IPC 经过验证OK,NVR需要实际验证


本SDK项目基本想法:直接使用自己写的连视频SDK,在ARM上获取流,做到简单高效。基本兼容国内主流品牌NVR。库文件大小控制在300K以内。


我来回答
回答10个
时间排序
认可量排序

ngswfx

2个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-19 23:04:05
认可0
大华的NVR不知道是否支持RTSP取流,我不明确,没测试过。

我写的取数据流部分也通了。NVR,DVR,IPC都可以

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool bDHIPC=true;
int CNVRLink::nvr_cmd_login_DH(NVR_DEVICEINFO_EX *deviceInf)
{
        printf("DH login %s pos 1________________\n",strIP);
        char ip[32];
        sprintf(ip,"%s",strIP);
        int port=nPort;
        int ret=-1;
        struct sockaddr_in dest_addr;
        memset(&dest_addr,0,sizeof(dest_addr));
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_addr.s_addr = inet_addr(ip);
        dest_addr.sin_port = htons(port);
        if(fdLogin>0)
                close(fdLogin);
        fdLogin=im_socket_tcp_connect(&dest_addr);
        if (fdLogin<0){
                return 0;
        }
        ret=im_socket_tcp_connect_chk(fdLogin,-1);
        if (ret<0){
                if(fdLogin>0)
                        close(fdLogin);
                return 0;
        }
        char inBuff[MAX_CMD_BUFF_LEN];
        memset(inBuff,0,sizeof inBuff);
        char outBuff[MAX_CMD_BUFF_LEN];
        memset(outBuff,0,sizeof outBuff);
        struct cmd_head_DHEx *head=(struct cmd_head_DHEx *)outBuff;
        /////////////////////////////////////////step 1
        cmd_UserName_DHEx usernameStrc;
        memset(&usernameStrc,0,sizeof(usernameStrc));
        sprintf((char *)usernameStrc.username,UserName);
        sprintf((char *)usernameStrc.password,PassWord);
        usernameStrc.cmd1=0x600000A0;
        if(!bDHIPC)
        usernameStrc.cmd3=0x00000104;
        else
        usernameStrc.cmd3=0x00000105;
        usernameStrc.cmd4=0xAAA10000;
        //发送A0 00 00 60 00 00 00 00 61 64 6D 69 6E 00 00 00 61 64 6D 69 6E 00 00 00 04 01 00 00 00 00 A1 AA
        ret=tcp_write(fdLogin,(char*)&usernameStrc,32);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                return 0;
        }
        printf("DH login %s pos 2________________\n",strIP);
        usleep(10*1000);
        //返回32字节B0 00 00 58 00 00 00 00 00 08 04 08 42 00 00 00 0F 00 00 00 01 00 00 00 06 00 F9 00 00 04 64 02
        ret=tcp_read(fdLogin,inBuff,32);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                return 0;
        }
        printf("DH login %s pos 3________________\n",strIP);
        memcpy(strLoginID,inBuff+16,4);
        nLoginID=(unsigned int)strLoginID;
        memset(inBuff,0,32);
        //利用这个发送一次心跳流程
        memset(outBuff,0,sizeof outBuff);
        memset(head,0,sizeof head);
        head->cmd1=0xA1;
        //发送A1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,(char*)head,32);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                return 0;
        }
        printf("DH login %s pos 4________________\n",strIP);
        //返回32字节B1 00 00 58 00 00 00 00 00 00 00 00 00 FD 00 00 00 00 00 00 0F 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_read(fdLogin,inBuff,320);
        if (ret<0){
                if(fdLogin>0)
                        close(fdLogin);
                return 0;
        }
        memset(inBuff,0,32);
        ////////////////////////////////////////创建一个全新的端口SOCKET////////////
        if(fdLogin2>0)
                close(fdLogin2);
        fdLogin2=im_socket_tcp_connect(&dest_addr);
        if (fdLogin2<0){
                if(fdLogin>0)
                        close(fdLogin);
                return 0;
        }
        ret=im_socket_tcp_connect_chk(fdLogin2,-1);
        if (ret<0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        //////////////////////////////////////////step 2
        //2:客户端利用socket2紧接着发送32字节数据:
        //其中:F1 00 00 00 00 00 00 00 0F 00 00 00 02 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        memset(outBuff,0,sizeof outBuff);
        head->cmd1=0xF1;
        head->cmd3=nLoginID;
        if(!bDHIPC)
        head->cmd4=0x00000502;
        else
        head->cmd4=0x00000202;
        //socket 2发送32个字节
        memcpy(outBuff,head,32);
        memcpy(outBuff+8,strLoginID,4);
        ret=tcp_write(fdLogin2,(char*)outBuff,32);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        printf("DH login %s pos 5________________\n",strIP);
        //socket 2设备返回32:
        //F1 00 00 58 00 00 00 00 11 00 00 00 02 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_read(fdLogin2,inBuff,32);//32
        if (ret<0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        memset(inBuff,0,32);
        //////////////////////////////////////////steop 3  socket1发送命令
        memset(outBuff,0,sizeof outBuff);
        memset(head,0,sizeof head);
        head->cmd1=0xA4;
        head->cmd3=0x01;
        //socket 1发送32个字节
        //A4 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,(char*)head,32);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        printf("DH login %s pos 6________________\n",strIP);
        //socket 1设备返回64:
        //B4 00 00 58 20 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //02 3C 04 02 00 00 04 01 02 00 00 00 DB 07 07 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_read(fdLogin,inBuff,64);
        if (ret<0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        memset(inBuff,0,32);
        //////////////////////////////////////////step 4 socket 1
        memset(outBuff,0,sizeof outBuff);
        memset(head,0,sizeof head);
        head->cmd1=0xA4;
        head->cmd3=0x07;
        printf("DH login %s pos 7________________\n",strIP);
        //socket 1发送32个字节
        //A4 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,(char*)head,32);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        printf("DH login %s pos 8________________\n",strIP);
        //socket 1设备返回54:
        //B4 00 00 58 16 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //50 41 31 4B 46 30 33 32 30 31 30 34 35 00 00 00 00 00 00 00 00 00
        ret=tcp_read(fdLogin,inBuff,54);//47 54
        if (ret<0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        memset(inBuff,0,54);
        //////////////////////////////////////////step 5 socket 1
        memset(outBuff,0,sizeof outBuff);
        memset(head,0,sizeof head);
        head->cmd1=0xA4;
        head->cmd3=0x02;
        printf("DH login %s pos 9________________\n",strIP);
        //socket 1发送32个字节
        //A4 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,(char*)head,32);//32
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        //socket 1设备返回320:
        /*B4 00 00 58 20 01 00 00 02 00 00 00 00 00 00 00
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00*/
        printf("DH login %s pos 10________________\n",strIP);
        ret=tcp_read(fdLogin,inBuff,320);
        if (ret<=0){
                if(fdLogin>0)
                        close(fdLogin);
                if(fdLogin2>0)
                        close(fdLogin2);
                return 0;
        }
        memset(inBuff,0,320);
        ///////////////////////////////////////////////////////////
        printf("DH login OK\n");
        nLoginID=fdLogin;
        //到这里,登录算是成功了
        bLoginSuccess=true;
        lastLoginAliveTimer=GetTickCount();
        pthread_attr_t attr;
        ret = pthread_attr_init(&attr);
        ret = pthread_attr_setstacksize(&attr, 32*1024);
        if(!lThreadLogin)
                ret=pthread_create(&lThreadLogin,&attr,LoginAliveThread,this);
        pthread_attr_destroy(&attr);

        return 1;
}
int CNVRLink::Logout_Cmd_DH()
{
        if(fdLogin<1)
                return 0;
        int ret=-1;
        char outBuff[MAX_CMD_BUFF_LEN];
        memset(outBuff,0,sizeof outBuff);
        struct cmd_head_DHEx *head=(struct cmd_head_DHEx *)outBuff;
        /////////////////////////////////////////step 1
        head->cmd1=0x0A;
        head->cmd3=nLoginID;
        memcpy(outBuff+8,strLoginID,4);
        //发送0A 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,outBuff,32);
        if (ret<=0)
                return 0;
        //设备返回 32字节 0B 00 00 58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_read(fdLogin,outBuff,32);
        if (ret<=0)
                return 0;
        return 1;
}
int CNVRLink::HeartAlive_Cmd_DH()
{
        if(fdLogin<1)
                return 0;
        int ret=-1;
        char outBuff[MAX_CMD_BUFF_LEN];
        memset(outBuff,0,sizeof outBuff);
        struct cmd_head_DHEx *head=(struct cmd_head_DHEx *)outBuff;
        /////////////////////////////////////////step 1
        head->cmd1=0xA1;//心跳
        //printf("heart out:%x\n",outBuff[0]);
        //A1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,outBuff,32);
        if (ret<0)
                return 0;
        memset(outBuff,0,sizeof outBuff);
        //B1 00 00 58 00 00 00 00 00 00 00 00 00 FD 00 00 00 00 00 00 0F 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_read(fdLogin,outBuff,32);
        if (ret<0)
                return 0;
        //printf("DH heart in:%x\n",outBuff[0]);
        lastLoginAliveTimer=GetTickCount();
        return 1;
}
bool CNVRLink::ConnectChl_Cmd_DH(int nChannel,bool bLinkSub)
{
        char outBuff[MAX_CMD_BUFF_LEN];
        char inBuff[MAX_CMD_BUFF_LEN];
        memset(outBuff,0,sizeof outBuff);
        memset(inBuff,0,sizeof inBuff);       
        struct cmd_head_DHEx head;
        int _nChannelEx=nChannel;
        if(bLinkSub)//子码流后移32
                _nChannelEx=nChannel+MAX_DVR_CHL_NUM;
        int ret;
        ///////////////////
        //视频连接:
        //////////////////////////////////////////////////////////////////////
        //////////////////////////步骤1
        //创建视频端口lRealHandle socket    32字节   也有通道号 2通道
        //视频端口发送F1 00 00 00 00 00 00 00 2A 00 00 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //返回:      F1 00 00 58 00 00 00 00 2A 00 00 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //////////////第4通道
        //                        F1 00 00 00 00 00 00 00 30 00 00 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //                        F1 00 00 58 00 00 00 00 30 00 00 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
       
        // 0       F1 00 00 00 00 00 00 00 36 00 00 00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        // 1       F1 00 00 00 00 00 00 00 39 00 00 00 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        // 2       F1 00 00 00 00 00 00 00 3C 00 00 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        // 2       F1 00 00 00 00 00 00 00 2A 00 00 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        // 3       F1 00 00 00 00 00 00 00 30 00 00 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        // 3       F1 00 00 00 00 00 00 00 3F 00 00 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //         F1 00 00 00 00 00 00 00 09 00 00 00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

        /////////////////////////////////////////////////////////////////////////
        char ip[32];
        sprintf(ip,"%s",strIP);
        int port=nPort;
        struct sockaddr_in dest_addr;
        memset(&dest_addr,0,sizeof(dest_addr));
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_addr.s_addr = inet_addr(ip);
        dest_addr.sin_port = htons(port);
        RealSocket[_nChannelEx]=im_socket_tcp_connect(&dest_addr);
        if (RealSocket[_nChannelEx]<0){
                return false;
        }
        ret=im_socket_tcp_connect_chk(RealSocket[_nChannelEx],-1);
        if (ret<0){
                if(RealSocket[_nChannelEx]>0)
                        close(RealSocket[_nChannelEx]);
                return false;
        }
        ///////////////////////////
        //发送32个字节 F1 00 00 00 00 00 00 00 2A 00 00 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        memset(outBuff,0,sizeof outBuff);
        memset(&head,0,sizeof head);
        head.cmd1=0x000000F1;//F1 00 00 00
        head.cmd3=nLoginID;//2A 00 00 00
        if(!bDHIPC)
                head.cmd4=0x00000301;//01 03 00 00
        else
                head.cmd4=0x00000101;//01 01 00 00
        memcpy(outBuff,&head,sizeof (head));
        outBuff[13]=nChannel+1;
        memcpy(outBuff+8,strLoginID,4);
        ret=tcp_write(RealSocket[_nChannelEx],outBuff,32);
        if (ret<=0){
                if(RealSocket[_nChannelEx]>0)
                        close(RealSocket[_nChannelEx]);
                return false;
        }
        //返回32字节
        memset(inBuff,0,sizeof inBuff);
        ///F1 00 00 58 00 00 00 00 2A 00 00 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_read(RealSocket[_nChannelEx],inBuff,32);
        if (ret<=0){
                if(RealSocket[_nChannelEx]>0)
                        close(RealSocket[_nChannelEx]);
                return false;
        }
        //////////////////////////步骤2    48字节
        //loginID发送 11 00 00 00 10 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //////////////第4通道
        //                          11 00 00 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    //  0      // 11 00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        //  3      // 11 00 00 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

        //到此,视频端口就该有数据了
        ///////////////////////////////////////////////////
        memset(outBuff,0,sizeof outBuff);
        if(!bDHIPC)
                head.cmd1=0x00000011;//11 00 00 00
        else
                head.cmd1=0x01000011;//11 00 00 01
        head.cmd2=0x10;//10 00 00 00
        memcpy(outBuff,&head,sizeof (head));
        if(nChannel<32)
                outBuff[8+nChannel]=0x01;
        //这是最大24路的情况,如果路数更高,需要分析前面过来的数据
        //这里可能不同
        if(bLinkSub)
                outBuff[8+24+nChannel]=0x01;
        else
                outBuff[8+24+nChannel]=0x00;
        //发送48个字节
        ret=tcp_write(fdLogin,outBuff,48);
        if (ret<=0){
                if(RealSocket[_nChannelEx]>0)
                        close(RealSocket[_nChannelEx]);
                return false;
        }
        //到这里该有视频了
        bLinking[_nChannelEx]=true;
        return true;
}
int CNVRLink::DisconnectChl_Cmd_DH(int nChannel,bool bLinkSub)
{
        if(fdLogin<1)
                return 0;
        int  ret=-1;
        char outBuff[MAX_CMD_BUFF_LEN];
        memset(outBuff,0,sizeof outBuff);
        struct cmd_head_DHEx *head=(struct cmd_head_DHEx *)outBuff;
        /////////////////////////////////////////step 1
        head->cmd1=0x11;
        head->cmd2=0x10;
        //发送11 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        ret=tcp_write(fdLogin,outBuff,48);
        if (ret<=0){
                return 0;
        }
        return 1;
}
int CNVRLink::MakeKeyFrame_Cmd_DH(int nChannel,bool bLinkSubChl)
{
        return 0;
}
int CNVRLink::SolveDataIn_DH(int nChannel,bool bLinkSubChl,char *videoBuffer,int nLen)
{
        int _nServerChlEx=nChannel;
        if(bLinkSubChl)
                _nServerChlEx=nChannel+MAX_DVR_CHL_NUM;
        int nFrameType=0;
        char *outVideo=videoBuffer;
        int nSize=nLen;
        //printf("DH recv Data:%d in\n",nLen);
        //数据包中间,也可能会有64字节的头,需要循环处理
        /*bool bNotHeader=false;
        int nCurPos=0;
        int nStartCPpos=0;
        int nEndCPpos=nLen;
        int nCopyedPos=0;
        while(nCurPos<=nLen){
                //new IPC 72头是关键帧 64头P帧
                if((*(unsigned int*)(videoBuffer+nCurPos)==0x000000bc)||(*(unsigned int*)(videoBuffer+nCurPos)==0x00000018)){
                        if((nCurPos!=0)&&nCopyedPos==0){ //把从头到这个位置的数据先拷贝了
                                nEndCPpos=nCurPos;
                                nSize=nEndCPpos-nCopyedPos;
                                ParseGetInputVideo(_nServerChlEx,outVideo+nCopyedPos,nSize);
                                nCopyedPos=nCurPos;
                                nStartCPpos=nCurPos;
                                ///////////////////////////
                        }
                        while(nCurPos<=nLen){
                                if((*(unsigned int*)(videoBuffer+nCurPos)==0x01000000)){
                                        nStartCPpos=nCurPos;
                                        nCopyedPos=nCurPos;
                                        break;
                                }
                                nCurPos++;
                        }
                }
                //最后面有8个字节的DH标记64 68 61 76 57 4A 00 00  (57 4A 估计和时间有关,帧间时间)
                if((*(unsigned int*)(videoBuffer+nCurPos)==0x76616864)){
                        nEndCPpos=nCurPos;
                        nSize=nEndCPpos-nStartCPpos;
                        ParseGetInputVideo(_nServerChlEx,outVideo+nStartCPpos,nSize);
                        ///////////////////////
                        nCurPos+=8;
                        if(nCurPos==nLen)
                                return 0;
                        else{//还没有结束,可能还有头
                                nStartCPpos=nCurPos;
                                nCopyedPos=nCurPos;
                                continue;
                        }
                }
                nCurPos++;
                if(nCurPos==nLen){//已经到结尾处
                        nEndCPpos=nCurPos;
                        nSize=nEndCPpos-nCopyedPos;
                        ParseGetInputVideo(_nServerChlEx,outVideo+nCopyedPos,nSize);
                        nCopyedPos=nCurPos;
                        return 0;
                }
        }*/

        //if(_fDataCallBackEx&&bLinking[_nServerChlEx])
        //                _fDataCallBackEx((long)lThreadLink[_nServerChlEx],nFrameType,(unsigned char *)outVideo,nSize,dwUser[_nServerChlEx]);

#ifdef USE_DATA_PARSE_OUTPUT_ONE_FRAME
        ParseGetInputVideo(_nServerChlEx,outVideo,nSize);

#else
        if(_fDataCallBackEx&&bLinking[_nServerChlEx])
                _fDataCallBackEx((long)lThreadLink[_nServerChlEx],nFrameType,(unsigned char *)outVideo,nSize,dwUser[_nServerChlEx]);
#endif

        return 0;
}


ngswfx

2个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-19 23:26:23
认可0
本帖最后由 ngswfx 于 2016-4-19 23:29 编辑

HK  用户名改为0 密码空 ,交互数据大概如下:

步骤1,开启第一个TCP Socket,使用8000端口登录HK NVR 
第一个数据包84字节   包含用户名密码信息   加密了:(
00 00 00 54 5A 00 00 00 00 00 00 00 00 01 00 00
04 00 28 C1 00 00 00 00 75 02 A8 C0 F0 DE F1 58
9C 2F 00 00 63 74 62 58 63 73 58 58 62 73 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00



设备返回76字节  返回的数据加密了    :( ,要根据这个返回信息计算登录任务号呀,唉,咋整呀

00 00 00 4C 87 10 00 00 00 00 00 64 03 00 20 9C
4D 47 4A 6D 5A 44 63 78 59 7A 64 6A 5A 57 46 6C
4E 6D 45 30 4E 6A 46 69 5A 44 6B 77 4E 54 5A 68
59 6D 55 79 59 6A 49 31 4D 6D 59 3D 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00



步骤二:
开启另外socket2
发送32
00 00 00 20 63 00 00 00 00 00 00 00 00 11 01 50 65 04 A8 C0 5A 3A 2F DF F0 DE F1 58 9C 2F 00 00

注意:C0 5A 3A 2F DF F0
其中C0和F0是固定的,5A 3A 2F DF是变化的,是根据,前面动作返回的76字节数据计算出来的,如果这个数据能正确算出,就可以正常取流了。:lol


返回16  成功或者失败,这里的信息将不同,这个很关键,如果成功了,才能进行图像连接,否则都会失败
00 00 00 10 00 00 00 0D 00 00 00 0D 00 00 00 00



图像连接部分:


视频连接

开启一个视频端口socket
发送40字节  里面包含通道号
    00 00 00 28 63 00 00 00 00 00 00 00 00 03 00 00
65 04 A8 C0 5A 7E A3 4F F0 DE F1 58 9C 2F 00 00
00 00 00 01 00 00 00 00

命令发送出去,如果成功,视频端口socket就能收到一个文件头,64字节,以及视频数据了。 失败好像返回固定64字节内容,标识不允许访问,访问失败。

ngswfx

2个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-19 23:30:00
认可0
本帖最后由 ngswfx 于 2016-4-19 23:51 编辑

这种方法,如果各个厂家都简单提供交互命令计算细节的话,写一个支持所有设备图像连接的SDK,估计30K搞定,呵呵

要说那个TST ARM的SDK ,可是好几百K,如果HK自己把所有功能都ARM上编译,SDK估计都快1M的,就算厂商提供,我们也不会用呀,arm资源有限呀


前端时间HK出事,都是记者不懂行,瞎说,HK加密是最严格的,你看,我专业人员没搞定吧。


唉,垃圾视频数据,加什么密嘛,除了金库以及特定场合,视频录像数据都是垃圾数据。记者报社瞎操心。不想让人访问,改默认密码是基本常识。只要改了密码,能访问那才叫不安全。

或者密码明码传输,这也叫不安全。


想想,如果用这个方法,连接IPC,然后按照自己的方法处理图像数据,后续加工,或者流转,进入自己的管理平台,超级直接,不过不能干太多事,仅限于取预览图像。




zhuangweiye

8个粉丝

0

问答

0

专栏

0

资料

zhuangweiye 2016-04-20 08:10:38
认可0
HK的IPC在onvif下创建用户确实是发送的明文密码

falloutmx

1个粉丝

15

问答

0

专栏

0

资料

falloutmx 2016-04-20 09:06:35
认可0
大华NVR能支持SIP取流的话就能获取到RTP+PS的流,起码他们家的IPC可以。

ngswfx

2个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-20 12:43:24
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=28758&ptid=11053]zhuangweiye 发表于 2016-4-20 08:10[/url]
HK的IPC在onvif下创建用户确实是发送的明文密码[/quote]

我就喜欢明文,呵呵,随便连:lol

包龙兔

0个粉丝

14

问答

0

专栏

0

资料

包龙兔 2016-04-20 15:26:55
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=28809&ptid=11053]ngswfx 发表于 2016-4-20 12:43[/url]
我就喜欢明文,呵呵,随便连[/quote]

题主牛逼啊。 各种玩。

ngswfx

2个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-23 03:51:42
认可0
本帖最后由 ngswfx 于 2016-4-23 03:55 编辑

庆祝一下,大华的IPC数据解析搞定了,其实我想多了,对比了DH SDK出来的数据,其实就是找0xBC 0x00 0x00 0x00,需要遍历所有数据,只要发现这个头,就把后面的32字节抛弃就可以了.

这样就再送入HS解码器,就不花屏了,这意味着,估计NVR也是一样的.

int CNVRLink::SolveDataIn_DH(int nChannel,bool bLinkSubChl,char *videoBuffer,int nLen)
{
        int _nServerChlEx=nChannel;
        if(bLinkSubChl)
                _nServerChlEx=nChannel+MAX_DVR_CHL_NUM;
        int nFrameType=0;
        char *outVideo=videoBuffer;
        int nSize=nLen;
        //printf("DH recv Data:%d in\n",nLen);
        bool bNotHeader=false;
        int nCurPos=0;
        int nStartCPpos=0;
        int nEndCPpos=nLen;
        int nCopyedPos=0;

        while(nCurPos<=nLen){
                 //DH SDK仅仅舍弃了32字节,仿照做
                if((*(unsigned int*)(videoBuffer+nCurPos)==0x000000bc)){//||(*(unsigned int*)(videoBuffer+nCurPos)==0x00000018)){
                         //把从头到这个位置的数据先拷贝了
                                nEndCPpos=nCurPos;
                                nSize=nEndCPpos-nCopyedPos;
                                if(nSize>0){
                                        ParseGetInputVideo(_nServerChlEx,outVideo+nCopyedPos,nSize);
                                }
                                nCopyedPos=nCurPos+32;
                                nStartCPpos=nCurPos+32;
                                ///////////////////////////
                }
                nCurPos++;
                if(nCurPos==nLen){//已经到结尾处
                        nEndCPpos=nCurPos;
                        nSize=nEndCPpos-nCopyedPos;
                        ParseGetInputVideo(_nServerChlEx,outVideo+nCopyedPos,nSize);
                        nCopyedPos=nCurPos;
                        return 0;
                }
        }

        return 0;

}

函数
ParseGetInputVideo(_nServerChlEx,outVideo+nCopyedPos,nSize);

用来找出0001,然后将包进行常规组合为一个单独帧

cwyyy

0个粉丝

2

问答

0

专栏

0

资料

cwyyy 2016-06-27 09:28:37
认可0
LZ是大牛呀,有相关资料可分享的吗

csuzhsh

1个粉丝

14

问答

0

专栏

0

资料

csuzhsh 2016-06-29 21:22:39
认可0
向楼主学习
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区