One, foreword

A system must have a lot of configuration parameters stored in the configuration file, the configuration file can be INI file, can also be A JSON file, can also be a custom format of text file, I recommend INI file, read and write node is extremely convenient, support Chinese content, a variety of Qt built-in data types can be stored, It even includes QByteArray. For example, the layout file can be stored directly in the configuration file, which is a bunch of characters that can’t be read. If you choose to store it in a JSON file, humans can’t read it directly.

Along with the increase in function, the corresponding configuration file node parameters more and more, the monitoring system, too, remember when the first version is around ten parameters (title, boot operation, interface style, etc.), now light basic setup this part of the switch there ten, so constantly in the process of iteration split deposit classification group configuration parameters, Convenient management also refer to understand code, such as the video parameters part separate out and put a special group, in the system Settings in the main interface, different groups for different QGroupBox, corresponding to the setting of each parameter in the group box, the switch can be used to switch button to indicate, the other can be a text box and a drop-down box.

I like configuration parameters have a class to read and write alone, at the same time to convert the value of the configuration parameters to the corresponding global variables, it’s very comfortable to use, most of the parameters actually need to use more than one place, the efficiency is very high, the use of global variables in a mapping configuration parameters, the system configuration parameters in ini file, cross-platform, all parameters corresponding to a variable, Assign a value to a variable when reading a configuration parameter, and write the variable value to the configuration file when writing. In order to apply the parameter changes immediately (very few need to automatically restart the application, such as the change of working mode), it is necessary to send the corresponding signal when the parameter changes and automatically change the place where the signal is received.

Basic Parameters

  1. Startup: After startup, it automatically starts with the system. It is enabled by default.
  2. Automatic login: After this function is enabled, the system automatically logs in to the system with the information of the last user. This function is disabled by default.
  3. Remember password: After this function is enabled, it will automatically fill in the last login user information to the login form.
  4. Chinese title: Chinese title in the upper left title bar of the software. Changes are applied immediately.
  5. English title: English title in the upper left title bar of the software. Changes are applied immediately.
  6. Copyright: Current software copyrighted by company, currently not shown where, standby.
  7. Full screen mode: After this function is enabled, the maximum display mode automatically displays full screen instead of maximum display. This function is disabled by default.
  8. Full screen adaptation: When enabled, it automatically moves up one pixel to resolve opengL bugs.
  9. Software icon: The software icon is automatically read from the LOGO folder and you can select the corresponding logo file.
  10. Interface style: the system comes with 17 sets of skin, you can automatically skin here, the default video black.
  11. Working mode: default video monitoring, robot monitoring, uav monitoring and so on are optional.
  12. Navigation style: Used to select the style of the top and left navigation bars. Top + left means the top style of the top navigation bar (ICONS on the top and text on the bottom), and left style of the left navigation bar (ICONS on the left and text on the right).
  13. Pop-up time: Indicates the time when a message is displayed at the lower right corner. 0 seconds indicates that the resident function is not disabled.
  14. Alarm sound: 0 indicates that the alarm is not enabled, and the rest indicates the number of sounds played after the alarm.
  15. Hide mouse: The mouse pointer will be automatically hidden when the main interface is not operated. Generally, it needs to be set when the full screen polling, the effect will be better.
  16. Auto full screen: Indicates how long has elapsed since the mouse has not operated auto full screen. 0 indicates that auto full screen is disabled.
  17. Spare switch: reserved for later use.
  18. Graphic alert: the number of lines in the graphic alert module. 0 means the automatic calculation is filled, and no scroll bar is generated.
  19. Window message: the number of message lines in the window message module. 0 indicates that it is automatically filled and no scroll bar is generated.
  20. Transparency value: Transparency value of docked form, adjustable, dynamic application.

Two, functions and features

