基于Qt+海康sdk+MySql的远程录像下载程序

一.前言

距离上次完成的Linux下QT实时音频采集传输项目已经有一个月的时间。之后又在Linux上完成了许多大大小小的项目,多是与UI有关。

这次给实现的是Windows下的QT+Mysql+海康sdk的远程录像下载程序。

需要QT连上Mysql,数据库版本必须和QT对应,32位QT是连不上64位的Mysql滴。连接方法可以参考这个文章:QT5.5连接mysql5.6 或 本文setsql.cpp中 sql_init() 函数的内容。

另外还测试了用SqlServer连接,原理差不多,只修改了连接部分,程序运行良好。


二.程序流程

程序的流程思路很简单:先通过QT进入本地Mysql数据库,遍历一张表,找出未下载过的录像记录并读取对应的IP和时间Time,逐个添加到海康sdk中,下载该IP号录像机在这个时间Time的录像。下载完毕后更新数据库。

 

1.Mysql表参考 (表名:ear)

基于Qt+海康sdk+MySql的远程录像下载程序_第1张图片  

EAR_Ip:录像机IP号     EAR_Time:下载该时间的录像     

EAR_Confirm:确认是否下载(已下载为1,未下载为0)

 

2.海康sdk录像下载流程(截自官方的设备网络SDK使用手册)

 基于Qt+海康sdk+MySql的远程录像下载程序_第2张图片

 写的非常清楚,对应的sdk函数都在里面写好了,跟着调用就好。本篇是按时间查找下载。

 

 

3.程序流程

基于Qt+海康sdk+MySql的远程录像下载程序_第3张图片


二.项目代码

 

1.   pro文件

手头的海康Lib、.h文件、.dll文件需要链接到QT上,不知道如何添加的朋友可以参考这篇文章:QT 添加 lib库

QT+= sql 要加上

#-------------------------------------------------
#
# Project created by QtCreator 2018-07-30T16:12:52
#
#-------------------------------------------------

QT       += core gui sql

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = DownloadVideo
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0


SOURCES += main.cpp\
        dialog.cpp \
        setsql.cpp \
    HK_sdk.cpp


HEADERS  += dialog.h \
    setsql.h\
    HK_sdk.h

FORMS    += dialog.ui


INCLUDEPATH += $$PWD/include

LIBS += -L$$PWD/ -lGdiPlus
LIBS += -L$$PWD/ -lHCAlarm
LIBS += -L$$PWD/ -lHCCore
LIBS += -L$$PWD/ -lHCGeneralCfgMgr
LIBS += -L$$PWD/ -lHCPreview
LIBS += -L$$PWD/ -lPlayCtrl
LIBS += -L$$PWD/ -lHCNetSDK

2.   .h文件

 

HK_SDK.h

/*********************************
*     本文件主要包含海康SDK中
*     下载模块的各种接口函数
*  以及对QSTring格式的时间处理函数
* [email protected]  姓值钱的金三岁
* --------2018年7月30日-----------
*********************************/


#ifndef HK_SDK_H
#define HK_SDK_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include "windows.h"
#include "HCNetSDK.h"



using namespace std;

//因为要用到QTimer,因此继承QObject
class HK_SDK:public QObject
{
    Q_OBJECT
public:
    explicit HK_SDK(QObject *parent=0);
    ~HK_SDK();


    void HK_Login(QString ip);               //登录设备
    bool HK_DownLoadVideo(QString Ptime);    //下载录像
    void get_DownloadPos();                  //获取下载进度
    void Time_Adjust(QString time);          //时间处理


    int ChannelNumber = -1;                                 //存储通道号
    QString SavePath = "D:/Qt Save/SDK_Save/VideoSave/";    //文件存储路径
    char * IPAdress = "192.168.0.10";                       //录像总线IP号
    WORD PORT       = 8000;                                 //录像总线端口号
    char * Username = "admin";                              //录像总线登录用户名
    char * Password = "admin123";                           //录像总线登录密码 
    long user_id    = -1;                                   //登录号返回的用户id号(类似socket里面的套接字fd)
    uint last_error = 0;                                    //用于存储最近一次的错误
    int findHandle  = -1;                                   //录像查找句柄
    int downHandle  = -1;                                   //录像下载句柄
    int ipos        = 0;                                    //录像下载句柄
    DWORD dwReturn;                                         //作参数传入NET_DVR_GetDVRConfig,作用未知
    NET_DVR_DEVICEINFO_V30    lpDeviceInfo;        //设备参数结构体
    NET_DVR_LOCAL_GENERAL_CFG _cfg;                //通用参数配置结构体
    NET_DVR_IPPARACFG_V40     m_struIpParaCfgV40;  //IP设备资源及IP通道资源配置结构体
    LPNET_DVR_FILECOND_V40    pFindCond;           //欲查找的文件信息结构
    LPNET_DVR_PLAYCOND        pDownloadCond;       //回放或者下载信息结构体


