Qt Writing Security Video Monitoring System 16-Device Playback

Keywords: github Qt less SDK

1. Preface

Device playback module is added later, the core is to play real-time and historical videos by combining rtsp video stream addresses. At present, many manufacturers such as Haikang, the number one on the market support direct rtsp to play a channel video stream and playback a channel video stream through NVR. These formats can be searched on the Internet, and the first possible point of each manufacturer isDifferent, but the general information is the same, for example, to play a real-time video stream, you need to provide information such as user name, password, NVR address, corresponding channel, code stream type (primary/subcode stream). If you want to play a historical video stream, that is, playback a video, you need to provide information in addition to the above, you need to limit a time range to get the right oneThe corresponding video stream files, this time stamp is calculated in seconds in 1970 by some manufacturers, and some are time-time, etc., which need to be specified in the format of specific manufacturers.

The principle flow of device playback is that the manufacturer repackages the video stream files or stored video files and sends them out again. Some manufacturers use their own algorithms, some use live555 and so on.As a whole, it may refer to some open source push libraries more or less. People who have consulted many peers will basically refer to open source libraries such as ffmpeg and live 555. In fact, ffmpeg has fed many domestic manufacturers, even some large ones. To enlarge, github has fed more than N companies, especially AI enterprises. There is a passage in the industry saying: if github cannotAccess allowed, domestic AI level falls back 5 years.

Universal Video Control Open Source: https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo File name: videowidget

Experience address: https://gitee.com/feiyangqingyun/QWidgetExe https://github.com/feiyangqingyun/QWidgetExe File name: bin_video_system.zip

2. Functional features

  1. Support 16 picture switching, full screen switching, including 1+4+6+8+9+13+16 picture switching.
  2. Support alt+enter full screen, esc exit full screen.
  3. Custom Info Box + Error Box + Question Box + Tip Box in the lower right corner.
  4. 17 sets of skin styles are replaced at will, all of which are uniform, including menus.
  5. Cloud Dashboard mouse up highlighted, accurate identification of eight directions.
  6. The bottom Picture toolbar (settings such as split switching + sound for screenshots) is moved up and highlighted.
  7. You can change the logo+Chinese software name+English software name in the upper left corner of the configuration file.
  8. Encapsulated Baidu map, three-dimensional switching, device point, mouse press to get latitude and longitude, etc.
  9. Stack forms, each of which is a separate qwidget, make it easy to write your own code.
  10. The top right mouse button menu dynamically controls the display and hiding of time CPU+upper left panel+lower left panel+upper right panel+lower right panel, supporting the restoration of the default layout.
  11. The toolbar can have multiple small icons and close icons.
  12. On the left and right side, you can drag the stretch and automatically remember the width and height position to restart it.
  13. Double-click the camera node to play the video automatically, double-click the node to add the video automatically in turn, and automatically skip to the next, double-click the parent node to add all the videos under that node automatically.
  14. The camera node drags to the corresponding form to play the video, while supporting dragging local files to play directly.
  15. The video picture form supports drag exchange and instant response.
  16. Double-click Node+Drag Node+Drag Form to swap locations, automatically updating url.txt.
  17. Supports loading 16 channels of video playback from url.txt, automatically memorizing the last channel corresponding video, and automatically opening the playback after the software starts.
  18. Volume bar control in lower right corner, lose focus auto hide, volume bar mute icon.
  19. Integrated with Baidu Map, you can add corresponding locations of devices, automatically generate maps, support zooming and three-dimensional maps, provide map style selection, a total of 12 styles.
  20. Drag the video outside the channel window to automatically delete the video.
  21. Right mouse button can delete current + all videos, screenshot current + all videos.
  22. Video recorder management, camera management, can add delete modify import export print information, immediately apply new device information to generate a tree list, without restarting.
  23. In the pro file, you are free to open whether or not to load the map.
  24. Video playback can be switched freely by four cores, vlc+ffmpeg+easyplayer+haikang sdk, which can be set in pro.
  25. You can set 1+4+9+16 picture polling, set polling interval and polling code stream type, click the Start Polling button directly on the right side of the toolbar at the bottom of the main interface, and click Stop Polling again.
  26. Auto-hide mouse pointer is not operated by default for more than 10 seconds.
  27. Supports onvif search devices, supports any onvif cameras, including, but not limited to, Haikang Dahua Yuyu Shitianwei Huawei, and supports onvif cloud control.
  28. Highly customizable, users can easily derive their own functions and support linux system.