(1) Software module

  1. Video surveillance module, various docking small form submodules, including equipment list, graphic alarm, window information, PTC control, preset position, cruise setting, equipment control, suspension map, web browsing, etc.
  2. Video playback module, including local playback, remote playback, device playback, picture playback, and video upload.
  3. Electronic map module, including picture map, online map, offline map, path planning and so on.
  4. Log query module, including local logs and device logs.
  5. System setting module, including system Settings (basic Settings, video parameters, database Settings, map configuration, serial port configuration, etc.), VCR management, camera management, polling configuration, user management, etc.

(2) Basic functions

  1. Support all kinds of video streams (RTSP, RTMP, HTTP, etc.), video files (MP4, RMVB, AVI, etc.), local USB camera playback.
  2. Supports multi-screen switching, including 1, 4, 6, 8, 9, 13, 16, 25, 36, 64 screen switching.
  3. Supports full-screen switching, including the right mouse button menu, toolbar buttons, and shortcut keys (Alt + Enter full-screen, esc exit full-screen).
  4. Supports video polling, including 1, 4, 9, and 16 screen polling. You can set polling groups (polling plan), polling interval, and bit stream types.
  5. Supports the ONVIF protocol, including device search, PTZ control, and device control (picture parameters, check time, system restart, and picture capture).
  6. Supports permission management. Different users have different permissions for modules, such as deleting logs and shutting down the system.
  7. Multiple databases are supported, including SQLite, mysql, SQLServer, PostgresQL, Oracle, and CNPC.
  8. You can set parameters such as resolution and frame rate for a local USB camera.
  9. All the docked modules automatically generate the corresponding menu to control the display and hide, right-click the title bar can be popup.
  10. You can display or hide all modules, reset the normal layout, or reset the full-screen layout.
  11. Double-click the device to display real-time preview videos, including picture maps, online maps, and offline maps.
  12. Drag the camera node to the corresponding form to play the video. You can also drag the local file to play the video directly.
  13. You can delete a video from the right mouse button, close the hover bar, or drag it outside the video monitoring panel.
  14. The device button on the picture map can be dragged freely to automatically save the location information. On the Baidu map, you can click to obtain the latitude and longitude information to update the device location.
  15. Any channel in the form of the video monitoring panel supports drag exchange and instant response.
  16. Encapsulating Baidu map, view switching, motion trajectory, device point, click the mouse to obtain latitude and longitude.
  17. Double click the node, drag the node, drag the form to change the position and other operations, are automatically updated and saved the last play address, the next software open automatic application.
  18. Lower right volume bar control, automatically hidden when losing focus, volume band mute icon.
  19. Support video capture, you can specify a single or all channel capture, the bottom toolbar also has a screenshot button.
  20. Supports automatic hiding of the mouse pointer and automatic full screen after timeout.
  21. Support onVIF PTZ control, can move PTZ camera up, down, left and right, including reset and focus adjustment.
  22. Support any ONVIF camera, including but not limited to Hikon, Dahua, Yusee, Tiandi weiye, Huawei, etc.
  23. Can save the video, can select the storage or single file storage, optional storage interval.
  24. The video stream communication mode can be set to TCP + UDP, and the video decoding mode can be set to speed first, quality first, balance, etc.
  25. You can set the software name in Chinese, English, and LOGO.
  26. The stored video files can be exported to a specified directory and uploaded to the server in batches.

