One, foreword

Equipment to play behind module is increased, the core is through the combination of RTSP streaming video address to broadcast live video and video history, currently on the market many manufacturers such as first sea kang are support RTSP directly through the NVR to play a channel video streaming and playback a channel video streams, these formats can be searched on the net, Each manufacturer first might be a little different, but generally the information, such as real-time video streaming to play, need to provide the information user name, password, NVR address, the corresponding channel and stream type (main stream/child stream), video playback video, if you want to play history need to provide the information besides the above time range, It is necessary to limit a time range to get the corresponding video stream file. Some manufacturers calculate the time stamp in 1970 in seconds, some in time, etc., which need to be in accordance with the format convention of the specific manufacturer.

The principle process of device playback is that manufacturers repackage the video stream files or stored video files and send them out. Some manufacturers use their own algorithms, and some use live555 and the like. Generally speaking, I may refer to some open source push stream libraries more or less. I have consulted many friends in the same industry and basically refer to ffMPEG, Live555 and other open source libraries. In fact, FFMPEG supports many domestic manufacturers, even some large ones. Especially for AI enterprises, there is a saying in the industry: If Github is not allowed to access, the level of AI in China will be set back five years.

Two, functional characteristics

Software modules

  1. Video monitoring module, various docking small window sub-module, including device list, graphic warning, window information, panyt control, preset position, cruise setting, device control, floating map, web browsing, etc.
  2. Video playback module, including local playback, remote playback, device playback, picture playback, video upload, etc.
  3. Electronic map module, including picture map, online map, offline map, path planning, etc.
  4. Log query module, including local logs, device logs, etc.
  5. System setting module, including system Settings (basic Settings, video parameters, database Settings, map configuration, serial port configuration, etc.), VIDEO recorder management, camera management, polling configuration, user management, etc.

Basis function

  1. Support various video streams (RTSP, RTMP, HTTP, etc.), video files (MP4, RMVB, AVI, etc.), local USB camera playback.
  2. Support 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, toolbar button, 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 group (polling plan), polling interval, and bit stream type.
  5. Supports the OnVIF protocol, including device search, pte control, device control (picture parameters, check time, system restart, capture pictures, etc.).
  6. Different users can have different module permissions, such as deleting logs and shutting down the system.
  7. Support a variety of databases, including sqlite, mysql, sqlserver, postgresql, oracle, rendajincang and so on.
  8. You can set resolution and frame rate for a local USB camera.
  9. All docking modules automatically generate corresponding menus to control the display and hide, in the title bar right click can pop up.
  10. Display all modules, hide all modules, reset the common layout, and reset the full-screen layout.
  11. Double-click the device to pop up real-time preview video, supporting picture map, online map, offline map, etc.
  12. The camera node can be dragged to the corresponding window to play the video, and the local file can be dragged to play the video.
  13. You can delete a video by right-clicking the mouse button, closing the floating bar, or dragging it outside the video surveillance panel.
  14. The device button on the picture map can be dragged freely to automatically save the location information. You can click the mouse to obtain the longitude and latitude information on the Baidu map to update the location of the device.
  15. Any channel in the video surveillance panel form supports drag exchange, instant response.
  16. Encapsulated Baidu map, view switch, movement track, equipment point, mouse click to obtain latitude and longitude.
  17. Double-click the node, drag the node, drag the window to switch positions and other operations, will automatically update and save the last playing address, the next software open automatic application.
  18. Volume bar control in the lower right corner, automatically hide when losing focus, volume strip mute icon.
  19. You can specify a screenshot for a single channel or all channels. The screenshot button is also available on the bottom toolbar.
  20. The mouse pointer can be automatically hidden when timeout expires and the mouse pointer can be automatically displayed in full screen.
  21. Support onVIF PTZ control, can move PTZ camera up, down, left and right, including reset and focal length adjustment.
  22. Support any ONVIF camera, including but not limited to Hikang, Dahua, Yushi, Weiye, Huawei, etc.
  23. Can save video, can select the time storage or single file storage, optional storage interval time.
  24. Video stream communication mode can be set TCP + UDP, video decoding can be set speed first, quality first, balance, etc.
  25. You can set the software name, English name, and LOGO icon.
  26. You can export stored video files to specific directories or upload them to servers in batches.