3. Effect Charts

4. 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();
    this->initIcon();
    this->initAddr();
    this->initVideo();
}

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();
            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()
{
    ui->cboxCompany->addItems(DBData::NvrTypes);
    ui->cboxCompany->setCurrentIndex(ui->cboxCompany->findText("deep and broad"));

    ui->cboxType->addItem("real-time video");
    ui->cboxType->addItem("Playback Video");

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

    ui->cboxRtsp->addItem("Primary Code Stream");
    ui->cboxRtsp->addItem("Subcode Stream");

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

    //Binding Changes Automatically Fill in 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()
{
    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()
{
    QString company = ui->cboxCompany->currentText();
    QString type = ui->cboxType->currentText();
    QString name = ui->txtName->text().trimmed();
    QString pwd = ui->txtPwd->text().trimmed();
    QString ip = ui->txtIP->text().trimmed();
    int ch = ui->cboxCh->currentIndex();
    int rtsp = ui->cboxRtsp->currentIndex();
    QString dateStart = ui->dateTimeStart->dateTime().toString("yyyy-MM-dd HH:mm:ss");
    QString dateEnd = ui->dateTimeEnd->dateTime().toString("yyyy-MM-dd HH:mm:ss");

    //Deep and wide NVR
    //Real-time preview format rtsp://admin:12345@192.168.1.128:554/live?Channel=1&stream=1
    //Video playback format rtsp://admin:12345@192.168.1.128:554/file?Channel=1&start=1494485280&stop=1494485480
    //Convert the timestamp first, the number of seconds between 1970 and that time
    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();
    qint64 stopTimeSec = stopTime.toTime_t();

    //Haikang NVR
    //Real-time preview format rtsp://admin:12345@192.168.1.128:554/Streaming/Channels/101?transportmode=unicast
    //Video playback format rtsp://admin:12345@192.168.1.128:554/Streaming/tracks/101?Starttime=20120802t063812z&endtime=20120802t064816z
    //Streaming media streaming rtsp://172.6.24.15:554/Devicehc8://172.6.22.106:8000:0:0?Username=admin&password=12345
    //The date-time format ISO 8601 represents the Zulu(GMT) time YYYMMDD"T" HHmmSS.fraction"Z".
    //Unicast means unicast, multicast means multicast, default unicast can be omitted
    //101,1 is the channel number 01 is the 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();
    endtime = endtime.replace("-", "");
    endtime = endtime.replace(":", "");
    endtime = endtime.toLower();

    QString addr;
    if (company == "deep and broad") {
        if (type == "real-time 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 == "Haikang") {
        if (type == "real-time 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 == "real-time video") {

        } else if (type == "Playback Video") {

        }
    }

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

void frmVideoPlayNvr::initVideo()
{
    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 Background Text
        widget->setBgText(QString("passageway %1").arg(i + 1));
        //Set Background Picture
        widget->setBgImage(QImage(":/bg_novideo.png"));
        //Set url address
        widget->setUrl("");
        //Set suspension bar visibility
        widget->setFlowEnable(false);
        //Set whether to reconnect automatically
        widget->setCheckLive(false);

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

    //Join in 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()
{
    QString addr = ui->txtAddr->toPlainText();
    if (addr.isEmpty()) {
        return;
    }

    widgets.at(videoIndex)->setUrl(addr);
    widgets.at(videoIndex)->close();
    widgets.at(videoIndex)->open();
    widgets.at(videoIndex)->setFocus();
}

void frmVideoPlayNvr::on_btnDelete_clicked()
{
    widgets.at(videoIndex)->close();
    widgets.at(videoIndex)->setFocus();
}

void frmVideoPlayNvr::on_btnPause_clicked()
{
    widgets.at(videoIndex)->pause();
    widgets.at(videoIndex)->setFocus();
}

void frmVideoPlayNvr::on_btnNext_clicked()
{
    widgets.at(videoIndex)->next();
    widgets.at(videoIndex)->setFocus();
}

Posted by TFD3 on Wed, 18 Dec 2019 19:03:55 -0800