(3) Features

  1. The main interface adopts the mode of docked form, and various components are added in the form of small modules, and any modules can be customized.
  2. The docking module can be dragged to any position to embed and hover, support maximum full screen, support multi-screen.
  3. Dual layout file storage mechanism, normal mode, full screen mode correspond to different layout scheme, automatic switching and saving, such as the full screen mode can highlight several modules transparent display in the specified position, more science fiction sense of modernization.
  4. The original ONVIF protocol mechanism, using the underlying protocol parsing (UDP broadcast search + HTTP request execution command) is more lightweight, easy to learn and expand, do not rely on any third-party components such as GSOAP.
  5. Original data import and export mechanism, cross-platform does not depend on any components, instantaneous data export.
  6. Built-in multiple original components, the universe value is super awesome, It includes data import and export components (export to XLS, PDF, print), database components (database management thread, automatic data cleaning thread, universal paging, data request, etc.), map components, video monitoring components, file multi-threaded transceiver components, ONVIF communication components, general browser kernel components, etc.
  7. Custom information box, error box, query box, and message box (in various formats) in the lower right corner.
  8. Exquisite skin peels, up to 17 sets of skin styles can be changed at will, all styles are unified, including menu, etc.
  9. Multiple buttons can be added to the video control hover bar, and buttons can also be added to the small toolbar at the bottom of the monitoring interface.
  10. Double click the camera node to automatically play the video, double click the node to automatically add the video, will automatically jump to the next, double click the parent node to automatically add all the videos under this node. Primary stream and substream are optional.
  11. VCR management and camera management: You can add, delete, modify, import or export printed information. The new device information is immediately applied to generate a tree list without restarting the system.
  12. Optional a variety of kernel free switching, FFMPEG, VLC, MPV, etc., can be set in pro. It is recommended to use FFMPEG, the most cross-platform, default to provide a good Linux and MAC platform compiled library.
  13. Support hard decoding, can set the hard decoding type (QSV, DXVA2, D3D11VA, etc.).
  14. Opengl rendering video by default, ultra low CPU resource occupation, support yuYV and NV12 two formats, very cow force.
  15. Highly customizable, users can easily derive their own functions on this basis, such as adding custom modules, operating modes, robot monitoring, uav monitoring, excavator monitoring, etc.
  16. Support XP, Win7, Win10, Linux, MAC, a variety of domestic systems (UOS, Kirin, Galaxy, etc.), embedded Linux and other systems.
  17. Complete comments, clear project structure, super detailed complete use of the development manual, down to the function of each code file, continuous iterations.

Three, experience address

  1. Experience address: pan.baidu.com/s/1d7TH_GEY… Extract code: 01JF File name: bin_video_system.zip.
  2. Domestic website: gitee.com/feiyangqing…
  3. International site: github.com/feiyangqing…
  4. Profile: blog.csdn.net/feiyangqing…
  5. Zhihu homepage: www.zhihu.com/people/feiy…
  6. Online documentation: feiyangqingyun. Gitee. IO/qwidgetdemo…

Four, the effect diagram

5. Core code

void frmConfigSystem::initAppConfig1(a)
{
    QStringList styleNames, styleFiles;
    QUIStyle::getStyle(styleNames, styleFiles);
    for (int i = 0; i < styleNames.count(a); i++) { ui->cboxStyleName->addItem(styleNames.at(i), styleFiles.at(i));
    }

    ui->cboxStyleName->setCurrentIndex(ui->cboxStyleName->findData(AppConfig::StyleName));
    connect(ui->cboxStyleName, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig1()));

    ui->txtCopyright->setText(AppConfig::Copyright);
    connect(ui->txtCopyright, SIGNAL(textChanged(QString)), this.SLOT(saveAppConfig1()));

    ui->txtTitleCn->setText(AppConfig::TitleCn);
    connect(ui->txtTitleCn, SIGNAL(textChanged(QString)), this.SLOT(saveAppConfig1()));

    ui->txtTitleEn->setText(AppConfig::TitleEn);
    connect(ui->txtTitleEn, SIGNAL(textChanged(QString)), this.SLOT(saveAppConfig1()));

    // Move the Settings to the far left, otherwise the text will default to the right
    ui->txtCopyright->setCursorPosition(0);
    ui->txtTitleCn->setCursorPosition(0);
    ui->txtTitleEn->setCursorPosition(0);

    // Load all images from the logo directory
    QDir dir(QUIHelper::appPath() + "/logo");
    QStringList fileNames = dir.entryList(QStringList() < <"*.png");
    foreach (QString fileName, fileNames) {
        ui->cboxLogoImage->addItem(fileName.split(".").first());
    }
    // Add an empty configuration file to prevent the configuration file from being reset if there are none
    if (fileNames.count() = =0) {
        ui->cboxLogoImage->addItem(AppConfig::LogoImage);
    }

    ui->cboxLogoImage->setCurrentIndex(ui->cboxLogoImage->findText(AppConfig::LogoImage));
    connect(ui->cboxLogoImage, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig1()));
}

