N_QT

QT with 海康SDK

  1. 下载SDK
  2. PRO
//引入头文件
INCLUDEPATH += $$PWD/haikang/include
HEADERS += \
    haikang/include/DataType.h \
    haikang/include/DecodeCardSdk.h \
    haikang/include/HCNetSDK.h \
    haikang/include/plaympeg4.h
 
//引入lib库
LIBS += $$PWD/haikang/lib/HCNetSDK.lib   \
 $$PWD/haikang/lib/HCNetSDK.lib   \
 $$PWD/haikang/lib/HCCore.lib   \
 $$PWD/haikang/lib/PlayCtrl.lib   \
 $$PWD/haikang/lib/GdiPlus.lib   \

注意问题

  1. 运行还需要dll(运行库)

  2. 参数结构体初始化 NET_DVR_DEVICEINFO_V40 devinfo SDK报参数为nullptr错误. 可用NET_DVR_DEVICEINFO_V40 devinfo ={}初始化

  3. 需要包含 windows api #include <windows.h>

  • 大概代码
 
std::cout<<"NET_DVR_Init="<<  NET_DVR_Init()<<std::endl;
///开始
NET_DVR_USER_LOGIN_INFO info={0};
info.wPort = 8000;
 
std::string username = "admin";
strcpy_s( info.sUserName, NET_DVR_LOGIN_USERNAME_MAX_LEN, username.c_str());
 
std::string password = "abc123COM";
strcpy_s( info.sPassword, NET_DVR_LOGIN_PASSWD_MAX_LEN, password.c_str());
 
std::string addrss = "192.168.33.203";
strcpy_s( info.sDeviceAddress, NET_DVR_DEV_ADDRESS_MAX_LEN, addrss.c_str());
info.bUseAsynLogin = 0;//同步登陆
 
/*********************V4 登陆***********************************/
NET_DVR_DEVICEINFO_V40 devinfo ={};
devinfo.byCharEncodeType=0;
//登陆; 函数原型
//NET_DVR_API LONG __stdcall NET_DVR_Login_V40(LPNET_DVR_USER_LOGIN_INFO pLoginInfo,LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo);
LONG   loginID = NET_DVR_Login_V40(&info, &devinfo);
printLastError();

代码归档

代码归档

回调RTP流数据 NET_DVR_SetStandardDataCallBack

 
 
/**
  * @brief 数据回调
  * @param lRealHandle 当前的预览句柄
  * @param dwDataType dwDataType
  * @param pBuffer 存放数据的缓冲区指针
  * @param dwBufSize 缓冲区大小
  * @param dwUser 用户数据
  */
 void CALLBACK realStdDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer,DWORD dwBufSize,DWORD dwUser)
{
    //
    switch (dwDataType)
    {
    case NET_DVR_SYSHEAD:{ //系统头
        QFile hik_call_std("F:/test/stream/hik_call_std_HEAD.dat");
        if(hik_call_std.open( QIODevice::WriteOnly)){
          char *cp = (char*)(pBuffer);
          hik_call_std.write(cp, dwBufSize );
        }else{
           std::cout<<"------hik_call_std_HEAD open fail-----------"<<std::endl;
        }
          std::cout<<"------NET_DVR_SYSHEAD-----"<<std::endl;
        break;
    }
    case NET_DVR_STREAMDATA:{ //音视频复合流数据
          std::cout<<"------NET_DVR_STREAMDATA-----"<<dwBufSize<<std::endl;
          char *cp2 = (char*)(pBuffer);
          g_out_stream->writeRawData(cp2, dwBufSize);
        break;
    }
    }
}
//异常回调
 void CALLBACK exceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
 {
     char tempbuf[256] = {0};
     switch(dwType)
     {
     case EXCEPTION_RECONNECT:   //预览时重连
     printf("----------reconnect--------%d\n", time(nullptr));
     break;
     default:
     break;
     }
 }
 
 ///
