海康威视多摄像头实时视频预览(基于SDK的二次开发)

11 篇文章 1 订阅

项目背景

   很久没有做工程项目了,最近突然接单,要做多摄像头下运动物体入侵检测及拌线检测,本文测试用到的摄像头是海康威视的DS-2CD23**D摄像头。

 

环境配置:

1.下载SDK

2.vs2010开发环境

3..opencv2.4.8

具体配置自行百度吧。下面贴上我这边的主要配置,需要注意的是需要在x64环境下编译。

将摄像头插入以太网口后,那么我们就可以通过官方提供的“设备网络搜索软件“——SADP工具,这个软件可以在海康威视的官方网站下载最新版本。本篇文章的很大程度上参照了lonelyrains的教程,在此基础上进行改进,同时在此表示感谢。

 

1.先在官网下载到SDK开发包:

 

下载下来SDK后我们解压,就可以看到里面包含一些开发文档以及一些Demo示例:

 

2.VS2010下环境配置

首先,配置属性---常规

1)输出目录:$(SolutionDir)\bin\

2.)中间目录:$(SolutionDir)\Temp\Compile\$(ProjectName)\$(ConfigurationName)

 

 

接着,配置属性---调试

 

 

VC++目录

包含目录:

..\include

 

 

opencv目录也要包含进来,继承值里如果没有的话

 

库目录:

 

接着C/C++

常规--附加包含目录 ../include/

链接器--常规 --附加库目录  ../lib/

 

 

 

链接器--输入--附加依赖项 

HCNetSDK.lib

ws2_32.lib
PlayCtrl.lib
winmm.lib
GdiPlus.lib
IPHlpApi.Lib

 

3.opencv配置,参见这里

 

视频采集

下面进入重点,实时视频采集。

先看看SDK里的demo函数,参见这里

 

代码如下:

NesunCamDriver.h 

添加了进程锁,由于考虑到项目保密性,下面开放部分源码。

 

.cpp源码开放出来:

 

#include "StdAfx.h"
#include "NesunCamDriver.h"
#include <windows.h>

IplImage * NesunCamDriver::m_pImg = NULL;
long NesunCamDriver::nPort = -1;
float NesunCamDriver::Scalefactor = 1.0f;
MTCMutex NesunCamDriver::m_hMutex;
HWND NesunCamDriver::m_hPlayWnd=NULL;
NesunCamDriver::NesunCamDriver(void)
	: lUserID(0)
	, lRealPlayHandle(-1)
{
	/*  Create a mutex Lock when a object create */
	//m_pImg = NULL;
	//hMutex = CreateMutex(NULL,FALSE,NULL);
	
}


NesunCamDriver::~NesunCamDriver(void)
{
	ReleaseCamera();
}



int NesunCamDriver::ReleaseCamera(void)
{
    if(!NET_DVR_StopRealPlay(lRealPlayHandle)){
        printf("NET_DVR_StopRealPlay error! Error number: %d\n",NET_DVR_GetLastError());
        return 0;
    }
    NET_DVR_Logout(lUserID);
    NET_DVR_Cleanup();
	
	cvReleaseImage(&m_pImg);//gavin++
	if (m_pImg)
	{
		m_pImg = NULL;
	}
	
    return 1;
}

void NesunCamDriver::InitHKNetSDK(void)
{
    /*  SDK Init                                 */
    NET_DVR_Init();
    /*  Set the Connect Time and Reconnect time  */
    NET_DVR_SetConnectTime(200, 1);
    NET_DVR_SetReconnect(10000, true);


}