features

  1. The main interface adopts the mode of docked form, various components in the form of small modules, can be customized to join any module.
  2. Docking module can drag any position embedded and suspended, support maximum full screen, support multi-screen.
  3. Dual layout file storage mechanism, normal mode and full-screen mode are corresponding to different layout schemes, automatic switching and saving, for example, full-screen mode can highlight several modules transparent display in the specified position, more science fiction sense of modernization.
  4. Original onVIF protocol mechanism, using the underlying protocol resolution (UDP broadcast search + HTTP request execution command) more lightweight easy to understand learning expansion, does not rely on any third-party components such as GSOAP.
  5. Original data import and export mechanism, cross-platform independent of any components, instant data export.
  6. Built in multiple original components, the universe super value super awesome, Including data import and export components (export to XLS, PDF, printing), database components (database management thread, automatic data cleaning thread, universal paging, data request, etc.), map component, video monitoring component, file multithreading transceiver component, onVIF communication component, universal browser kernel component, etc.
  7. Customize information box + error box + query box + lower right prompt box (including various formats).
  8. Exquisite skin change, 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, it will automatically jump to the next, double click the parent node to automatically add all the videos under the node. Primary stream and sub-stream are optional.
  11. You can add, delete, and modify the import and export printed information, and immediately apply the new device information to generate a tree list without restarting.
  12. Optional a variety of kernel free switch, FFMPEG, VLC, MPV, etc., can be set in pro. Ffmpeg is recommended. It is most cross-platform and provides libraries compiled on Linux and MAC platforms by default.
  13. Supports hard decoding and can be set to hard decoding type (QSV, DXVA2, d3D11VA, etc.).
  14. The default opengL rendering video, ultra-low CPU resource consumption, support YUYV and NV12 two formats to draw, very awesome.
  15. Highly customizable, users can easily derive their own functions on this basis, such as adding custom modules, operation mode, robot monitoring, UAV monitoring, excavator monitoring, procuratorate trial monitoring, etc.
  16. Support XP, Win7, Win10, Linux, MAC, a variety of domestic systems (UOS, kyrin, Galaxy Kyrin, etc.), embedded Linux and other systems.
  17. Complete annotation, clear project structure, super detailed complete use of the development manual, accurate to the function description of each code file, continuous iteration version.

3. Experience address

  1. Experience address: pan.baidu.com/s/1d7TH_GEY… Extraction code: 01Jf File name: bin_video_system.zip
  2. Domestic site: gitee.com/feiyangqing…
  3. International site: github.com/feiyangqing…
  4. Profile: blog.csdn.net/feiyangqing…
  5. Zhihu homepage: www.zhihu.com/people/feiy…

Four, effect drawing

Five, core code

#include "frmvideoplaynvr.h"
#include "ui_frmvideoplaynvr.h"
#include "quiwidget.h"
#include "iconfont.h"
#include "videowidget.h"

#ifdef videovlc
#include "vlc.h"
#elif videoffmpeg
#include "ffmpeg.h"
#elif easyplayer
#include "easyplayer.h"
#endif

frmVideoPlayNvr::frmVideoPlayNvr(QWidget *parent) : QWidget(parent), ui(new Ui::frmVideoPlayNvr)
{
    ui->setupUi(this);
    this->initForm(a);this->initIcon(a);this->initAddr(a);this->initVideo(a); } frmVideoPlayNvr::~frmVideoPlayNvr()
{
    delete ui;
}

bool frmVideoPlayNvr::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress) {
        if (watched->inherits("QWidget")) {
            QWidget *widget = (QWidget *) watched;
            videoIndex = widget->property("index").toInt(a); ui->labTip->setText(QString("Currently selected %1").arg(widgets.at(videoIndex)->getBgText())); }}else if (event->type() == QEvent::MouseButtonDblClick) {
        if (watched->inherits("QWidget")) {
            QWidget *widget = (QWidget *) watched;
            if(! videoMax) {for (int i = 0; i < videoCount; i++) {
                    widgets.at(i)->setVisible(false);
                }

                videoMax = true;
                widget->setVisible(true);
            } else {
                for (int i = 0; i < videoCount; i++) {
                    widgets.at(i)->setVisible(true);
                }

                videoMax = false;
            }

            widget->setFocus();
        }
    }

    return QWidget::eventFilter(watched, event);
}

