基于大华SDK 实现大华NVR 取流显示和文件回放功能的实现

最近在做关于大华nvr 获取大华摄像头的数据流和存储到硬盘中的视频文件,发现网上关于大华摄像头的二次开发的博客比较少,特分享一下最近完成的关于大华nvr的两个小功能,希望能够给大家一些启发与帮助。

#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include "dhnetsdk.h"
#include "dhplay.h"
#include <cstring>
#include <winCon.h>
#include "opencv2/opencv.hpp"
using namespace std;
#define SWITCH 1
#define PLAYPORT 1
typedef struct VideoData
{
    char* data;
    int width;
    int height;
}TVideoData; //视频数据结构体
list<VideoData> videolist;//list存储视频数据

//解码函数 将YUV420解码为IplImage
IplImage* YUV420_To_IplImage_Opencv(char* pYUV420, int width, int height)
{
    if (!pYUV420)
    {
        return NULL;
    }
    IplImage *yuvimage, *rgbimg, *yimg, *uimg, *vimg, *uuimg, *vvimg;
    int nWidth = width;
    int nHeight = height;
    rgbimg = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 3);
    yuvimage = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 3);
    yimg = cvCreateImageHeader(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 1);
    uimg = cvCreateImageHeader(cvSize(nWidth / 2, nHeight / 2), IPL_DEPTH_8U, 1);
    vimg = cvCreateImageHeader(cvSize(nWidth / 2, nHeight / 2), IPL_DEPTH_8U, 1);
    uuimg = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 1);
    vvimg = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 1);
    cvSetData(yimg, pYUV420, nWidth);
    cvSetData(uimg, pYUV420 + nWidth*nHeight, nWidth / 2);
    cvSetData(vimg, pYUV420 + long(nWidth*nHeight*1.25), nWidth / 2);
    cvResize(uimg, uuimg, CV_INTER_LINEAR);
    cvResize(vimg, vvimg, CV_INTER_LINEAR);
    cvMerge(yimg, uuimg, vvimg, NULL, yuvimage);
    cvCvtColor(yuvimage, rgbimg, CV_YCrCb2RGB);
    cvReleaseImage(&uuimg);
    cvReleaseImage(&vvimg);
    cvReleaseImageHeader(&yimg);
    cvReleaseImageHeader(&uimg);
    cvReleaseImageHeader(&vimg);
    cvReleaseImage(&yuvimage);
    if (!rgbimg)
    {
        return NULL;
    }
    CvSize sz;
    IplImage *desc;
    sz.width = rgbimg->width*0.5;
    sz.height = rgbimg->height*0.5;
    desc = cvCreateImage(sz, rgbimg->depth, rgbimg->nChannels);
    cvResize(rgbimg, desc, CV_INTER_CUBIC);
    cvShowImage("test", desc);
    cvWaitKey(1);
    cvReleaseImage(&desc);
    return rgbimg;
}
//设备断线回调函数
void CALLBACK DisConnectFunc(LONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser)
{
    printf("设备断线.\n");
    return;
}
//自动重连回调函数
void CALLBACK AutoReConnectFunc(LONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser)
{
    printf("自动重连成功.\n");
    return;
}
//实时数据流回调函数 由于使用的NVR所以使用扩展回调函数
void CALLBACK RealDataCallBackEx(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, LONG lParam, DWORD dwUser)
{
    if (dwDataType == 0)  //原始视频流送播放库    
    {
        PLAY_InputData(PLAYPORT, pBuffer, dwBufSize);
    }
}
//解码回调函数
void CALLBACK DecCBFun(LONG nPort, char * pBuf, LONG nSize, FRAME_INFO * pFrameInfo, void* pUserData, LONG nReserved2)
{
    // pbuf里的数据是YUV I420格式的数据   
    if (pFrameInfo->nType == 3) //视频数据   
    {
        //将回调获取的YUV420数据放入list数据结构中
        //这种方式可以保证所有数据不会丢失
        //若做实时显示,可以进行丢帧处理来降低卡顿。
        TVideoData data;
        data.data = (char*)malloc(sizeof(char)*nSize);
        memcpy(data.data,pBuf,nSize);
        data.height = pFrameInfo->nHeight;
        data.width = pFrameInfo->nWidth;
        videolist.push_back(data);
    }
    return;
}
//文件回放下载进度回调函数
void CALLBACK cbDownLoadPos(LLONG lPlayHandle, DWORD dwTotalSize, DWORD dwDownLoadSize, LDWORD dwUser)
{
    //printf("cbDownLoadPos\n");
}
//文件回放数据回调函数
int CALLBACK fDownLoadDataCallBack(LLONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, LDWORD dwUser)
{
    if (dwDataType == 0)  //原始视频流送播放库    
    {
        PLAY_InputData(PLAYPORT, pBuffer, dwBufSize);
    }
    return 1;
}
//数据处理函数
DWORD WINAPI DataDeal(LPVOID lpParameter)
{
    while (1)
    {
        while (videolist.size() == 0);
        TVideoData data = videolist.front();
        double Time = (double)cvGetTickCount();
        YUV420_To_IplImage_Opencv(data.data, data.width, data.height);
        Time = (double)cvGetTickCount() - Time;
        printf("run time = %gms\n", Time / (cvGetTickFrequency() * 1000));
        free(data.data);
        videolist.pop_front();
    }
    return 0;
}
int main(void)
{
    //功能一:实时显示预览
    //功能二:文件下载回放
    PLAY_OpenStream(PLAYPORT, 0, 0, 1024*900);
    PLAY_SetDecCallBackEx(PLAYPORT, DecCBFun, NULL);
    PLAY_Play(PLAYPORT, NULL);
    //以上代码为启用解码
    CLIENT_LogClose();
    NET_DEVICEINFO_Ex info_ex = { 0 };
    int err = 0;
    unsigned long lLogin = 0;
    LLONG lSearch = 0;
    LLONG lRealPlay = 0;
    CLIENT_Init(DisConnectFunc, 0);
    CLIENT_SetAutoReconnect(AutoReConnectFunc, 0);
    lLogin = CLIENT_LoginEx2("192.168.0.101", 37777, "admin", "kz123456", EM_LOGIN_SPEC_CAP_TCP, NULL, &info_ex, &err);
    if (lLogin == 0)
    {
        printf("login error!\r\n");
    }
    else
    {
        printf("login success!\r\n");
#if SWITCH //SWITCH 宏定义,可通过修改该开关切换实时数据显示和文件回调显示
        //1.实时取流。
        lRealPlay = CLIENT_RealPlayEx(lLogin, 2, NULL, DH_RType_Realplay);
        //CLIENT_RealPlayEx 第二个参数为NVR 播放通道 此处为单通道显示可改为多通道预览
        if (lRealPlay != 0)
        {
            CLIENT_SetRealDataCallBackEx(lRealPlay, RealDataCallBackEx, 0, 0x0000001f);
        }
        HANDLE hThread1 = CreateThread(NULL, 0, DataDeal, NULL, 0, NULL);
#endif
#if !SWITCH
        //2.文件取流 回放
        NET_RECORDFILE_INFO info = { 0 };
        LPNET_TIME time_start = (LPNET_TIME)malloc(sizeof(LPNET_TIME));
        LPNET_TIME time_end = (LPNET_TIME)malloc(sizeof(LPNET_TIME));
        time_start->dwYear = 2017;
        time_start->dwMonth = 11;
        time_start->dwDay = 10;
        time_start->dwHour = 9;
        time_start->dwMinute = 10;
        time_start->dwSecond = 0;
        time_end->dwYear = 2017;
        time_end->dwMonth = 11;
        time_end->dwDay = 10;
        time_end->dwHour = 9;
        time_end->dwMinute = 15;
        time_end->dwSecond = 0;
        //设置回放时间段
        lSearch = CLIENT_FindFile(lLogin, 0, 0, NULL, time_start, time_end, FALSE, 1000);
        //CLIENT_FindFile 第二个参数为通道号,文件回放只允许开启一个通道进行文件回放 第三个参数为文件类型
        int result = CLIENT_FindNextFile(lSearch, &info);
        //查询到符合参数的文件名 存储于info结构体中
        LONG state = CLIENT_PlayBackByRecordFileEx(lLogin,&info,NULL,cbDownLoadPos,NULL,fDownLoadDataCallBack,NULL);
        HANDLE hThread1 = CreateThread(NULL, 0, DataDeal, NULL, 0, NULL);
#endif
    }
    getchar();
    //释放网络库  
    CLIENT_StopRealPlay(lRealPlay);
    CLIENT_Logout(lLogin);
    CLIENT_Cleanup();
    //关闭播放通道,释放资源  
    PLAY_Stop(PLAYPORT);
    PLAY_CloseStream(PLAYPORT);
    return 0;
}