CamHandle NesunCamDriver::InitCamera(char *sIP,char *UsrName,char *PsW, HWND hPlayWnd,int Port)
{
	m_hPlayWnd = hPlayWnd;
    NET_DVR_DEVICEINFO_V30 struDeviceInfo;
	memset(&struDeviceInfo,0,sizeof(NET_DVR_DEVICEINFO_V30));

    lUserID = NET_DVR_Login_V30(sIP, Port,UsrName,PsW, &struDeviceInfo);

    if (lUserID < 0){
        printf("Login error, %d\n", NET_DVR_GetLastError());
        NET_DVR_Cleanup();
        return -1;
    }

    NET_DVR_SetExceptionCallBack_V30(0, NULL,ExceptionCallBack, NULL);

    NET_DVR_CLIENTINFO ClientInfo;
    ClientInfo.lChannel = 1;                    /* Channel number Device channel number. */
	ClientInfo.hPlayWnd = NULL;					//NULL;  窗口为空,设备SDK不解码只取流	
    ClientInfo.lLinkMode = 0;                   /* Main Stream                           */
    ClientInfo.sMultiCastIP = NULL;

    lRealPlayHandle = NET_DVR_RealPlay_V30(lUserID,&ClientInfo,fRealDataCallBack,NULL,TRUE);

	if(-1 == lRealPlayHandle)
	{
		DWORD err=NET_DVR_GetLastError();
		printf("NET_DVR_RealPlay_V30 failed! Error number: %d\n", err);
		CString sErr;
		sErr.Format("播放出错,错误代码:%d",err);
		AfxMessageBox(sErr);
		return 0;
	}

    return lRealPlayHandle;
}

void CALLBACK  NesunCamDriver::DecCBFun(long nPort,char * pBuf,long nSize,FRAME_INFO * pFrameInfo, long nReserved1,long nReserved2)
{
    long lFrameType = pFrameInfo->nType;  
    char WindowName[15];
    static IplImage* pImgYCrCb =NULL;
    sprintf_s(WindowName,"Windows:%d",nPort);

    if(lFrameType ==T_YV12)
    {
		m_hMutex.Lock();

        /*    Single Camera decode 3.5%    */
	
		
		if(pImgYCrCb == NULL)
		{
			pImgYCrCb = cvCreateImage(cvSize(pFrameInfo->nWidth,pFrameInfo->nHeight), 8, 3);        
		}
		if (m_pImg == NULL)
		{
			m_pImg = cvCreateImage(cvSize((int)(pFrameInfo->nWidth*Scalefactor),(int)(pFrameInfo->nHeight*Scalefactor)), 8, 3); 
		}

        /*    CPU: 0.1%                    */
		
        yv12toYUV(pImgYCrCb->imageData, pBuf, pFrameInfo->nWidth,
                    pFrameInfo->nHeight,pImgYCrCb->widthStep);  

        cvResize(pImgYCrCb,m_pImg, CV_INTER_LINEAR);

        /*    CPU  3.4%                    */
        cvCvtColor(m_pImg,m_pImg,CV_YCrCb2RGB); 

        /*   1080p Video Display Need 3.5%
             per Cmaera                    */
        m_hMutex.UnLock();
		cvReleaseImage(&pImgYCrCb);//gavin++
    }
}

void CALLBACK  NesunCamDriver::ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
{
    char tempbuf[256] = {0};
    switch(dwType) 
    {
    case EXCEPTION_RECONNECT:    /* Reconnet when Error Happen */
        break;
    default:
        break;
    }
}