    QTimer *tim;          //作定时器,隔一段时间获取一次下载进度


    DWORD  HouRange = 0;  //设定下载的时间范围 小时
    DWORD  MinRange = 1;  //设定下载的时间范围 分钟
    DWORD  SecRange = 30; //设定下载的时间范围 秒


public slots:
    void get_Pos();      //槽函数,响应定时器,获取当前下载进度

private:

    /*录像起始时间结构体*/
    typedef struct STime_Config{
        DWORD Year;
        DWORD Month;
        DWORD Day;
        DWORD Hour;
        DWORD Minute;
        DWORD Second;
    }stime_conf;
    stime_conf *st;

    
    /*录像结束时间结构体*/
    typedef struct ETime_Config{
        DWORD Year;
        DWORD Month;
        DWORD Day;
        DWORD Hour;
        DWORD Minute;
        DWORD Second;
    }etime_conf;
     etime_conf *et;

    /*用于存储sdk返回的设备通道号*/
    int iChannelNum[96];

};

#endif // HK_SDK_H

setsql.h

/*********************************
*  本文件功能主要用于连接、读取
*  和更新本地Mysql数据库
*  同时定义HK类用于控制录像下载
* [email protected]  姓值钱的金三岁
*********************************/
#ifndef SETSQL_H
#define SETSQL_H
#include 
#include 
#include 
#include 
#include 

#include 
#include 

#include "HK_sdk.h"
using namespace std;

class SetSql
{
public:
    SetSql();
    ~SetSql();
    QString TableName="ear";                  //库名 可自行修改
    bool sql_init();                          //连接本地sql库
    void Show_Table();                        //打印表中所有数据
    void Change_TableConfirm(QString EAR_IP); //下载完毕后根据EAR_IP改变表中对应数据的EAR_Confirm
    void GetTime();                           //获得表中EAR_Confirm=0(未下载)的数据ip和time
    void DownLoadVideo();                     //下载录像


private:
    HK_SDK *hk;                               //该类包含海康sdk下载所需的接口函数

    QSqlDatabase db;                          //数据库句柄

    /*结构体存储未下载过的录像的IP和时间*/
    typedef struct UPDATE{
        QString EAR_IP;
        QString EAR_Time;
        bool EAR_Confirm;
    }update;
    update up;
    
    /*List容器存储update结构体*/
    typedef list upSave;
    upSave ups;

};
#endif // SETSQL_H

3.   .cpp文件

HK_SDK.cpp

#include "HK_sdk.h"


HK_SDK::HK_SDK(QObject *parent)
    :QObject(parent)
{

    st = new stime_conf;
    et = new etime_conf;

    tim = new QTimer(this);
    connect(tim,SIGNAL(timeout()),this,SLOT(get_Pos()));  //定时器连接槽函数,槽函数功能为获取下载进度

    /*初始化SDK*/
    if(NET_DVR_Init())
    {
        qDebug()<<"Init success!";
        NET_DVR_SetLogToFile(3,"D:/Qt Save/log/",true);
    }
    else
        qDebug()<<"Init Failed !";
}