void frmVideoPlayNvr::initForm(a)
{
    ui->cboxCompany->addItems(DBData::NvrTypes);
    ui->cboxCompany->setCurrentIndex(ui->cboxCompany->findText("深广"));

    ui->cboxType->addItem("Live video");
    ui->cboxType->addItem("Playback video");

    for (int i = 1; i <= 16; i++) {
        ui->cboxCh->addItem(QString(Channel "% 1").arg(i));
    }

    ui->cboxRtsp->addItem("Main stream");
    ui->cboxRtsp->addItem("Substream");

    ui->dateTimeStart->calendarWidget() - >setLocale(QLocale::Chinese);
    ui->dateTimeEnd->calendarWidget() - >setLocale(QLocale::Chinese);
    ui->dateTimeStart->setDate(QDate::currentDate().addDays(- 1));
    ui->dateTimeEnd->setDate(QDate::currentDate());

    // Bind changes to automatically fill in the video stream address
    connect(ui->cboxCompany, SIGNAL(currentIndexChanged(int)), this.SLOT(initAddr()));
    connect(ui->cboxType, SIGNAL(currentIndexChanged(int)), this.SLOT(initAddr()));
    connect(ui->txtName, SIGNAL(textChanged(QString)), this.SLOT(initAddr()));
    connect(ui->txtPwd, SIGNAL(textChanged(QString)), this.SLOT(initAddr()));
    connect(ui->txtIP, SIGNAL(textChanged(QString)), this.SLOT(initAddr()));
    connect(ui->cboxCh, SIGNAL(currentIndexChanged(int)), this.SLOT(initAddr()));
    connect(ui->cboxRtsp, SIGNAL(currentIndexChanged(int)), this.SLOT(initAddr()));
    connect(ui->dateTimeStart, SIGNAL(dateTimeChanged(QDateTime)), this.SLOT(initAddr()));
    connect(ui->dateTimeEnd, SIGNAL(dateTimeChanged(QDateTime)), this.SLOT(initAddr()));
}

void frmVideoPlayNvr::initIcon(a)
{
    quint32 size = 15;
    quint32 pixWidth = 20;
    quint32 pixHeight = 15;
    QSize iconSize = QSize(pixWidth, pixHeight);

    QPixmap pix1 = IconHelper::Instance() - >getPixmap(QUIConfig::TextColor, 0xf04b, size, pixWidth, pixHeight);
    QPixmap pix2 = IconHelper::Instance() - >getPixmap(QUIConfig::TextColor, 0xf00d, size, pixWidth, pixHeight);
    QPixmap pix3 = IconHelper::Instance() - >getPixmap(QUIConfig::TextColor, 0xf04d, size, pixWidth, pixHeight);
    QPixmap pix4 = IconHelper::Instance() - >getPixmap(QUIConfig::TextColor, 0xf061, size, pixWidth, pixHeight);

    ui->btnPlay->setIconSize(iconSize);
    ui->btnDelete->setIconSize(iconSize);
    ui->btnPause->setIconSize(iconSize);
    ui->btnNext->setIconSize(iconSize);

    ui->btnPlay->setIcon(QIcon(pix1));
    ui->btnDelete->setIcon(QIcon(pix2));
    ui->btnPause->setIcon(QIcon(pix3));
    ui->btnNext->setIcon(QIcon(pix4));
}