void NesunCamDriver::yv12toYUV(char *outYuv, char *inYv12, int width, int height,int widthStep)
{
    int col,row;
    unsigned int Y,U,V;
    int tmp;
    int idx;
    for (row=0; row<height; row++)
	{
        idx=row * widthStep;
        int rowptr=row*width;
        for (col=0; col<width; col++)
		{
            tmp = (row/2)*(width/2)+(col/2);
            Y=(unsigned int) inYv12[row*width+col];
            U=(unsigned int) inYv12[width*height+width*height/4+tmp];
            V=(unsigned int) inYv12[width*height+tmp];
            outYuv[idx+col*3]   = Y;
            outYuv[idx+col*3+1] = U;
            outYuv[idx+col*3+2] = V;
        }
    }
}
/*     Realtime Steam Callback           */
void CALLBACK NesunCamDriver::fRealDataCallBack(LONG lRealHandle,DWORD dwDataType,BYTE *pBuffer,DWORD dwBufSize,void *pUser)
{
    DWORD dRet;
    DWORD CameraIndex = 0;

    CameraIndex  = lRealHandle;
    printf("lRealHandle = %ld\n",CameraIndex);
    switch (dwDataType)
    {
        /*  System Head    */
        case NET_DVR_SYSHEAD:    
            if (!PlayM4_GetPort(&nPort))
				break;
            if(dwBufSize > 0)
			{
                if (!PlayM4_OpenStream(nPort,pBuffer,dwBufSize,1024*1024))
				{
                    dRet=PlayM4_GetLastError(nPort);
                    break;
                }
            
				//fix by gavin
				//设置解码回调函数 只解码不显示
				// 		if (!PlayM4_SetDecCallBack(nPort,DecCBFun))
				// 		{
				// 			dRet=PlayM4_GetLastError(nPort);
				// 			break;
				// 		}

				//设置解码回调函数 解码且显示
				if (!PlayM4_SetDecCallBackEx(nPort,DecCBFun,NULL,NULL))
				{
					dRet=PlayM4_GetLastError(nPort);
					break;
				}

				/*
                if (!PlayM4_Play(nPort,NULL))
				{
                    dRet=PlayM4_GetLastError(nPort);
                    break;
                }   */

				//打开视频解码
				if (!PlayM4_Play(nPort,m_hPlayWnd))
				{
					dRet=PlayM4_GetLastError(nPort);
					break;
				}

				//打开音频解码, 需要码流是复合流
				if (!PlayM4_PlaySound(nPort))
				{
					dRet=PlayM4_GetLastError(nPort);
					break;
				}
				break;
            }
            break;
        /* Code steam data    */
        case NET_DVR_STREAMDATA:   
            if (dwBufSize > 0 && nPort != -1) 
			{
                BOOL inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
                while (!inData)
				{
                    Sleep(10);
                    inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
                }
            }
            break;  
        }       
}

int NesunCamDriver::GetCamMat(Mat &Img,CamHandle handle,float factor)
{
    /*  Get the Port using handle    */
    int iPort = nPort;
    /*  Check the iPort is vaild     */
    if(iPort != -1)
	{
        //WaitForSingleObject(hMutex[iPort],INFINITE);
		m_hMutex.Lock();
        Mat(m_pImg).copyTo(Img);
        //ReleaseMutex(hMutex[iPort]);
		cvReleaseImage(&m_pImg);//gavin++
		m_pImg = NULL;//gavin++
		m_hMutex.UnLock();
		
        resize(Img,Img,cv::Size(),factor,factor);
        return 1;
    }
    /* If iPort is invaild, return 
       empty                         */
    return 0;
}

void NesunCamDriver::SetScaleFactor(float factor)
{
    Scalefactor = factor;
}


// 抓图保存到指定路径
int NesunCamDriver::CaptureImg(char* szPath,char* szError)
{
	FILE *file=NULL;
	static long iPicNum = 0;
	NET_DVR_JPEGPARA JpegPara;
	JpegPara.wPicQuality=0;
	JpegPara.wPicSize=0xff;

	char *JpegPicBuffer= new char[352*288*2]; 
	//这里的缓冲区大小需要根据抓图的分辨率大小自己调节,建议设置成2*图片的分辨率宽*图片的分辨率高
	LONG iPChannel = 1;//Channel number 设备通道号
	DWORD  SizeReturned=0;	
	BOOL bRet= NET_DVR_CaptureJPEGPicture_NEW(lUserID, iPChannel,&JpegPara,JpegPicBuffer,352*288*2,&SizeReturned);
	if (!bRet)
	{
		sprintf(szError, "NET_DVR_CaptureJPEGPicture_NEW failed! Error number: %d\n", NET_DVR_GetLastError());
		return 0;
	}
	
	if (file==NULL)
	{
		sprintf(szPath,"%s\\JpegCAP%d_%d.jpg",szPath,lUserID,iPicNum);
		file = fopen(szPath,"wb");
	}
	fwrite(JpegPicBuffer,SizeReturned,1,file);
	iPicNum++;

	delete JpegPicBuffer;
	fclose(file);
	file=NULL;
	return 1;
}

 

