使用QT实现Mjpeg-streamer的客户端,采用单独的线程进行视频图片的获取

1. mjpeg-streamer服务器的搭建

  1. 在树莓派上搭建好mjpeg-streamer的服务器,搭建过程可以参考这篇文章mjpg-streamer在树莓派上的使用

2. 简单QT界面的设计

  1. QT的界面布局主要参考了这篇文章,但是我的里面是使用单独开辟的线程进行解析数据流的,这个文章里面是在主线程中完成的。QT界面设计.

3. 使用线程获取网络图片

  1. 使用线程会遇到很多的问题,可以参考这篇文章QT 多线程采用线程池进行网络操作

4. 源码

1. 主函数

#include "loginwindow.h"

#include <QApplication>

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

    w.setWindowFlags(Qt::FramelessWindowHint);
    w.show();
    return a.exec();
}

2. 登录窗口界面代码

1. loginwindow.h

#ifndef LOGINWINDOW_H
#define LOGINWINDOW_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QTimer>
#include "mainwindow.h"

QT_BEGIN_NAMESPACE
namespace Ui { class LoginWindow; }
QT_END_NAMESPACE

class LoginWindow : public QMainWindow
{
    Q_OBJECT

public:
    LoginWindow(QWidget *parent = nullptr);
    ~LoginWindow();

private slots:
    void timerFinish();
    void on_btn_login_clicked();
    void on_btn_logout_clicked();

private:
    Ui::LoginWindow *ui;
    QString login_ipAddr;
    QString login_port;
    int waitCnt;
    QTimer *time;
    QString text;
    QTcpSocket *tcpClient;
    MainWindow *main;
    void init();
};
#endif // LOGINWINDOW_H

2. loginwindow.cpp

#include "loginwindow.h"
#include "ui_loginwindow.h"
#include <QMessageBox>

LoginWindow::LoginWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::LoginWindow)
{
    ui->setupUi(this);

    waitCnt = 0;
    text.append("Login");

    init();
}

LoginWindow::~LoginWindow()
{
    delete ui;
}

void LoginWindow::init()
{
    this->setWindowTitle("Please to Login");
    ui->le_ipAddr->setText("219.216.115.53");
    ui->le_port->setText("8080");
}

void LoginWindow::timerFinish()
{
    if(tcpClient->state() == QTcpSocket::ConnectedState){
        waitCnt = 0;
        time->stop();

        this->close();

        main = new MainWindow;
        main->main_ipAddr = login_ipAddr;
        main->main_port = login_port;
        main->init();
        main->show();

    }else{
        waitCnt++;

        if(waitCnt%10 == 3)
            text = "Login.";
        else if(waitCnt%10 == 6)
            text = "Login..";
        else if(waitCnt%10 == 9)
            text = "Login...";
        ui->btn_login->setText(text);

        if(waitCnt == 50){
            time->stop();
            waitCnt = 0;
            ui->btn_login->setText("Login");

            QMessageBox::warning(this, "Warning", "Please to Check params\nand Login again!", QMessageBox::Ok);
        }
    }
}

void LoginWindow::on_btn_login_clicked()
{
    login_ipAddr = ui->le_ipAddr->text();
    login_port = ui->le_port->text();

    tcpClient = new QTcpSocket(this);
    tcpClient->connectToHost(login_ipAddr, login_port.toInt());

    time = new QTimer(this);
    time->setInterval(100);

    connect(time, SIGNAL(timeout()), this, SLOT(timerFinish()));
    time->start();
}

void LoginWindow::on_btn_logout_clicked()
{
    this->close();
}

3. 主窗口界面代码

1. mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPixmap>
#include "getpixmap.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    QString main_ipAddr;
    QString main_port;

    void init();


private slots:
    void on_btn_start_clicked();
    void on_btn_screenshot_clicked();
    void on_btn_quit_clicked();
    void main_getOnePixmap(QPixmap);

private:
    Ui::MainWindow *ui;
    bool main_state = false;
    bool main_btnStartSta = false;
    GetPixmap *getPixmap;
    QThread *thread;

    QPixmap show_pix;
    QPixmap save_pix;
};

#endif // MAINWINDOW_H

2. mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QMessageBox>
#include <QFile>
#include <QFileDialog>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    main_btnStartSta = true;
    main_state = true;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::init()
{
    ui->lb_vedio->setScaledContents(main_state);
    this->setWindowTitle("Camera Client");
    this->setWindowFlags(this->windowFlags()&~(Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint));
}

