From 3f1ffca85625204be833f801fe5611dcd7d68a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E8=B6=85?= Date: Thu, 24 Oct 2024 17:24:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=AF=B9=E6=8E=A5=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4=E4=BF=A1=E6=81=AF)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 50 ++++ HX_CameraLoopPlay/CameraLoopPlay.cpp | 262 +++++++++++++++++- HX_CameraLoopPlay/CameraLoopPlay.h | 181 +++++++++++- HX_CameraLoopPlay/CameraLoopPlay.qrc | 4 + HX_CameraLoopPlay/CameraLoopPlay.ui | 91 +++++- HX_CameraLoopPlay/CameraThread.cpp | 189 ++++++++++++- HX_CameraLoopPlay/CameraThread.h | 137 ++++++++- HX_CameraLoopPlay/ControlptzWidget.cpp | 10 + HX_CameraLoopPlay/ControlptzWidget.h | 16 ++ HX_CameraLoopPlay/ControlptzWidget.ui | 22 ++ HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj | 15 +- .../HX_CameraLoopPlay.vcxproj.filters | 92 ++++++ .../Resource/image/AI摄像头.ico | Bin 0 -> 4286 bytes .../Resource/image/head_title.png | Bin 0 -> 18448 bytes HX_CameraLoopPlay/Resource/image/min.png | Bin 0 -> 372 bytes .../Resource/image/min_honver.png | Bin 0 -> 406 bytes HX_CameraLoopPlay/SingleCameraWidget.cpp | 12 + HX_CameraLoopPlay/SingleCameraWidget.h | 16 ++ HX_CameraLoopPlay/SingleCameraWidget.ui | 124 +++++++++ HX_CameraLoopPlay/cameradeviceinfo.h | 46 +++ .../component/videowindowscomponent.cpp | 40 +++ .../component/videowindowscomponent.h | 29 ++ HX_CameraLoopPlay/model/CameraDeviceInfo.h | 46 +++ 23 files changed, 1364 insertions(+), 18 deletions(-) create mode 100644 .gitignore create mode 100644 HX_CameraLoopPlay/ControlptzWidget.cpp create mode 100644 HX_CameraLoopPlay/ControlptzWidget.h create mode 100644 HX_CameraLoopPlay/ControlptzWidget.ui create mode 100644 HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj.filters create mode 100644 HX_CameraLoopPlay/Resource/image/AI摄像头.ico create mode 100644 HX_CameraLoopPlay/Resource/image/head_title.png create mode 100644 HX_CameraLoopPlay/Resource/image/min.png create mode 100644 HX_CameraLoopPlay/Resource/image/min_honver.png create mode 100644 HX_CameraLoopPlay/SingleCameraWidget.cpp create mode 100644 HX_CameraLoopPlay/SingleCameraWidget.h create mode 100644 HX_CameraLoopPlay/SingleCameraWidget.ui create mode 100644 HX_CameraLoopPlay/cameradeviceinfo.h create mode 100644 HX_CameraLoopPlay/component/videowindowscomponent.cpp create mode 100644 HX_CameraLoopPlay/component/videowindowscomponent.h create mode 100644 HX_CameraLoopPlay/model/CameraDeviceInfo.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d856f20 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +*.vcxproj.user +*.zip + +Debug +Release +.vs +GeneratedFiles + +moc_*.cpp +*.pdb +*.lib +*.exp + +*.lib +*.pdb +*.exp +*.output diff --git a/HX_CameraLoopPlay/CameraLoopPlay.cpp b/HX_CameraLoopPlay/CameraLoopPlay.cpp index 2c9a69f..f6aeb28 100644 --- a/HX_CameraLoopPlay/CameraLoopPlay.cpp +++ b/HX_CameraLoopPlay/CameraLoopPlay.cpp @@ -1,24 +1,268 @@ -#include "CameraLoopPlay.h" +#include "CameraLoopPlay.h" +#include "ui_CameraLoopPlay.h" +#include "ui_SingleCameraWidget.h" +#include +#include +#include +#include +#include +#include +#include +#include -CameraLoopPlay::CameraLoopPlay(QWidget *parent) - : QMainWindow(parent), ui(new Ui::CameraLoopPlayClass) +// 相机列表JSON文件名称 +const QString CameraJsonFileName = "camera.json"; + +CameraLoopPlay::CameraLoopPlay(QWidget* parent) + : QMainWindow(parent), ui(new Ui::CameraLoopPlayClass) { - ui->setupUi(this); + ui->setupUi(this); - // ز˵ - setWindowFlag(Qt::FramelessWindowHint); - setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint); + // 隐藏菜单栏 + setWindowFlag(Qt::FramelessWindowHint); + setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint); + + qRegisterMetaType("HWND"); + + m_cameraLoopThread = new QThread(this); + m_cameraThread = new CameraThread(); + m_cameraThread->moveToThread(m_cameraLoopThread); + + connect(m_cameraLoopThread, &QThread::started, m_cameraThread, &CameraThread::run); + connect(m_cameraLoopThread, &QThread::finished, m_cameraThread, &CameraThread::stop); + connect(this, &CameraLoopPlay::loginSignal, m_cameraThread, &CameraThread::login); + connect(this, &CameraLoopPlay::realPlaySignal, m_cameraThread, &CameraThread::realPlay); + connect(this, &CameraLoopPlay::stopReadPlaySignal, m_cameraThread, &CameraThread::stopRealPlay); + + m_cameraLoopThread->start(); + + calendarTimerUpdater(); + + connect(ui->comboBox_windowNumber, SIGNAL(currentIndexChanged(int)), this, SLOT(changeWindowNumber(int))); + + initTreeViewCameraList(); + + initCameraFarmes(); } CameraLoopPlay::~CameraLoopPlay() { - delete ui; + // 关闭并等待视频轮播线程完成 + if (m_cameraThread && m_cameraLoopThread->isRunning()) { + m_cameraLoopThread->quit(); + m_cameraLoopThread->wait(); + } + + delete m_cameraLoopThread; + delete m_cameraThread; + delete ui; } +bool CameraLoopPlay::eventFilter(QObject* watched, QEvent* event) +{ + return false; +} + +void CameraLoopPlay::on_pushButton_min_clicked() +{ + this->showMinimized(); +} + +void CameraLoopPlay::on_pushButton_slide_clicked() +{ + if (m_unfold) { + ui->widget_left->hide(); + ui->pushButton_slide->setStyleSheet("border-image: url(:/CameraLoopPlay/Resource/image/unfold.png);"); + m_unfold = false; + } + else { + ui->widget_left->show(); + ui->pushButton_slide->setStyleSheet("border-image: url(:/CameraLoopPlay/Resource/image/fold.png);"); + m_unfold = true; + } +} + +void CameraLoopPlay::on_pushButton_loopPlay_clicked() +{ + if (ui->pushButton_loopPlay->text() == QStringLiteral("开启轮播")) { + ui->pushButton_loopPlay->setText(QStringLiteral("关闭轮播")); + // 开启轮播 + startLoopPlay(); + } + else { + ui->pushButton_loopPlay->setText(QStringLiteral("开启轮播")); + // 关闭轮播 + stopLoopPlay(); + } +} + +void CameraLoopPlay::changeWindowNumber(int index) +{ + if (index == 0) { + addCameraWidgetToCameraFarmes(1, 1); + } + else if (index == 1) { + addCameraWidgetToCameraFarmes(2, 2); + } + else if (index == 2) { + addCameraWidgetToCameraFarmes(3, 3); + } + else if (index == 3) { + addCameraWidgetToCameraFarmes(4, 4); + } + else if (index == 4) { + addCameraWidgetToCameraFarmes(4, 5); + } + else if (index == 5) { + addCameraWidgetToCameraFarmes(6, 6); + } +} + +void CameraLoopPlay::addCameraWidgetToCameraFarmes(int rows, int cols) +{ + // 清除已有的布局项 + QLayoutItem* item; + while ((item = ui->gridLayout_cameraFarmes->takeAt(0)) != nullptr) { + delete item->widget(); + delete item; + } + + // 停止摄像头播放 + stopVideoStreamPlay(); + m_singleCameraWidgetList.clear(); + //m_lastFocusSignalCameraWidget = nullptr; + + // 遍历行和列,添加widget到gridLayout中 + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + + int index = (row * cols + col); + + QWidget* cameraWidgetContainer = new QWidget; + Ui::SingleCameraWidget* signalCameraWidget = new Ui::SingleCameraWidget; + signalCameraWidget->setupUi(cameraWidgetContainer); + + signalCameraWidget->label_cameraNumber->hide(); + + if (m_cameraDeviceInfoList.count() > index) { + signalCameraWidget->widget_camera->setCameraName( m_cameraDeviceInfoList[index].getName()); + signalCameraWidget->widget_camera->setCameraWidgetWidth( signalCameraWidget->widget_camera->width()); + + signalCameraWidget->label_cameraNumber->setText( m_cameraDeviceInfoList[index].getName()); + emit realPlaySignal((HWND)signalCameraWidget->label_camera->winId(), index); + signalCameraWidget->label_camera->raise(); + } + else { + signalCameraWidget->widget_camera->setCameraName(QStringLiteral("无视频%1").arg(index)); + } + + signalCameraWidget->label_camera->installEventFilter(this); + signalCameraWidget->label_camera->setFocusPolicy(Qt::StrongFocus); + + m_singleCameraWidgetList.append(signalCameraWidget); + ui->gridLayout_cameraFarmes->addWidget(cameraWidgetContainer, row, col); + } + } +} + +void CameraLoopPlay::calendarTimerUpdater() +{ + QTimer* timer_calendar = new QTimer(this); + connect(timer_calendar, &QTimer::timeout, this, [this]() { + QDateTime time = QDateTime::currentDateTime(); + QString str = time.toString("yyyy-MM-dd hh:mm:ss dddd"); + ui->label_clander->setText(str); + }); + timer_calendar->start(1000); //每一秒溢出一次进入槽函数 +} + +void CameraLoopPlay::startLoopPlay() +{ + +} + +void CameraLoopPlay::stopLoopPlay() +{ +} + +void CameraLoopPlay::initTreeViewCameraList() +{ + ui->treeView_cameraList->setHeaderHidden(true); + ui->treeView_cameraList->setEditTriggers(QAbstractItemView::NoEditTriggers); + + readCameraJsonInfo(); +} + +void CameraLoopPlay::readCameraJsonInfo() +{ + QFile file(QCoreApplication::applicationDirPath() + "/" + CameraJsonFileName); + + if (file.open(QIODevice::ReadOnly)) { + QByteArray jsonData = file.readAll(); + file.close(); + + int indexValue = 0; + QStandardItemModel* standardItemModel = new QStandardItemModel(this); + + QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonData)); + QJsonObject jsonObject = jsonDoc.object(); + for (auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); ++it) { + QJsonArray jsonArray = it.value().toArray(); + + QStandardItem* rootItem = new QStandardItem(it.key()); + rootItem->setIcon(QIcon(":/CameraLoopPlay/Resource/image/camera.png")); + + for (QJsonValue deviceInfo : jsonArray) { + + QString cameraDeviceName = deviceInfo["Name"].toString(); // 摄像头名称 + QString cameraDeviceIP = deviceInfo["IP"].toString(); + QString cameraDeviceUserName = deviceInfo["UserName"].toString(); + QString cameraDevicePassWord = deviceInfo["PassWord"].toString(); + CameraDeviceInfo cameraDeviceInfo(indexValue, cameraDeviceName, cameraDeviceIP, cameraDeviceUserName, cameraDevicePassWord); + + // 登录摄像头 + emit loginSignal(cameraDeviceIP, cameraDeviceUserName, cameraDevicePassWord, indexValue, cameraDeviceName); + + indexValue++; + + // 加入至摄像头列表树 + QStandardItem* subItem = new QStandardItem(cameraDeviceName); + + subItem->setIcon(QIcon(":/CameraLoopPlay/Resource/image/offline.png")); + rootItem->appendRow(subItem); + m_treeCameraItemList.append(subItem); + m_cameraDeviceInfoList.append(cameraDeviceInfo); + } + + standardItemModel->appendRow(rootItem); + } + + ui->treeView_cameraList->setModel(standardItemModel); + ui->treeView_cameraList->expandAll(); + } +} + +void CameraLoopPlay::initCameraFarmes() +{ + ui->comboBox_windowNumber->setCurrentIndex(4); + //addCameraWidgetToCameraFarmes(4, 5); +} + +void CameraLoopPlay::stopVideoStreamPlay() +{ + if (m_cameraDeviceInfoList.isEmpty()) + return; + for (int i = 0; i < m_cameraDeviceInfoList.size(); i++) { + int cameraIndex = m_cameraDeviceInfoList.at(i).getTreeindex(); + emit stopReadPlaySignal(cameraIndex-1); + } +} + + void CameraLoopPlay::on_pushButton_close_clicked() { - this->close(); + this->close(); } diff --git a/HX_CameraLoopPlay/CameraLoopPlay.h b/HX_CameraLoopPlay/CameraLoopPlay.h index fe3433a..0ef84b0 100644 --- a/HX_CameraLoopPlay/CameraLoopPlay.h +++ b/HX_CameraLoopPlay/CameraLoopPlay.h @@ -7,7 +7,18 @@ #pragma once #include -#include "ui_CameraLoopPlay.h" +#include +#include + +#include "model/CameraDeviceInfo.h" +#include "CameraThread.h" +#include "SingleCameraWidget.h" + +namespace Ui +{ + class CameraLoopPlayClass; + class SingleCameraWidget; +} class CameraLoopPlay : public QMainWindow { @@ -17,6 +28,38 @@ public: CameraLoopPlay(QWidget *parent = nullptr); ~CameraLoopPlay(); +protected: + bool eventFilter(QObject* watched, QEvent* event) override; + +signals: + + /** + * @brief ȡƵ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void realPlaySignal(HWND hWnd, int hWndIndex); + + /** + * @brief ͷ¼. + * @param strIP IP + * @param strUser û + * @param strPwd + * @param hWndIndex + * @param cameraName ͷ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + void loginSignal(QString strIP, QString strUser, QString strPwd, int hWndIndex, QString cameraName); + + /** + * @brief ֹͣƵ. + * @param hwndIndex + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + void stopReadPlaySignal(int hwndIndex); + private slots: /** @@ -26,6 +69,142 @@ private slots: */ void on_pushButton_close_clicked(); + /** + * @brief С. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + void on_pushButton_min_clicked(); + + /** + * @brief . + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void on_pushButton_slide_clicked(); + + /** + * @brief /رֲ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void on_pushButton_loopPlay_clicked(); + + /** + * @brief ޸Ĵڻ. + * @param index б + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void changeWindowNumber(int index); + + +private: + + /** + * @brief . + * @param rows + * @param cols + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void addCameraWidgetToCameraFarmes(int rows, int cols); + + /** + * @brief ʱʾ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void calendarTimerUpdater(); + + /** + * @brief ֲ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void startLoopPlay(); + + /** + * @brief رֲ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void stopLoopPlay(); + + /** + * @brief ʼб. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void initTreeViewCameraList(); + + /** + * @brief ȡ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void readCameraJsonInfo(); + + /** + * @brief ʼڽ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void initCameraFarmes(); + + /** + * @brief ֹͣƵIJ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + void stopVideoStreamPlay(); + + private: Ui::CameraLoopPlayClass *ui = nullptr; + + /** + * @brief ֲ߳ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + QThread* m_cameraLoopThread{ nullptr }; + + /** + * @brief ֲ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + CameraThread* m_cameraThread{ nullptr }; + + /** + * @brief ״̬ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + bool m_unfold = true; + + /** + * @brief ͷ豸Ϣб + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + QList m_cameraDeviceInfoList; + + /** + * @brief бͷ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + QList m_treeCameraItemList; + + /** + * @brief б + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + QList m_singleCameraWidgetList; + + + }; diff --git a/HX_CameraLoopPlay/CameraLoopPlay.qrc b/HX_CameraLoopPlay/CameraLoopPlay.qrc index 4e39902..dbd2a1e 100644 --- a/HX_CameraLoopPlay/CameraLoopPlay.qrc +++ b/HX_CameraLoopPlay/CameraLoopPlay.qrc @@ -26,5 +26,9 @@ Resource/image/zoom.png Resource/image/close.png Resource/image/close_hover.png + Resource/image/head_title.png + Resource/image/AI摄像头.ico + Resource/image/min.png + Resource/image/min_honver.png diff --git a/HX_CameraLoopPlay/CameraLoopPlay.ui b/HX_CameraLoopPlay/CameraLoopPlay.ui index 20fd13a..ad9881a 100644 --- a/HX_CameraLoopPlay/CameraLoopPlay.ui +++ b/HX_CameraLoopPlay/CameraLoopPlay.ui @@ -36,19 +36,28 @@ #widget_title{ - border-image: url(:/CameraLoopPlay/Resource/image/yuquan_workface_title.png); + border-image: url(:/CameraLoopPlay/Resource/image/head_title.png); background-color: transparent; } + + 20 + + + 30 + Qt::Horizontal + + QSizePolicy::Maximum + - 40 + 750 20 @@ -56,14 +65,23 @@ + + + 黑体 + 28 + 50 + false + false + + #label_title{ color:white; - font: 24pt "黑体"; + font: 28pt "黑体"; } - 标题示例 + 玉泉煤业工作面视频监控 @@ -95,6 +113,29 @@ font: 16pt "Arial"; + + + + + 32 + 32 + + + + QPushButton{ + border-image: url(:/CameraLoopPlay/Resource/image/min.png); + border:0; +} +QPushButton:hover{ + border-image: url(:/CameraLoopPlay/Resource/image/min_honver.png); + border:0; +} + + + + + + @@ -263,7 +304,47 @@ QPushButton:hover{ background-color: transparent; font-size:18px; color:white; -} +} + +QScrollBar:vertical{ + width:8px; + background:rgba(80,180,255,100%); + margin:0px,0px,0px,0px; + padding-top:2px; + padding-bottom:2px; + border-radius:4px; + } + QScrollBar::handle:vertical + { + width:8px; + background:rgba(0,0,0,25%); + border-radius:4px; + min-height:20; + } + QScrollBar::handle:vertical:hover + { + width:8px; + background:rgba(0,0,0,50%); + border-radius:4px; + min-height:20; + } + QScrollBar::add-line:vertical + { + height:9px;width:8px; + background-color:transparent; + subcontrol-position:bottom; + } + QScrollBar::sub-line:vertical + { + height:9px;width:8px; + background-color:transparent; + subcontrol-position:top; + } + QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical + { + background:rgba(0,0,0,10%); + border-radius:4px; + } diff --git a/HX_CameraLoopPlay/CameraThread.cpp b/HX_CameraLoopPlay/CameraThread.cpp index 9a45f48..bc76b18 100644 --- a/HX_CameraLoopPlay/CameraThread.cpp +++ b/HX_CameraLoopPlay/CameraThread.cpp @@ -1,8 +1,195 @@ #include "CameraThread.h" +#include +#include + CameraThread::CameraThread(QObject *parent) : QObject(parent) -{} +{ + checkLoginState(); + checkLoginStatu(); +} CameraThread::~CameraThread() {} + +void CameraThread::run() +{ + initSDK(); +} + +void CameraThread::stop() +{ + cleanupSDK(); +} + +void CameraThread::login(QString strIP, QString strUser, QString strPwd, int hWndIndex, QString cameraName) +{ + CameraDeviceInfo cameraDeviceInfo(hWndIndex,cameraName, strIP, strUser, strPwd); + + HWNDloginMsg.insert(hWndIndex, cameraDeviceInfo); + if (HWNDlogin.contains(hWndIndex) && HWNDlogin[cameraDeviceInfo.getIndex()] >= 0) { + logout(HWNDlogin[hWndIndex]); + } + + int loginId = -1; + long iRealPlayHandle = -1; + + NET_DVR_USER_LOGIN_INFO struLoginInfo = {}; // 첽¼״̬û ID 豸Ϣͨ NET_DVR_USER_LOGIN_INFO ṹõĻص (fLoginResultCallBack)ء + NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = {}; + + struLoginInfo.bUseAsynLogin = false; //ͬ¼ʽ + struLoginInfo.wPort = 8000; //豸˿ + strcpy_s(struLoginInfo.sDeviceAddress, strIP.toLatin1().data()); //豸ipַ + strcpy_s(struLoginInfo.sUserName, strUser.toLatin1().data()); //豸¼û + strcpy_s(struLoginInfo.sPassword, strPwd.toLatin1().data()); //豸¼ + + //豸Ϣ, + loginId = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40); // ûע豸 + + qDebug() << "loginId" << loginId; + HWNDlogin.insert(hWndIndex, loginId); + iIpcStartChan.insert(hWndIndex, struDeviceInfoV40.struDeviceV30.byStartChan); + +} + +bool CameraThread::realPlay(HWND hWnd, int index) +{ + int loginId = HWNDlogin[index]; + if (loginId == -1) { + return false; + } + + if (HWNDPlayHandle.contains(index) && HWNDPlayHandle[index] >= 0) + return true; + + long iRealPlayHandle = -1; + + NET_DVR_PREVIEWINFO struPlayInfo = {}; + struPlayInfo = {}; + struPlayInfo.hPlayWnd = hWnd; //Ҫ SDK ʱΪЧֵȡʱΪ + struPlayInfo.lChannel = 0 + iIpcStartChan[index]; //Ԥͨ + + struPlayInfo.dwStreamType = 1; //ͣ0-1-2-3-Դ + struPlayInfo.dwLinkMode = 4; //0- TCP ʽ1- UDP ʽ2- ಥʽ3- RTP ʽ4-RTP/RTSP5-RSTP/HTTP + struPlayInfo.bBlocked = 1; //0- ȡ1- ȡ + iRealPlayHandle = NET_DVR_RealPlay_V40(loginId, &struPlayInfo, NULL, NULL); // ʵʱԤ + + IsPlay.insert(index, 5); + + if (iRealPlayHandle < 0) { + qDebug() << "NET_DVR_RealPlay_V40 error;error number " << NET_DVR_GetLastError(); + return -1; + } + + IndexHWNDMap.insert(index, hWnd); + HWNDPlayHandle.insert(index, iRealPlayHandle); + return iRealPlayHandle; +} + +int CameraThread::stopRealPlay(int hWndIndex) +{ + int iRealPlayHandle = HWNDPlayHandle[hWndIndex]; + int errorId = 0; + if (iRealPlayHandle == -1) { + return true; + } + if (!NET_DVR_StopRealPlay(iRealPlayHandle)) { + errorId = NET_DVR_GetLastError(); + } + if (IsPlay.contains(hWndIndex)) { + IsPlay.remove(hWndIndex); + } + HWNDPlayHandle[hWndIndex] = -1; + return errorId; +} + +bool CameraThread::initSDK() +{ + // ʼ + bool isok = NET_DVR_Init(); + + if (isok == false) { + qDebug() << "NET_DVR_Init error;error number is " << NET_DVR_GetLastError(); // Ĵ + return isok; + } + + //ʱʱ + NET_DVR_SetConnectTime(2000, 1); // ӳʱʱӳԴ + NET_DVR_SetReconnect(10000, true); // + return isok; +} + +bool CameraThread::cleanupSDK() +{ + // ͷ SDK Դ + bool isok = NET_DVR_Cleanup(); + if (isok == false) { + qDebug() << "NET_DVR_Cleanup error;error number is " << NET_DVR_GetLastError(); + return isok; + } + return isok; +} + +void CameraThread::checkLoginState() +{ + // ÿ鲢ִ IsPlay беIJ + QTimer* replayTime = new QTimer(this); + connect(replayTime, &QTimer::timeout, this, [=]() { + if (IsPlay.count() > 0) { + QList tmp; + for (int i = 0; i < IsPlay.count(); i++) { + + // realPlay() в + realPlay(IndexHWNDMap[IsPlay.keys()[i]], IsPlay.keys()[i]); + IsPlay[IsPlay.keys()[i]]--; + if (IsPlay[IsPlay.keys()[i]] == 0) { + tmp.append(IsPlay.keys()[i]); + } + } + for (int i = 0; i < tmp.count(); i++) { + IsPlay.remove(tmp[i]); + } + } + }); + replayTime->start(1000); +} + +int CameraThread::logout(int loginId) +{ + + int errorId = 0; + if (loginId == -1 || loginId < 0) { + return true; + } + if (!NET_DVR_Logout(loginId)) { + errorId = NET_DVR_GetLastError(); + } + return errorId; + +} + +void CameraThread::checkLoginStatu() +{ + // ÿ10 Ӷʱ¼״̬ + QTimer* checkOnline = new QTimer(this); + connect(checkOnline, &QTimer::timeout, this, [=]() { + if (HWNDlogin.count() > 0) { + for (int i = 0; i < HWNDlogin.count(); i++) { + int loginIndex = HWNDlogin.keys()[i]; + + int loginId = HWNDlogin[loginIndex]; + if (loginId == -1) { + login(HWNDloginMsg[loginIndex].getIp(), HWNDloginMsg[loginIndex].getUsername(), HWNDloginMsg[loginIndex].getPassword(), loginIndex,HWNDloginMsg[loginIndex].getName()); + } + else { + bool isonline = NET_DVR_RemoteControl(loginId, 20005, nullptr, 0); + if (!isonline) { + login(HWNDloginMsg[loginIndex].getIp(), HWNDloginMsg[loginIndex].getUsername(), HWNDloginMsg[loginIndex].getPassword(), loginIndex, HWNDloginMsg[loginIndex].getName()); + } + } + } + } + }); + checkOnline->start(600000); +} diff --git a/HX_CameraLoopPlay/CameraThread.h b/HX_CameraLoopPlay/CameraThread.h index e3ab67d..9fd7f44 100644 --- a/HX_CameraLoopPlay/CameraThread.h +++ b/HX_CameraLoopPlay/CameraThread.h @@ -1,18 +1,153 @@ +/*****************************************************************//** + * @file CameraThread.h + * @brief ͷƵֲ߳ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + *********************************************************************/ #pragma once #include +#include +#include "windows.h" #include "HCNetSDK.h" +#include "cameradeviceinfo.h" class CameraThread : public QObject { Q_OBJECT public: - CameraThread(QObject *parent); + CameraThread(QObject *parent = nullptr); ~CameraThread(); +signals: + void loginResultSignal(long loginId, int iRealPlayHandle, int hWndIndex); +public slots: + /** + * @brief . + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void run(); + /** + * @brief ֹͣ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void stop(); + + /** + * @brief ¼ͷ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + void login(QString strIP, QString strUser, QString strPwd, int loginIndex, QString cameraName); + + /** + * @brief Ƶ. + * @param hWnd žϢ + * @param index + * @return + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + bool realPlay(HWND hWnd, int index); + + /** + * @brief ֹͣ. + * @param hWndIndex + * @return + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + int stopRealPlay(int hWndIndex); + +private: + + /** + * @brief ʼsdkԴ. + * @return true ʼɹfalse ʼʧ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + bool initSDK(); + + /** + * @brief ͷsdkԴ. + * @return + * @author XuChao (xxu715737@163.com) + * @date 2024-10-23 + */ + bool cleanupSDK(); + + /** + * @brief 鲢ִIsPlayбеIJ. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + void checkLoginState(); + + /** + * @brief ˳¼. + * @param loginId + * @return + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + int logout(int loginId); + + /** + * @brief ʱͷ¼״̬. + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + void checkLoginStatu(); + +private: + + /** + * @brief 豸,豸¼Ϣ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + QMap HWNDloginMsg; + + /** + * @brief 豸ʼͨӳ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + QMap iIpcStartChan; + + /** + * @brief 豸¼IDӳ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + QMap HWNDlogin; + + /** + * @brief 豸ʵʱԤ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + QMap HWNDPlayHandle; + + /** + * @brief ¼״̬ keyŴ + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + QMap IsPlay; + + /** + * @brief žź + * @author XuChao (xxu715737@163.com) + * @date 2024-10-24 + */ + QMap IndexHWNDMap; }; diff --git a/HX_CameraLoopPlay/ControlptzWidget.cpp b/HX_CameraLoopPlay/ControlptzWidget.cpp new file mode 100644 index 0000000..a796db3 --- /dev/null +++ b/HX_CameraLoopPlay/ControlptzWidget.cpp @@ -0,0 +1,10 @@ +#include "ControlptzWidget.h" + +ControlptzWidget::ControlptzWidget(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +ControlptzWidget::~ControlptzWidget() +{} diff --git a/HX_CameraLoopPlay/ControlptzWidget.h b/HX_CameraLoopPlay/ControlptzWidget.h new file mode 100644 index 0000000..11c7749 --- /dev/null +++ b/HX_CameraLoopPlay/ControlptzWidget.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "ui_ControlptzWidget.h" + +class ControlptzWidget : public QWidget +{ + Q_OBJECT + +public: + ControlptzWidget(QWidget *parent = nullptr); + ~ControlptzWidget(); + +private: + Ui::ControlptzWidgetClass ui; +}; diff --git a/HX_CameraLoopPlay/ControlptzWidget.ui b/HX_CameraLoopPlay/ControlptzWidget.ui new file mode 100644 index 0000000..5177eee --- /dev/null +++ b/HX_CameraLoopPlay/ControlptzWidget.ui @@ -0,0 +1,22 @@ + + ControlptzWidgetClass + + + ControlptzWidgetClass + + + + 0 + 0 + 600 + 400 + + + + ControlptzWidget + $centralwidget$ + + + + + diff --git a/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj b/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj index 0bde147..8f85736 100644 --- a/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj +++ b/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj @@ -66,6 +66,7 @@ ..\external\CH-HCNetSDK\include;%(AdditionalIncludeDirectories) + Disabled ..\external\CH-HCNetSDK\lib;%(AdditionalLibraryDirectories) @@ -95,22 +96,34 @@ Windows - false + true true true + + + + + + + + + + + + diff --git a/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj.filters b/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj.filters new file mode 100644 index 0000000..a182a20 --- /dev/null +++ b/HX_CameraLoopPlay/HX_CameraLoopPlay.vcxproj.filters @@ -0,0 +1,92 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + + + {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} + ts + + + {08feb7d5-209b-4a70-8be8-2943dbd43e49} + + + {36367f84-7f0a-45d9-8b96-53eaa0db232d} + + + + + Resource Files + + + Form Files + + + Header Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\component + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files\component + + + + + Header Files + + + Header Files + + + + + Form Files + + + Form Files + + + \ No newline at end of file diff --git a/HX_CameraLoopPlay/Resource/image/AI摄像头.ico b/HX_CameraLoopPlay/Resource/image/AI摄像头.ico new file mode 100644 index 0000000000000000000000000000000000000000..72d56668f400f31d2991f0c1dacac3377dcaffe2 GIT binary patch literal 4286 zcmeI0J8r`;3_zKtXghSsRCM%`z=I9s2suh_65YfddkaS=@e$lHOW~4|Xwh<97;Tuz z3K&}Q=kY5C0a)QD%YeS&a|7@O067XS!2yNV-N19pSRx=J(B{RV-IWbWcSC8~e4k0q z)N#8l>l<>T58LuM#gywRY#+-?a?)dt&%OD?ZFj{ugAS0&A7?80xl3=IlG^$WNd1`#j!9y&(mAm3YA)VrcL?_GwCs`cdK2 zo(BWUpowO@Fmlq`)e9y4oQyTrR6k>qC|NI_4#g*%!Hu$~& ze;xW&GM3{d0!swO5$KYE{}yyXzEOXnoKeip6_#XZZwI-$hr4>6J4UH||9 literal 0 HcmV?d00001 diff --git a/HX_CameraLoopPlay/Resource/image/head_title.png b/HX_CameraLoopPlay/Resource/image/head_title.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b10537030ffb6b18846eefa14b9e7721d2d6ef GIT binary patch literal 18448 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 KelF{r5}E)DS(vi` literal 0 HcmV?d00001 diff --git a/HX_CameraLoopPlay/Resource/image/min.png b/HX_CameraLoopPlay/Resource/image/min.png new file mode 100644 index 0000000000000000000000000000000000000000..c962d21811b5bbfb6e02a60f869889ba64348874 GIT binary patch literal 372 zcmV-)0gL{LP)Px$E=fc|R9Hvtmdz1@Fc5{`Qi)cg7NP?sIE-iT>{x>V3(-=n#F#JyVdXDC)B~It ze%|}`CE0}VV=fz~Assn@)DOHT zHsU~c7a-fS^a;3VZ3U1Ge=!GC0vUjL;Q~Nwa-SJsPGC;p>#ewP8M<2cTz52pf0FB` zhm~oiw&0@x%B@rx7yaA@qOB7~ZB;RI<7o}i)rxBc8_Xer;2M&cDuHY>;?YiN-fJ@| zLriUM0{}_5lf;_GJ0$k9M%Nr@9nP`lRtZd9xzQVx00ANiDX^LCP2Uazs9POFVa5P_ zEKysCyp7+~(f^T#w5&ap_7JUYR;IEZ|5pn6IFQ&1@X6KV|4IR0KM!!g8Q=xq5cDDR SawPBo0000Px$P)S5VR9HvtmeFa$Fc60SgDy~T-dt$Gouln0$s|oDsXIx#M;$QKfj}}s;1UVT z$ckk}vK9BiezdInzxyrS9bw{!Cf3LQ0@$b7J25Xo^cck%=8}o>yW{ceepi-4qj5lr z1M4WlMoml&0UXlo{2pN7ZBZ3JF+dIv&r2|Wir7h2$mAOb6o6WY0U%?p9P=NSV&8Tk45@Kxes{!gv#Y`YheESK^Tm^BqU)7lhpTE{I?N{dR;pA<8%b-(W72?dGX-D0Kz57OQ%y zcI`J4xfn=%1DJ=)wckwO=JUWsS#c4^UZ3276T7qxFzHx}AOHXW07*qoM6N<$f}TgY A-T(jq literal 0 HcmV?d00001 diff --git a/HX_CameraLoopPlay/SingleCameraWidget.cpp b/HX_CameraLoopPlay/SingleCameraWidget.cpp new file mode 100644 index 0000000..a1fb36d --- /dev/null +++ b/HX_CameraLoopPlay/SingleCameraWidget.cpp @@ -0,0 +1,12 @@ +#include "SingleCameraWidget.h" + +SingleCameraWidget::SingleCameraWidget(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +SingleCameraWidget::~SingleCameraWidget() +{ + +} diff --git a/HX_CameraLoopPlay/SingleCameraWidget.h b/HX_CameraLoopPlay/SingleCameraWidget.h new file mode 100644 index 0000000..3db78e6 --- /dev/null +++ b/HX_CameraLoopPlay/SingleCameraWidget.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "ui_SingleCameraWidget.h" + +class SingleCameraWidget : public QWidget +{ + Q_OBJECT + +public: + SingleCameraWidget(QWidget *parent = nullptr); + ~SingleCameraWidget(); + +private: + Ui::SingleCameraWidget ui; +}; diff --git a/HX_CameraLoopPlay/SingleCameraWidget.ui b/HX_CameraLoopPlay/SingleCameraWidget.ui new file mode 100644 index 0000000..22470b5 --- /dev/null +++ b/HX_CameraLoopPlay/SingleCameraWidget.ui @@ -0,0 +1,124 @@ + + + SingleCameraWidget + + + + 0 + 0 + 585 + 393 + + + + SingleCameraWidget + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + #widget_camera{ + border-image: url(:/CameraLoopPlay/Resource/image/rect.png); +} + + + + + 0 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + color: rgb(255, 255, 255); + + + + + + + + + + QLabel{ + font:75 25px; + color:#F0F0F0; + border:2px solid #AAAAAA; + background:transparent; +} +QLabel:focus{ + border:2px solid #00BB9E; + background:transparent; +} + + + + + + + + + + + + + + + + + + VideoWindowsComponent + QWidget +
component/videowindowscomponent.h
+ 1 +
+
+ + +
diff --git a/HX_CameraLoopPlay/cameradeviceinfo.h b/HX_CameraLoopPlay/cameradeviceinfo.h new file mode 100644 index 0000000..1746b42 --- /dev/null +++ b/HX_CameraLoopPlay/cameradeviceinfo.h @@ -0,0 +1,46 @@ +#ifndef CAMERADEVICEINFO_H +#define CAMERADEVICEINFO_H +#include + +class CameraDeviceInfo { +public: + // 构造函数 + CameraDeviceInfo(const int& index = 0, + const QString& name = "", + const QString& ip = "", + const QString& username = "", + const QString& password = "") + : index(index) + , name(name) + , ip(ip) + , username(username) + , password(password) + { + } + + int getIndex() const { return index; } + void setIndex(const int& newIndex) { index = newIndex; } + + // Getters 和 Setters + QString getName() const { return name; } + void setName(const QString& newName) { name = newName; } + + QString getIp() const { return ip; } + void setIp(const QString& newIp) { ip = newIp; } + + QString getUsername() const { return username; } + void setUsername(const QString& newUsername) { username = newUsername; } + + QString getPassword() const { return password; } + void setPassword(const QString& newPassword) { password = newPassword; } + +private: + // 设备信息 + int index{ 0 }; // 索引值 + QString name { "" }; // 设备名称 + QString ip { "" }; // 设备IP地址 + QString username { "" }; // 设备用户名 + QString password { "" }; // 设备密码 +}; + +#endif // CAMERADEVICEINFO_H diff --git a/HX_CameraLoopPlay/component/videowindowscomponent.cpp b/HX_CameraLoopPlay/component/videowindowscomponent.cpp new file mode 100644 index 0000000..0caacfc --- /dev/null +++ b/HX_CameraLoopPlay/component/videowindowscomponent.cpp @@ -0,0 +1,40 @@ +#include "videowindowscomponent.h" +#include "QHBoxLayout" +#include "QtDebug" + +VideoWindowsComponent::VideoWindowsComponent(QWidget* parent) + : QWidget(parent) +{ + standNumberWidget = new QLabel(m_cameraName, this); + standNumberWidget->setStyleSheet("background-color: rgba(173, 216, 230, 150); padding: 2px; color: white;"); + standNumberWidget->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + // 设置 QLabel 默认位置和大小 + standNumberWidget->move(7, 7); // 设置支架号 label 的初始位置(比如视频窗口左上角) + standNumberWidget->hide(); // 默认隐藏 +} + +void VideoWindowsComponent::setCameraName(const QString& cameraName) +{ + m_cameraName = cameraName; +} + +void VideoWindowsComponent::setCameraWidgetWidth(const double& cameraWidgetWidth) +{ + m_cameraWidgetWidget = cameraWidgetWidth; +} + +void VideoWindowsComponent::enterEvent(QEvent* event) +{ + standNumberWidget->show(); + standNumberWidget->setText(m_cameraName); + // standNumberWidget->setFixedSize(this->width() - 20, 25); // 设置固定的大小 + standNumberWidget->resize(this->width() - 14, 25); + standNumberWidget->raise(); + QWidget::enterEvent(event); // 调用基类的enterEvent方法 +} + +void VideoWindowsComponent::leaveEvent(QEvent* event) +{ + standNumberWidget->hide(); + QWidget::leaveEvent(event); // 调用基类的leaveEvent方法 +} diff --git a/HX_CameraLoopPlay/component/videowindowscomponent.h b/HX_CameraLoopPlay/component/videowindowscomponent.h new file mode 100644 index 0000000..1d98819 --- /dev/null +++ b/HX_CameraLoopPlay/component/videowindowscomponent.h @@ -0,0 +1,29 @@ +#ifndef VIDEOWINDOWSCOMPONENT_H +#define VIDEOWINDOWSCOMPONENT_H + +#include +#include +#include +#include + +class VideoWindowsComponent : public QWidget { + Q_OBJECT +public: + VideoWindowsComponent(QWidget* parent = nullptr); + + void setCameraName(const QString& cameraName); + + void setCameraWidgetWidth(const double& cameraWidgetWidth); + +protected: + void enterEvent(QEvent* event) override; + void leaveEvent(QEvent* event) override; + +private: + QLabel* standNumberWidget; + + QString m_cameraName; + double m_cameraWidgetWidget; +}; + +#endif // VIDEOWINDOWSCOMPONENT_H diff --git a/HX_CameraLoopPlay/model/CameraDeviceInfo.h b/HX_CameraLoopPlay/model/CameraDeviceInfo.h new file mode 100644 index 0000000..e8ffceb --- /dev/null +++ b/HX_CameraLoopPlay/model/CameraDeviceInfo.h @@ -0,0 +1,46 @@ +#ifndef CAMERADEVICEINFO_H +#define CAMERADEVICEINFO_H +#include + +class CameraDeviceInfo { +public: + // 构造函数 + CameraDeviceInfo(const int& treeIndex = 0, + const QString& name = "", + const QString& ip = "", + const QString& username = "", + const QString& password = "") + : treeindex(treeIndex) + , name(name) + , ip(ip) + , username(username) + , password(password) + { + } + + int getTreeindex() const { return treeindex; } + void setTreeIndex(const int& newTreeIndex) { treeindex = newTreeIndex; } + + // Getters 和 Setters + QString getName() const { return name; } + void setName(const QString& newName) { name = newName; } + + QString getIp() const { return ip; } + void setIp(const QString& newIp) { ip = newIp; } + + QString getUsername() const { return username; } + void setUsername(const QString& newUsername) { username = newUsername; } + + QString getPassword() const { return password; } + void setPassword(const QString& newPassword) { password = newPassword; } + +private: + // 设备信息 + int treeindex{ 0 }; // 索引值 + QString name{ "" }; // 设备名称 + QString ip{ "" }; // 设备IP地址 + QString username{ "" }; // 设备用户名 + QString password{ "" }; // 设备密码 +}; + +#endif // CAMERADEVICEINFO_H