调用:

 

        CString strMode;
	GetDlgItemText(IDC_BT_PLAY, strMode);	
	if (_T("播放") == strMode)
	{
		m_hkCamDriver[0].InitHKNetSDK();
		m_hkCamDriver[0].SetScaleFactor(0.5f);

		Sleep(500);
		

		if (m_hkHandle[0] >= 0)
		{
			NET_DVR_StopRealPlay(m_hkHandle[0]);
			m_hkHandle[0] = -1;
		}

		//m_lPlayHandle = NET_DVR_RealPlay_V30(m_lUserID, &struPlayInfo, NULL, NULL, TRUE); 
		m_hkHandle[0] = m_hkCamDriver[0].InitCamera("192.168.1.222","admin","12345",m_hPlayWnd[0]);

		if (m_hkHandle[0] < 0)
		{
			char szTemp[128] = {0};
			sprintf(szTemp, "视频播放出错, %s", NET_DVR_GetErrorMsg());
			AfxMessageBox(szTemp);
		}

		GetDlgItem(IDC_BT_PLAY)->SetWindowText("停止");
		
	}
	else if (_T("停止") == strMode)
	{
		m_hkCamDriver[0].ReleaseCamera();
		GetDlgItem(IDC_BT_PLAY)->SetWindowText("播放");
	}

注意对应窗口显示区域,HWND m_hPlayWnd[12];

m_hPlayWnd[0] = GetDlgItem(IDC_STATIC_PLAY)->GetSafeHwnd();

 

其他参考:

1.https://blog.csdn.net/log_zhan/article/details/75041352#commentsedit

2.https://blog.csdn.net/qq_15029743/article/details/79733960

 

3.OpenCV笔记(2)打开海康威视摄像头

4.海康摄像头实时显示与字符叠加详解

5.海康威视IP摄像头基于OPENCV的二次开发

6.ROS:海康威视+opencv运动检测

7.捕获海康威视IPCamera图像,转成OpenCV可以处理的图像(二)