void frmConfigSystem::saveAppConfig1(a)
{
    int styleIndex = ui->cboxStyleName->currentIndex(a); QString styleName = ui->cboxStyleName->itemData(styleIndex).toString(a);if(AppConfig::StyleName ! = styleName) { AppConfig::StyleName = styleName; AppStyle::initStyle(a); AppEvent::Instance() - >slot_changeStyle(a); } QString company = ui->txtCopyright->text().trimmed(a);if(AppConfig::Copyright ! = company) { AppConfig::Copyright = company; AppEvent::Instance() - >slot_changeTitleInfo(a); } QString titleCn = ui->txtTitleCn->text().trimmed(a);if(AppConfig::TitleCn ! = titleCn) { AppConfig::TitleCn = titleCn; AppEvent::Instance() - >slot_changeTitleInfo(a); } QString titleEn = ui->txtTitleEn->text().trimmed(a);if(AppConfig::TitleEn ! = titleEn) { AppConfig::TitleEn = titleEn; AppEvent::Instance() - >slot_changeTitleInfo(a); } QString logoImage = ui->cboxLogoImage->currentText().trimmed(a);if(AppConfig::LogoImage ! = logoImage) { AppConfig::LogoImage = logoImage; AppEvent::Instance() - >slot_changeLogo(a); } AppConfig::writeConfig(a); }void frmConfigSystem::initAppConfig2(a)
{
    QStringList listWorkMode;
    listWorkMode << "Video surveillance" << "Robot surveillance" << "Drone surveillance.";
    ui->cboxWorkMode->addItems(listWorkMode);
    ui->cboxWorkMode->setCurrentIndex(AppConfig::WorkMode);
    connect(ui->cboxWorkMode, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));
    //ui->cboxWorkMode->setEnabled(AppConfig::WorkMode ! = 1);

    QStringList listNavStyle;
    listNavStyle << "Left + left" << "Left side + upper side" << Upper side + left side << "Upper + upper";
    ui->cboxNavStyle->addItems(listNavStyle);
    ui->cboxNavStyle->setCurrentIndex(AppConfig::NavStyle);
    connect(ui->cboxNavStyle, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));

    QStringList listTime;
    listTime << "0 seconds" << "For 10 seconds" << "For 20 seconds" << "30 seconds" << "60 seconds" << "120 seconds";

    ui->cboxTimeHideCursor->addItems(listTime);
    QString timeHideCursor = QString("% 1 seconds").arg(AppConfig::TimeHideCursor);
    ui->cboxTimeHideCursor->setCurrentIndex(ui->cboxTimeHideCursor->findText(timeHideCursor));
    connect(ui->cboxTimeHideCursor, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));

    ui->cboxTimeAutoFull->addItems(listTime);
    QString timeAutoFull = QString("% 1 seconds").arg(AppConfig::TimeAutoFull);
    ui->cboxTimeAutoFull->setCurrentIndex(ui->cboxTimeAutoFull->findText(timeAutoFull));
    connect(ui->cboxTimeAutoFull, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));

    QStringList listCount;
    listCount << "Zero" << "1" << "Three times" << "Five" << "Ten times" << "20 times" << "50" << "100";

    ui->cboxAlarmSoundCount->addItems(listCount);
    QString alarmSoundCount = QString("%1次").arg(AppConfig::AlarmSoundCount);
    ui->cboxAlarmSoundCount->setCurrentIndex(ui->cboxAlarmSoundCount->findText(alarmSoundCount));
    connect(ui->cboxAlarmSoundCount, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));

    QStringList msgCount;
    msgCount << "Zero" << "1 line" << "Three lines" << "5 lines" << "10 lines" << "15 lines" << "20 lines" << "25 lines" << "30 lines" << "50 lines";

    ui->cboxMsgListCount->addItems(msgCount);
    QString msgListCount = QString(Line "% 1").arg(AppConfig::MsgListCount);
    ui->cboxMsgListCount->setCurrentIndex(ui->cboxMsgListCount->findText(msgListCount));
    connect(ui->cboxMsgListCount, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));

    ui->cboxMsgTableCount->addItems(msgCount);
    QString msgTableCount = QString(Line "% 1").arg(AppConfig::MsgTableCount);
    ui->cboxMsgTableCount->setCurrentIndex(ui->cboxMsgTableCount->findText(msgTableCount));
    connect(ui->cboxMsgTableCount, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));

    ui->labWindowOpacityValue->setText(QString::number(AppConfig::WindowOpacity));
    ui->sliderWindowOpacity->setValue(AppConfig::WindowOpacity);
    ui->sliderWindowOpacity->setRange(10.100);
    connect(ui->sliderWindowOpacity, SIGNAL(valueChanged(int)), this.SLOT(saveAppConfig2()));

    QStringList listTipInterval;
    listTipInterval << "0 seconds" << "3 seconds" << "5 seconds" << "For 10 seconds" << "For 20 seconds" << "30 seconds" << "60 seconds" << "120 s" << "10000 seconds";
    ui->cboxTipInterval->addItems(listTipInterval);
    QString tipInterval = QString("% 1 seconds").arg(AppConfig::TipInterval);
    ui->cboxTipInterval->setCurrentIndex(ui->cboxTipInterval->findText(tipInterval));
    connect(ui->cboxTipInterval, SIGNAL(currentIndexChanged(int)), this.SLOT(saveAppConfig2()));
}