void frmVideoPlayNvr::initAddr(a)
{
    QString company = ui->cboxCompany->currentText(a); QString type = ui->cboxType->currentText(a); QString name = ui->txtName->text().trimmed(a); QString pwd = ui->txtPwd->text().trimmed(a); QString ip = ui->txtIP->text().trimmed(a);int ch = ui->cboxCh->currentIndex(a);int rtsp = ui->cboxRtsp->currentIndex(a); QString dateStart = ui->dateTimeStart->dateTime().toString("yyyy-MM-dd HH:mm:ss");
    QString dateEnd = ui->dateTimeEnd->dateTime().toString("yyyy-MM-dd HH:mm:ss");

    Vast NVR / /
    RTSP ://admin:[email protected]:554/live? channel=1&stream=1
    // Video playback format RTSP ://admin:[email protected]:554/file? channel=1&start=1494485280&stop=1494485480
    // Convert the timestamp to the number of seconds elapsed since 1970
    QDateTime startTime = QDateTime::fromString(dateStart, "yyyy-MM-dd HH:mm:ss");
    QDateTime stopTime = QDateTime::fromString(dateEnd, "yyyy-MM-dd HH:mm:ss");
    qint64 startTimeSec = startTime.toTime_t(a); qint64 stopTimeSec = stopTime.toTime_t(a);/ / hai kang NVR
    / / real-time preview format RTSP: / / admin: 12345 @192.168.1.128:554 / Streaming/Channels / 101? transportmode=unicast
    / / RTSP video playback format: / / admin: 12345 @192.168.1.128:554 / Streaming/seen / 101? starttime=20120802t063812z&endtime=20120802t064816z
    / / streaming media flow RTSP: / / 172.6.24.15:554 / Devicehc8: / / 172.6.22.106:8000:0-0 draw? username=admin&password=12345
    // Date and time format ISO 8601 indicates Zulu(GMT) time YYYYMMDD "T" HHmmSS.
    Unicast indicates unicast. Multicast indicates multicast. The default unicast can be omitted
    //101,1 is the channel number. 01 is the code stream number of the channel, or 02, 03
    QString starttime = ui->dateTimeStart->dateTime().toString(Qt::ISODate);
    QString endtime = ui->dateTimeEnd->dateTime().toString(Qt::ISODate);
    starttime = starttime.replace("-"."");
    starttime = starttime.replace(":"."");
    starttime = starttime.toLower(a); endtime = endtime.replace("-"."");
    endtime = endtime.replace(":"."");
    endtime = endtime.toLower(a); QString addr;if (company == "深广") {
        if (type == "Live video") {
            addr = QString("rtsp://%1:%2@%3:554/live? channel=%4&stream=%5").arg(name).arg(pwd).arg(ip).arg(ch + 1).arg(rtsp);
        } else if (type == "Playback video") {
            addr = QString("rtsp://%1:%2@%3:554/file? channel=%4&start=%5&stop=%6").arg(name).arg(pwd).arg(ip).arg(ch + 1).arg(startTimeSec).arg(stopTimeSec); }}else if (company == "Hai kang") {
        if (type == "Live video") {
            addr = QString("rtsp://%1:%2@%3:554/Streaming/Channels/%4%5%6").arg(name).arg(pwd).arg(ip).arg(ch + 1).arg(0).arg(rtsp + 1);
        } else if (type == "Playback video") {
            addr = QString("rtsp://%1:%2@%3:554/Streaming/tracks/%4%5? starttime=%6&endtime=%7").arg(name).arg(pwd).arg(ip).arg(ch + 1).arg("01").arg(starttime).arg(endtime); }}else if (company == "Dahua") {
        if (type == "Live video") {}else if (type == "Playback video") {

        }
    }

    ui->txtAddr->setText(addr);
}

void frmVideoPlayNvr::initVideo(a)
{
    videoMax = false;
    videoCount = 4;
    videoIndex = 0;

    for (int i = 0; i < videoCount; i++) {
#ifdef videovlc
        VlcWidget *widget = new VlcWidget;
        widget->setCallback(true);
        //widget->setHardware("auto");
#elif videoffmpeg
        FFmpegWidget *widget = new FFmpegWidget;
        //widget->setHardware("d3d11va");
#elif easyplayer
        EasyPlayerWidget *widget = new EasyPlayerWidget;
#else
        VideoWidget *widget = new VideoWidget;
#endif

        // Set the background text
        widget->setBgText(QString(Channel "% 1").arg(i + 1));
        // Set the background image
        widget->setBgImage(QImage(":/bg_novideo.png"));
        // Set the URL
        widget->setUrl("");
        // Make the hover bar visible
        widget->setFlowEnable(false);
        // Set whether to automatically reconnect
        widget->setCheckLive(false);

        widget->installEventFilter(this);
        widget->setProperty("index", i);
        widget->setObjectName(QString("video%1").arg(i + 1));
        widgets.append(widget);
    }

    // Add to the layout
    ui->gridLayout->addWidget(widgets.at(0), 0.0);
    ui->gridLayout->addWidget(widgets.at(1), 0.1);
    ui->gridLayout->addWidget(widgets.at(2), 1.0);
    ui->gridLayout->addWidget(widgets.at(3), 1.1);
}

void frmVideoPlayNvr::on_btnPlay_clicked(a)
{
    QString addr = ui->txtAddr->toPlainText(a);if (addr.isEmpty()) {
        return;
    }

    widgets.at(videoIndex)->setUrl(addr);
    widgets.at(videoIndex)->close(a); widgets.at(videoIndex)->open(a); widgets.at(videoIndex)->setFocus(a); }void frmVideoPlayNvr::on_btnDelete_clicked(a)
{
    widgets.at(videoIndex)->close(a); widgets.at(videoIndex)->setFocus(a); }void frmVideoPlayNvr::on_btnPause_clicked(a)
{
    widgets.at(videoIndex)->pause(a); widgets.at(videoIndex)->setFocus(a); }void frmVideoPlayNvr::on_btnNext_clicked(a)
{
    widgets.at(videoIndex)->next(a); widgets.at(videoIndex)->setFocus(a); }Copy the code