### 回答1: 要实现java海康威视摄像头实时预览视频流保存到指定文件中,需要先安装海康威视SDK,并使用Java SDK开发工具包中的类库来开发应用程序。 首先,在应用程序中引入海康威视SDK库,包括HCNetSDK.dll、PlayCtrl.dll、HCAlarm.dll等。然后,使用HCNetSDK类库中提供的方法来实现视频实时预览功能,并将预览视频流通过PlayCtrl.dll中提供的方法进行渲染和显示。 同时,在将视频流保存到指定文件时,可以使用Java中的IO流进行文件操作。首先在程序中创建File对象指定文件路径,然后使用FileOutputStream类创建输出流对象,通过读取预览视频流数据的byte数组并将其写入到输出流中实现将视频流保存到文件的功能。 需要注意的是,保存到文件时,时间戳的处理,文件格式等问题都需要按照实际需求进行处理。 总之,要实现java海康威视摄像头实时预览视频流保存到指定文件中,需要结合使用海康威视SDK和Java SDK开发工具包,具体实现过程需要根据实际情况灵活处理。 ### 回答2: Java是一种广泛应用于各种领域的高级编程语言,海康威视摄像头是一种高清晰度的视频监控设备。如何实现将海康威视摄像头实时预览视频流保存到指定文件中呢?下面以Java编程语言为主体进行分析探讨。 首先,需要了解Java的多媒体相关类库和海康威视摄像头的API接口。Java多媒体相关类库包括javax.sound.sampled和javax.media包。javax.sound.sampled是Java音频API,可以处理音频文件的读、写、播放和录制等操作;javax.media则是Java多媒体API,可以处理音频、视频和图像等媒体数据。海康威视摄像头的API接口包括SDK、HCNetSDK和PlayCtrl等。 其次,需要进行海康威视摄像头实时预览视频流以及保存到指定文件中的操作。具体步骤如下: 1. 初始化海康威视摄像头SDK,包括设备登录、设备初始化和预览四个步骤。设备登录是使用设备账号密码进行登录,设备初始化是对设备进行初始化设置,预览则是打开视频流并进行播放。 2. 在预览中添加截图功能,通过调用SDK中的抓图函数将视频帧数据保存到内存中的一个缓冲区中。抓取一帧数据需要使用NET_DVR_CaptureJPEGPicture_V30函数,并将数据放置到指定的缓存区。 3. 将缓冲区中的数据保存到本地文件中。在Java中可以使用BufferedImage类来保存JPEG图像数据,使用ImageIO类将缓冲区中的图像数据保存到指定的文件中。 4. 关闭设备预览,退出SDK。 需要注意的是,保存视频流到文件中需要根据需求进行设置参数,包括视频流的编码格式、分辨率、帧率等。在进行保存时还应该进行异常处理,例如文件不存在、写入失败等异常情况的处理。 总之,Java实现海康威视摄像头实时预览视频流保存到指定文件中需要进行多项操作,包括海康威视SDK的初始化和调用、截图和保存等。具体操作可以根据实际需要进行调整和修改,最终实现预览视频流保存到文件的功能。 ### 回答3: java是一种广泛使用的编程语言,可用于开发各种应用程序,包括与摄像头相关的应用程序。海康威视(Hikvision)是一家专业从事视频监控设备制造的企业,提供多种摄像头系列产品。本文将介绍如何使用java编写程序,实现海康威视摄像头实时预览视频流,并将视频流保存到指定文件中。 首先,要实现海康威视摄像头实时预览视频流,需要使用其提供的软件开发包(SDK),该SDK提供了一组API,用于控制海康威视摄像头的各种功能。在使用SDK前,需要先在操作系统中安装相关依赖库,并且在开发环境中配置好SDK相关参数。 接下来,我们需要按照以下步骤编写java程序: 1.引入SDK相关jar包,并创建SDK实例。 import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.NativeLongByReference; import com.sun.jna.ptr.PointerByReference; import com.hikvision.netsdk.*; public class HikvisionTest { private HCNetSDK hCNetSDK; public static void main(String[] args) { HikvisionTest test = new HikvisionTest(); test.init(); test.preview(); } public void init() { hCNetSDK = HCNetSDK.INSTANCE; boolean initSuc = hCNetSDK.NET_DVR_Init(); if(!initSuc) { System.out.println("SDK初始化失败"); } } public void preview() { int userId = -1; HCNetSDK.NET_DVR_DEVICEINFO_V30 devInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30(); NativeLong lRealHandle = new NativeLong(-1); NativeLong lLoginHandle = hCNetSDK.NET_DVR_Login_V30("10.10.10.1", 8000, "admin", "password", devInfo); if(lLoginHandle.longValue() < 0) { System.out.println("登录失败"); return; } HCNetSDK.NET_DVR_PREVIEWINFO previewInfo = new HCNetSDK.NET_DVR_PREVIEWINFO(); previewInfo.lChannel = 1; previewInfo.dwStreamType = 0; previewInfo.dwLinkMode = 0x80000000; Pointer hPlayWnd = null;//播放窗口句柄,为null表示不播放画面,只预览数据 lRealHandle = hCNetSDK.NET_DVR_RealPlay_V40(lLoginHandle, previewInfo, null); if(lRealHandle.longValue() < 0) { System.out.println("预览失败"); return; } //TODO: 在这里添加保存视频流到文件的代码 } } 2.登录网络摄像头,并开启实时预览。 在上述代码中,我们调用了NET_DVR_Login_V30方法登录摄像头设备,该方法返回登录句柄,如果登录失败则返回-1。登录成功后,我们可以通过NET_DVR_RealPlay_V40方法开启实时预览功能,该方法调用后返回实时预览句柄,如果开启预览失败则返回-1。在实时预览时,我们可以指定播放窗口句柄,如果传入null则表示只预览不播放。 3.将视频流保存到指定文件中。 要将视频流保存到指定文件中,我们可以在预览时添加代码,调用NET_DVR_SaveRealData保存视频流数据。 hCNetSDK.NET_DVR_SaveRealData(lRealHandle, "D:\\video\\test.mp4"); 以上代码将把视频流数据保存到指定文件路径(D:\\video\\test.mp4)中。 另外,为了保证视频流数据正常保存,还需要添加停止预览和注销登录相关的代码。停止预览时,可以调用NET_DVR_StopRealPlay方法停止实时预览;注销登录时,可以调用NET_DVR_Logout方法注销登录句柄。 总之,使用java编写程序实现海康威视摄像头实时预览视频流并保存视频到指定文件,需要使用海康威视摄像头SDK提供的API来控制摄像头功能,同时需要注意代码的执行顺序和各种参数的设置。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值