主要功能:
海康SDK开发,通过连接NVR,实现连接NVR的2个相机同时采集(多线程),并进行opencv图像格式转换。
关键技术点:
1、回调函数
2、YV12->oepncv图像格式转换
3、多线程连接多IPcamera,同时采集
---------------------------分割线-------------------------------------------------------
1、回调函数
定义:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
回调函数是继承自C语言的。
在C++中,应只在与C代码建立接口或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚拟方法或仿函数(functor),而不是回调函数。
理解:即回调函数的目的是解耦,
Callback
下面以一段不完整的C语言代码来呈现上图的意思:
#include<stdio.h>
#include<softwareLib.h> // 包含Library Function所在读得Software library库的头文件
int Callback() // Callback Function
{
// TODO
return 0;
}
int main() // Main program
{
// TODO
Library(Callback);
// TODO
return 0;
}
乍一看,回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且丝毫不需要修改库函数的实现,这就是解耦。
再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,想一想,如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了,这也就是在日常工作中常见的情况。
更详细的讲解请参考:
https://baike.baidu.com/item/%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0/7545973?fr=aladdin
实例:
//回调函数实例
void __stdcall show(void(*CallLBackFun)(const string&, InputArray), const string& winname, InputArray m)
{
namedWindow(winname,0);
CallLBackFun(winname, m);
waitKey(1);
}
void CALLBACK DecCBFun(long nPort,char *pBuf,long nSize,FRAME_INFO *pFrameInfo,void *nUser,void *nReserved2)
{
char buff[10];
sprintf_s(buff, "%d", nPort+11);
if (pFrameInfo->nType == T_YV12)
{
// YUV--> Mat格式转换
Mat g_BGRImage;
g_BGRImage.create(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);
Mat YUVImage(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, (unsigned char*)pBuf);
cvtColor(YUVImage, g_BGRImage, COLOR_YUV2BGR_YV12);
//把opencv的imshow作为回调函数使用
//imshow("dst", g_BGRImage);
show(imshow,buff, g_BGRImage);
}
}
2、YV12->oepncv图像格式转换
void CALLBACK DecCBFun(long nPort,char *pBuf,long nSize,FRAME_INFO *pFrameInfo,void *nUser,void *nReserved2)
{
if (pFrameInfo->nType == T_YV12)
{
// YUV--> Mat格式转换
Mat g_BGRImage;
g_BGRImage.create(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);
Mat YUVImage(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, (unsigned char*)pBuf);
cvtColor(YUVImage, g_BGRImage, COLOR_YUV2BGR_YV12);
imshow("dst", g_BGRImage);
cvWaitKey(1);
}
}
3、多线程连接多IPcamera,同时采集
C语言多线程介绍:
c语言库 process.h 中的函数, 用来创建一个线程 :_beginthreadex
unsigned long _beginthreadex(
void *security, // 安全属性, 为NULL时表示默认安全性
unsigned stack_size, // 线程的堆栈大小, 一般默认为0
unsigned(_stdcall *start_address)(void *), // 所要启动的线程函数
void *argilist, // 线程函数的参数, 是一个void*类型, 传递多个参数时用结构体
unsigned initflag, //新线程的初始状态,0表示立即执行,CREATE_SUSPENDED
表示创建之后挂起
unsigned *threaddr // 用来接收线程ID
);
返回值 : // 成功返回新线程句柄, 失败返回0
-------------分割线----------------------
#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned int __stdcall threadDemo(LPVOID) // void *
{
printf("我被执行啦!\n");
return 0;
}
int main()
{
HANDLE handle;
handle = (HANDLE)_beginthreadex(NULL, 0, ThreadDemo, NULL, 0, NULL);
return 0;
}
参考:
实例:
#include <process.h>
typedef struct MyStruct
{
LONG lUserId;
LONG channel;
}MyStruct, *LPMyStruct;
----------------------------
unsigned int __stdcall play(void* user)
{
LPMyStruct stru = (LPMyStruct)user;
//启动预览并设置回调数据流
LONG lRealPlayHandle;
//HWND hWnd = GetConsoleWindowAPI(); //获取窗口句柄
NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
struPlayInfo.hPlayWnd = NULL; //需要SDK解码时句柄设为有效值,仅取流不解码时可设为空
struPlayInfo.lChannel = stru->channel + 32; //预览通道号
struPlayInfo.dwStreamType = 0; //0-主码流,1-子码流,2-码流3,3-码流4,以此类推
struPlayInfo.dwLinkMode = 0; //0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
struPlayInfo.bBlocked = 1; //0- 非阻塞取流,1- 阻塞取流
lRealPlayHandle = NET_DVR_RealPlay_V40(stru->lUserId, &struPlayInfo, fRealDataCallBack, NULL);
if (lRealPlayHandle < 0)
{
printf("NET_DVR_RealPlay_V40 error\n");
printf("error :%d", NET_DVR_GetLastError());
NET_DVR_Logout(stru->lUserId);
NET_DVR_Cleanup();
return 0;
}
Sleep(10000);
//关闭预览
NET_DVR_StopRealPlay(lRealPlayHandle);
return 0;
}
-------------------------
//多线程
MyStruct structdata, structdata2;
structdata.lUserId = lUserID;
structdata.channel = 7;
HANDLE handle, handle2;
handle = (HANDLE)_beginthreadex(NULL, 0, play, (void*)(&structdata), 0, NULL);
structdata2.lUserId = lUserID;
structdata2.channel = 3;
handle2 = (HANDLE)_beginthreadex(NULL, 0, play, (void*)(&structdata2), 0, NULL);
Sleep(20000);
-----------------------分割线----------------------------------------
不能添加附件,大家去下载链接下载吧,不需要积分,免费下载。