HK_SDK::~HK_SDK()
{
    if(!NET_DVR_Logout(user_id))
    {
        last_error = NET_DVR_GetLastError();
        qDebug()<<"NET_DVR_Logout Error:"< 0)
    {
        if(!NET_DVR_GetDVRConfig(user_id,NET_DVR_GET_IPPARACFG_V40,0,
                                 &m_struIpParaCfgV40,sizeof(m_struIpParaCfgV40),&dwReturn))
        {
            last_error = NET_DVR_GetLastError();
            qDebug()<<"NET_DVR_GET_IPPARACFG_V40 Failed:"<lChannel = iChannelNum[ChannelNumber];
    pFindCond->dwFileType = 0xff;  //0xff-全部,0-定时录像,1-移动侦测,2-报警触发,...
    pFindCond->dwIsLocked = 0xff;  //0-未锁定文件,1-锁定文件,0xff表示所有文件(包括锁定和未锁定)

    //设置录像查找的开始时间
    pFindCond->struStartTime.dwYear = st->Year;
    pFindCond->struStartTime.dwMonth = st->Month;
    pFindCond->struStartTime.dwDay = st->Day;
    pFindCond->struStartTime.dwHour = st->Hour;
    pFindCond->struStartTime.dwMinute = st->Minute;
    pFindCond->struStartTime.dwSecond = st->Second;

    //设置录像查找的结束时间
    pFindCond->struStopTime.dwYear = et->Year;
    pFindCond->struStopTime.dwMonth = et->Month;
    pFindCond->struStopTime.dwDay = et->Day;
    pFindCond->struStopTime.dwHour = et->Hour;
    pFindCond->struStopTime.dwMinute = et->Minute;
    pFindCond->struStopTime.dwSecond = et->Second;


    findHandle = NET_DVR_FindFile_V40(user_id,pFindCond);

    if(findHandle < 0)
    {
        last_error = NET_DVR_GetLastError();
        qDebug()<<"NET_DVR_FindFile_V40 Failed:"<dwChannel = iChannelNum[ChannelNumber];

        //设置录像下载的开始时间
        pDownloadCond->struStartTime.dwYear = st->Year;
        pDownloadCond->struStartTime.dwMonth = st->Month;
        pDownloadCond->struStartTime.dwDay = st->Day;
        pDownloadCond->struStartTime.dwHour = st->Hour;
        pDownloadCond->struStartTime.dwMinute = st->Minute;
        pDownloadCond->struStartTime.dwSecond = st->Second;

        //设置录像下载的结束时间
        pDownloadCond->struStopTime.dwYear = et->Year;
        pDownloadCond->struStopTime.dwMonth = et->Month;
        pDownloadCond->struStopTime.dwDay = et->Day;
        pDownloadCond->struStopTime.dwHour = et->Hour;
        pDownloadCond->struStopTime.dwMinute = et->Minute;
        pDownloadCond->struStopTime.dwSecond = et->Second;

        //设置录像的存储路径,命名格式为表EAR_Time里的时间+.mp4,年月日时分秒用'-'隔开
        Ptime.replace("-","-");
        Ptime.replace("T","-");
        Ptime.replace(":","-");
        QString str = SavePath + Ptime +".mp4";
        char*  SaveFile;
        QByteArray ba = str.toLatin1(); // must
        SaveFile=ba.data();
        qDebug()<<"**********************************"<start(5000);   //开启定时器 每隔五秒获取一次下载进度
                return true;
            }
        }
    }
}

/*获取下载进度 0~100*/
void HK_SDK::get_DownloadPos()
{
    ipos = NET_DVR_GetDownloadPos(downHandle);
    qDebug()<<"Download===========> "<stop();
    }
}


/*时间处理函数 sdk需要年、月、日、时、分、秒,这里
 * 将EAR_Time字符串分割开,并添加范围,传入结构体*/
void HK_SDK::Time_Adjust(QString time)
{
    qDebug()<<"TIME ADJUST!!!!!!!!!!!!";
    //2018-07-24T09:06:11
    DWORD Year = time.section('-',0,0).toInt();
    DWORD Month= time.section('-',1,1).toInt();
    DWORD Day  = time.section('-',2,2).section('T',0,0).toInt();
    DWORD Hour = time.section('-',2,2).section('T',1,1).section(':',0,0).toInt();
    DWORD Min  = time.section('-',2,2).section('T',1,1).section(':',1,1).toInt();
    DWORD Sec  = time.section('-',2,2).section('T',1,1).section(':',2,2).toInt();

    qDebug()< R_sum)
    {
        st->Year = Year;
        st->Month = Month;
        st->Day = Day;

        SUM = S_sum - R_sum;
        st->Hour = SUM/3600;
        st->Minute = (SUM%3600)/60;
        st->Second = (SUM%3600)%60;
    }
    else
    {
        st->Year = Year;
        st->Month = Month;
        if(Day = 1)
        {
            st->Day = Day;
            st->Hour = 0;
            st->Minute = 0;
            st->Second = 0;
            qDebug()<<"=============仅限查询本月视频 上月视频请重新设置============";
        }
        else
        {
            st->Day = Day - 1;

            SUM = S_sum - R_sum + 24 * 3600;
            st->Hour = SUM/3600;
            st->Minute = (SUM%3600)/60;
            st->Second = (SUM%3600)%60;
        }
    }
    qDebug()<Year<Month<Day<Hour<Minute<Second;