PS:部分代码借鉴了某位博主的代码,但现在已经忘记了是哪位博主了,若该博主能看到这篇博文,请与我联系,我添加上相关引用说明,非常感谢该博主的代码给了我很大帮助。

此处附上代码工程,工程环境为VS2013
github:https://github.com/alonegiveup/NVRForDaHua.git

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
要基于海康SDK实现网络硬盘录像机(NVR)的实时预览,可以使用Spring Boot框架来开发。首先,需要引入海康SDK的依赖,例如海康SDK提供的Java SDK。 在Spring Boot的配置文件中,配置海康SDK的相关参数,例如NVR的地址、端口号、用户名和密码等。这些参数可以通过配置文件的方式进行管理,方便后续维护和修改。 接着,在Spring Boot项目中创建一个Controller,用于处理实时预览的请求。在该Controller中,可以调用海康SDK提供的接口,进行NVR的登录。登录成功后,可以获取到NVR的实时预览的实时流地址。 然后,可以使用Spring Boot提供的Web Socket功能实现实时流的推送。在Controller中,可以创建一个Web Socket连接,将实时流发送给前端页面。前端页面可以使用一些HTML5的标签和JavaScript库,例如video标签和Hls.js库,来实现实时预览的功能。 在Web Socket连接中,可以通过循环不断地从海康SDK获取实时流数据,并将数据发送给Web Socket连接。前端页面接收到数据后,可以将数据解析并显示在页面上,实现实时预览的效果。 最后,需要在Spring Boot项目中加入定时任务,定时检测NVR的状态,并在NVR断线或出现异常的情况下进行处理。可以将NVR的状态保存到数据库中,并在定时任务中检查NVR的状态,对异常状态进行处理,例如重新登录NVR或发送报警信息。 总之,通过使用Spring Boot框架和海康SDK,可以实现基于海康SDK的网络硬盘录像机NVR的实时预览功能。将海康SDK的接口与Spring Boot的功能相结合,可以实现更加稳定和高效的实时预览系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ant5985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值