void MainWindow::on_btn_start_clicked()
{
    QString name;

    if ((main_btnStartSta = !main_btnStartSta) == false)
    {
        name = "Stop";
        getPixmap = new GetPixmap;
        thread = new QThread();
        getPixmap->get_ipAddr = main_ipAddr;
        getPixmap->get_port = main_port;

        getPixmap->moveToThread(thread);

        void (GetPixmap:: *sig_getOnePixmap)(QPixmap) = &GetPixmap::get_getOnePixmap;
        void (MainWindow:: *slot_getOnePixmap)(QPixmap) = &MainWindow::main_getOnePixmap;

        connect(getPixmap,sig_getOnePixmap,this,slot_getOnePixmap);
        thread->start();
        connect(thread,&QThread::started,getPixmap,&GetPixmap::run);
    }
    else
    {
        name = "Start";
        thread->exit();
        disconnect(getPixmap,SIGNAL(get_getOnePixmap(QPixmap)),this,NULL);
        delete  getPixmap;
    }

    ui->btn_start->setText(name);
}

void MainWindow::on_btn_screenshot_clicked()
{
    save_pix = show_pix;

    if (save_pix.isNull())
    {
        QMessageBox::information(this,tr("Info"),tr("There are no images to save."));
    }
    else
    {
        QString fileName = QFileDialog::getSaveFileName(this,tr("Save File"),QDir::homePath(),tr("jpegfile(*.jpg)"));

        if (fileName.isEmpty())
        {
            QMessageBox::information(this,"Infor",tr("Save Cancel"));
            return;
        }

        save_pix.save(fileName);
    }
}


void MainWindow::on_btn_quit_clicked()
{
    this->close();
}


void MainWindow::main_getOnePixmap(QPixmap pix)
{
    show_pix = pix;

    ui->lb_vedio->setPixmap(show_pix);
    ui->lb_vedio->show();
}

4. 解析图像代码

1. getpixmap.h

#ifndef GETPIXMAP_H
#define GETPIXMAP_H

#include <QString>
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QByteArray>
#include <QPixmap>

class GetPixmap : public QObject
{
    Q_OBJECT

public:
    GetPixmap(QObject *parent = nullptr);
    ~GetPixmap();

public:
    QString get_ipAddr;
    QString get_port;

    void run();

private slots:
    void mjpeg_streamer_reply(QNetworkReply*);

signals:
    void get_getOnePixmap(QPixmap);


private:
    QNetworkAccessManager *manager;
    QNetworkRequest *request;
};

#endif // GETPIXMAP_H

2. getpixmap.cpp

#include "getpixmap.h"
#include <QDebug>

GetPixmap::GetPixmap(QObject *parent) :
    QObject(parent)
{

}

GetPixmap::~GetPixmap()
{

}

void GetPixmap::mjpeg_streamer_reply(QNetworkReply *reply)
{
    QByteArray byteArr = reply->readAll();

    QPixmap pix;
    pix.loadFromData(byteArr);

    emit get_getOnePixmap(pix);

    manager->get(*request);
    reply->deleteLater();
}



void GetPixmap::run()
{
    QString url;

    url.append("http://" + get_ipAddr + ":" + get_port + "/?action=snapshot");
    qDebug() << url;

//    qDebug() << "ipAddr:" << get_ipAddr;
//    qDebug() << "port:" << get_port;

    manager = new QNetworkAccessManager();
    request = new QNetworkRequest(QUrl(url));
    connect(manager,SIGNAL(finished(QNetworkReply*)), this, SLOT(mjpeg_streamer_reply(QNetworkReply*)));
    manager->get(*request);
}

5. 效果展示

1. 三个界面

  1. 登录窗口Login界面
  2. 主界面
    MainWindow界面
  3. 视频效果
    视频效果

2. 说明

  1. 视频效果不卡顿,分辨率可以依靠mjpeg-streamer服务器运行时调整,CPU资源使用32M左右,在现在的树莓上,这点资源消耗,不值得一提

5. 打包源码,使用QT Creator 4.13编辑

上面提供的代码已经可以搭建出界面,和主要的内容了,下面是可以直接编译,还有不懂的同学可以下载,一下资源收费

链接:https://pan.baidu.com/s/1LWaKJxqcYcK6KHM2z6jgWg
提取码:ecci
复制这段内容后打开百度网盘手机App,操作更方便哦

posted @ 2021-02-05 11:11  shukeke  阅读(892)  评论(1)    收藏  举报