int main(){
    // 初始化
     NET_DVR_Init();
     QFile hik_call_std("F:/test/stream/hik_call_std.dat");
     if(! hik_call_std.open( QIODevice::WriteOnly)){
         std::cout<<"------hik_call_std open fail-----------"<<std::endl;
         return -1;
     }
     g_out_stream = new QDataStream(&hik_call_std);//文件流
 
     NET_DVR_USER_LOGIN_INFO info={};//坑
     info.wPort = 707;
 
     std::string username = "admin";
     strcpy_s( info.sUserName, NET_DVR_LOGIN_USERNAME_MAX_LEN, username.c_str());
 
     std::string password = "abc123COM";
     strcpy_s( info.sPassword, NET_DVR_LOGIN_PASSWD_MAX_LEN, password.c_str());
 
     std::string addrss = "112.91.85.154";
     strcpy_s( info.sDeviceAddress, NET_DVR_DEV_ADDRESS_MAX_LEN, addrss.c_str());
     info.bUseAsynLogin = 0;//同步登陆
 
     /**********************************v3登陆***********************************/
     LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo={};
     LONG   lUserID = NET_DVR_Login_V30(info.sDeviceAddress,    info.wPort,info.sUserName, info.sPassword,  lpDeviceInfo);
     std::cout<<"lUserID="<<lUserID<<std::endl;
     if(lUserID<0){
           std::cout<<"------login fail-----------"<<std::endl;
            printLastError();
           return -1;
     }else{
         std::cout<<"------login success-----------"<<std::endl;
     }
         //---------------------------------------
           //设置异常消息回调函数
     if (! NET_DVR_SetExceptionCallBack_V30(0, nullptr,exceptionCallBack, nullptr) ){
         printf("NET_DVR_SetExceptionCallBack_V30 error\n");
         printLastError();
         return -1;
     }
 
           //---------------------------------------
           //启动 播放 预览
            LONG lRealPlayHandle;
            /***
 
           NET_DVR_CLIENTINFO ClientInfo = {};
           ClientInfo.lChannel     = 1;       //通道号, 1~32表示模拟通道1~32, 9000系列混合型DVR和NVR等设备的IP通道从33开始; 
           ClientInfo.lLinkMode    = 0;       //最高位(31)为0表示主码流, 为1表示子码流0~30位表示连接方式: 0-TCP方式; 1-UDP方式; 2-多播方式; 3-RTP方式;
           ClientInfo.hPlayWnd =nullptr;         //需要SDK解码时句柄设为有效值, 仅取流不解码时可设为空
           ClientInfo.sMultiCastIP = nullptr;   //多播地址, 需要多播预览时配置
           //lRealPlayHandle = NET_DVR_RealPlay(lUserID, &ClientInfo);
          // lRealPlayHandle = NET_DVR_RealPlay_V30(lUserID, &ClientInfo);
         ****/
           ////////////
            NET_DVR_PREVIEWINFO ClientInfo = {};
            ClientInfo.dwStreamType = 0;// 码流类型, 0-主码流, 1-子码流, 2-码流3, 3-码流4, 4-码流5,5-码流6,7-码流7,8-码流8,9-码流9,10-码流10
            ClientInfo.dwLinkMode = 0;// 0: TCP方式,1: UDP方式,2: 多播方式,3 - RTP方式, 4-RTP/RTSP,5-RSTP/HTTP ,6- HRUDP(可靠传输) ,7-RTSP/HTTPS
            ClientInfo.hPlayWnd = nullptr;//播放窗口的句柄,为NULL表示不播放图象
            ClientInfo.bPassbackRecord = 0; //0-不启用录像回传, 1-启用录像回传; ANR断网补录功能, 客户端和设备之间网络异常恢复之后自动将前端数据同步过来, 需要设备支持; 
            ClientInfo.byPreviewMode = 0;//: 0- 正常预览, 1- 延迟预览
            ClientInfo.bBlocked = 1;//0- 非阻塞取流, 1- 阻塞取流; 必须为1阻塞取流, 不然sdk报 顺序错误, 我K....
            ClientInfo.lChannel = 1;
 
            lRealPlayHandle = NET_DVR_RealPlay_V40(lUserID, &ClientInfo);
           if (lRealPlayHandle < 0)
           {
               printf("NET_DVR_RealPlay error\n");
               printLastError();
               NET_DVR_Logout(lUserID);
               NET_DVR_Cleanup();
                 return -2;
           }
 
          bool result  = NET_DVR_SetStandardDataCallBack(lRealPlayHandle, realStdDataCallBack, lUserID);
           if (!result )
           {
               printf("NET_DVR_SetStandardDataCallBack error\n");
               printLastError();
               NET_DVR_Logout(lUserID);
               NET_DVR_Cleanup();
           };
           /*--------------------------------------     -----------------------------*/
           QThread::msleep(3000);
           //关闭预览
           NET_DVR_StopRealPlay(lRealPlayHandle);
           //注销用户
           NET_DVR_Logout_V30(lUserID);
           NET_DVR_Cleanup();
 
           std::cout<<"------main end-----------"<<std::endl;
         return 0;
}

回调非RTP数据 NET_DVR_SetRealDataCallBack

源文件

解 SDK回调的RTP包 NET_DVR_SetStandardDataCallBack

参考下 笔记 > librtp源码 with qt

解 SDK回调数据包 NET_DVR_SetRealDataCallBack

参考下 笔记> H264包 解码 -FFmpeg

问题

TODO 可以解码但是 画面只有上半部分..

参考下 SMPlayer 信息:

Video
Resolution: 1280 x 960
Aspect ratio: 1.33333
Format: h264
Bitrate: 0 kbps
Frames per second: 25.000000
Selected codec: h264
 
Audio Streams
Track 0
Language: <undefined>
Name: <undefined>
ID: 1
--------------
...
Playing: F:/test/stream/hik_call_std.dat
 (+) Video --vid=1 (h264 1280x960 25.000fps)
 (+) Audio --aid=1 (pcm_alaw 1ch 8000Hz)
AO: [wasapi] 48000Hz stereo 2ch float
VO: [direct3d] 1280x960 yuv420p
INFO_VIDEO_DSIZE=1280x960
MPV_VERSION=mpv 0.28.0
INFO_VIDEO_WIDTH=1280
INFO_VIDEO_HEIGHT=960
INFO_VIDEO_ASPECT=1.333333
INFO_VIDEO_FPS=25.000000
INFO_VIDEO_FORMAT=h264
INFO_VIDEO_CODEC=h264 (H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10)
INFO_AUDIO_FORMAT=pcm_alaw
INFO_AUDIO_CODEC=pcm_alaw (PCM A-law / G.711 A-law)
INFO_AUDIO_RATE=8000
INFO_AUDIO_NCH=1
INFO_LENGTH=95445.595689
INFO_DEMUXER=lavf
INFO_SEEKABLE=yes
INFO_TITLES=
INFO_CHAPTERS=0
INFO_TRACKS_COUNT=2
METADATA_TITLE=
METADATA_ARTIST=
METADATA_ALBUM=
METADATA_GENRE=
METADATA_DATE=
METADATA_TRACK=
METADATA_COPYRIGHT=
INFO_MEDIA_TITLE=hik_call_std.dat
INFO_STREAM_PATH=F:/test/stream/hik_call_std.dat
INFO_TRACK_0: video 1 '' '' yes
INFO_TRACK_1: audio 1 '' '' yes

应该涉及封装格式了,

待研究..

解决

它不是完全的裸视频流,有封装格式, 包括音频, ffmpeg avformat_open_input 是可以打开的! (擦, 不早试一下..) avformat_find_stream_info 也可以分析出流索引..

源文件 测试方法: main_view_video_file

so ..

所以必须, 从内存喂数据了…

unsigned char* _iobuffer = (unsigned char*)av_malloc(40690);//要足够大
AVIOContext* avio = avio_alloc_context(_iobuffer , 40690 , 0 , this, fill_buffer,nullptr,nullptr);
assert( avio != NULL);
avFormat->pb = avio;
if ( ( avformat_open_input(&avFormat, nullptr,nullptr, nullptr)  ) != 0) {
        qDebug()<<"Could not open input .";
        return ;
    }
 
...
 

错误

Java 海康Linux SDK 登陆29 错误码

总是 login fail 29(Device operation failed., 错误码也没参考价值. 没头绪..

解决 使用命令 objdump 看下依赖的库; $ objdump -x java -jar testm.jar /home/jk-nyy/CH-HCNetSDKV6.1.4.17_build20200331_Linux64/lib/libhcnetsdk.so

Program Header:
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**20
         filesz 0x0000000000080449 memsz 0x0000000000080449 flags r-x
    LOAD off    0x0000000000080450 vaddr 0x0000000000180450 paddr 0x0000000000180450 align 2**20
         filesz 0x0000000000003150 memsz 0x00000000000033d8 flags rw-
 DYNAMIC off    0x0000000000082eb8 vaddr 0x0000000000182eb8 paddr 0x0000000000182eb8 align 2**3
         filesz 0x0000000000000210 memsz 0x0000000000000210 flags rw-
EH_FRAME off    0x000000000007378c vaddr 0x000000000007378c paddr 0x000000000007378c align 2**2
         filesz 0x0000000000001cd4 memsz 0x0000000000001cd4 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**3
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
 
Dynamic Section:
  NEEDED               libhpr.so
  NEEDED               libHCCore.so
  NEEDED               libstdc++.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6
  SYMBOLIC             0x0000000000000000
  RPATH                $ORIGIN
  RUNPATH              $ORIGIN
  INIT                 0x0000000000018648
  FINI                 0x0000000000064e28
  HASH                 0x0000000000000158
  STRTAB               0x0000000000008908
  SYMTAB               0x0000000000002290
  STRSZ                0x0000000000006f69
  SYMENT               0x0000000000000018
 
...

还是有一些库需要加载.. 设置到环境变量配置文件里! sudo vi /etc/profile export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/jk-nyy/CH-HCNetSDKV6.1.4.17_build20200331_Linux64/lib:/home/jk-nyy/CH-HCNetSDKV6.1.4.17_build20200331_Linux64/lib/HCNetSDKCom

source /etc/profile