//------------------------------------------------------------------------------


    if(S_sum + R_sum > D_sum)
    {
        et->Year = Year;
        et->Month = Month;
        et->Day = Day;
        et->Hour = 23;
        et->Minute = 59;
        et->Second = 59;
        qDebug()<<"=============仅限查询本日视频 次日视频请重新设置============";
    }
    else
    {
        et->Year = Year;
        et->Month = Month;
        et->Day = Day;
        SUM = S_sum + R_sum;
        et->Hour = SUM/3600;
        et->Minute = (SUM%3600)/60;
        et->Second = (SUM%3600)%60;
    }

     qDebug()<Year<Month<Day<Hour<Minute<Second;
}

/*槽函数 触发下载进度查询*/
void HK_SDK::get_Pos()
{
    get_DownloadPos();
}

 

setsql.cpp

#include "setsql.h"

SetSql::SetSql()
{
    hk = new HK_SDK();
    sql_init();
    DownLoadVideo();
}

SetSql::~SetSql()
{
    delete hk;
}

/*登录数据库*/
bool SetSql::sql_init()
{
    db = QSqlDatabase::addDatabase("QMYSQL");
    db.setConnectOptions("UTF8");
    db.setHostName("127.0.0.1");    //mysql的地址
    db.setPort(3306);               //数据库端口号
    db.setDatabaseName("ear");      //连接的数据库名称
    db.setUserName("root");         //mysql登录名
    db.setPassword("root");         //mysql密码
    if(db.open())
    {
        qDebug()<<"SQL init success!";
        qDebug()<::iterator iter;
    qDebug()<<"<=======Get Time========>";
    for(iter=ups.begin();iter!=ups.end();iter++)
    {
        qDebug()<EAR_IP<EAR_Time<EAR_Confirm;
    }
    qDebug()<<"<=======Get Time========>";
}


/*循环遍历List,按ip和time下载对应的录像*/
void SetSql::DownLoadVideo()
{
    GetTime();
    list::iterator iter;
    QString time;
    for(iter=ups.begin();iter!=ups.end();iter++)
    {
        time = iter->EAR_Time;
        hk->Time_Adjust(time);
        hk->HK_Login(iter->EAR_IP);
        if(hk->HK_DownLoadVideo(iter->EAR_Time))
            Change_TableConfirm(iter->EAR_IP);
    }
}

Main.cpp

#include "dialog.h"
#include 
#include "setsql.h"
#include "HK_sdk.h"
#include 
#include 
#include 
#include 
#include 
#include 

/*海康SDK头文件 必须添加!*/
#include "HCNetSDK.h"



int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    /*这句非常重要 很多人读写数据库乱码问题就是没加这句话*/
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8"));

    SetSql sql;

    return a.exec();
}

四.运行结果

若表如下,IP号0.68和0.2没下载,需要下载该EAR_Time下的录像

基于Qt+海康sdk+MySql的远程录像下载程序_第4张图片

运行QT程序,GetTime()函数找到他们俩

然后开始下载,得到下载进度

基于Qt+海康sdk+MySql的远程录像下载程序_第5张图片

下载完后两个表已更新

基于Qt+海康sdk+MySql的远程录像下载程序_第6张图片

对应路径下已经得到了这两个录像文件,命名格式按EAR_Time命名

基于Qt+海康sdk+MySql的远程录像下载程序_第7张图片


五.遇到的问题与注意事项

(1) 海康的sdk分 64位和32位,请与QT版本对应好,否则无法链接。

(2) 海康的几个.h文件需要转编码格式(若数据库和QT是其他编码格式就转成和他们一样),我是用Notepad++转成UTF-8。

(3)出现数据库在QT输出框上显示乱码的问题,程序Main开头加上 这句话:

QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8"));

(4)注意sdk中类似于下面这种

LPNET_DVR_FILECOND_V40 / LPNET_DVR_PLAYCOND

NET_DVR_FILECOND_V40 / NET_DVR_PLAYCOND

的区别。前面有没有LP,决定了这些函数内传入的参数结构体是否该加取地址符(&),需要注意一下。

你可能感兴趣的:(基于Qt+海康sdk+MySql的远程录像下载程序)