void frmConfigSystem::saveAppConfig2(a)
{
    int workMode = ui->cboxWorkMode->currentIndex(a);if(AppConfig::WorkMode ! = workMode) {// Let me know I'm ready to quit by sending an exit signal
        AppEvent::Instance() - >slot_exitAll(a); AppConfig::WorkMode = workMode; AppConfig::writeConfig(a); AppFun::reboot(a); }int navStyle = ui->cboxNavStyle->currentIndex(a);if(AppConfig::NavStyle ! = navStyle) {// Let me know I'm ready to quit by sending an exit signal
        AppEvent::Instance() - >slot_exitAll(a); AppConfig::NavStyle = navStyle; AppConfig::writeConfig(a); AppFun::reboot(a); } QString timeHideCursor = ui->cboxTimeHideCursor->currentText(a); AppConfig::TimeHideCursor = timeHideCursor.mid(0, timeHideCursor.length() - 2).toInt(a); QString timeAutoFull = ui->cboxTimeAutoFull->currentText(a); AppConfig::TimeAutoFull = timeAutoFull.mid(0, timeAutoFull.length() - 2).toInt(a); QString alarmSoundCount = ui->cboxAlarmSoundCount->currentText(a); AppConfig::AlarmSoundCount = alarmSoundCount.mid(0, alarmSoundCount.length() - 1).toInt(a); QString msgListCount = ui->cboxMsgListCount->currentText(a); AppConfig::MsgListCount = msgListCount.mid(0, msgListCount.length() - 1).toInt(a); QString msgTableCount = ui->cboxMsgTableCount->currentText(a); AppConfig::MsgTableCount = msgTableCount.mid(0, msgTableCount.length() - 1).toInt(a);int windowOpacity = ui->sliderWindowOpacity->value(a);if(AppConfig::WindowOpacity ! = windowOpacity) { AppConfig::WindowOpacity = windowOpacity; ui->labWindowOpacityValue->setText(QString::number(AppConfig::WindowOpacity));
        AppEvent::Instance() - >slot_changeWindowOpacity(a); } QString tipInterval = ui->cboxTipInterval->currentText(a); AppConfig::TipInterval = tipInterval.mid(0, tipInterval.length() - 2).toInt(a); AppConfig::writeConfig(a); }Copy the code