QT with 海康SDK
- 下载SDK
- 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 \注意问题
-
运行还需要dll(运行库)
-
参数结构体初始化
NET_DVR_DEVICEINFO_V40 devinfoSDK报参数为nullptr错误. 可用NET_DVR_DEVICEINFO_V40 devinfo ={}初始化 -
需要包含 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