当前位置 博文首页 > 诺谦:65.QT-UDP组播实现多人共享桌面(同时支持收发显示)

    诺谦:65.QT-UDP组播实现多人共享桌面(同时支持收发显示)

    作者:诺谦 时间:2021-06-24 18:47

    这里我们只是简单学习下通过udp组播如何共享桌面demo.帧率上面比较低,毕竟没有用推流,只是简单的将图片发送到组播地址,而加入组播地址的客户端去取数据显示而已.

    主要是为了学习UDP知识而写的,真的想要做共享桌面的话,建议还是使用qt FFmpeg推流.速度上会快很多(后续有时间再来出)

    1.Demo介绍

    截图如下所示:

    gif效果如下所示(有点大,加载有点久):

    功能介绍

    • 一份代码同时支持收数据处理发数据处理.
    • 自动检查帧率每帧图片字节大小
    • 代码中使用了多线程队列协助QWidget显示.
    • 当接收共享时,会在线程中不停接收数据,直到接收到完整的一份数据时,则放到队列中,然后供QWidget提取数据.
    • 当开启共享时,则在线程中抓取桌面数据,实时发送,并备份一个QPixmap供QWidget显示数据

     

    代码和可以直接运行的程序都放在群里,需要的自行下载:

     

     

     

    2.sharescreenthread.cpp代码如下所示

    #include "sharescreenthread.h"
    
    ShareScreenThread::ShareScreenThread(QThread *parent) : QThread(parent),
        m_state(ShareScreen_None),
        groupAddress("239.255.43.21"),
        m_runCnt(0),
        m_canRead(false),
        m_sendQuality(20)
    {
        m_recvQueue.clear();
    }
    
    
    bool ShareScreenThread::startGrabWindow()
    {
        QMutexLocker locker(&m_mutex);
        if (m_state == ShareScreen_Stop || m_state == ShareScreen_SendRunning) {
            m_state = ShareScreen_SendRunning;
            emit stateChange();
            return true;
        }
        return false;
    }
    
    bool ShareScreenThread::stopGrabWindow()
    {
        QMutexLocker locker(&m_mutex);
        if (m_state == ShareScreen_SendRunning || m_state == ShareScreen_Stop) {
            m_state = ShareScreen_EnterStop;
            return true;
        }
    
        return false;
    }
    void ShareScreenThread::run()
    {
        m_udp = new QUdpSocket();
        qDebug()<<"绑定:"<<m_udp->bind(QHostAddress::AnyIPv4, 44544, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
        qDebug()<<"加入:"<<m_udp->joinMulticastGroup(groupAddress);
    
        while(1) {
    
            switch (m_state) {
                case ShareScreen_None:
                    m_runCnt++;
                    if (m_runCnt > 100) {
                        m_state = ShareScreen_Stop;
                        m_preGetWindowMSec = QDateTime::currentDateTime().toMSecsSinceEpoch();     //记录时间
                        emit stateChange();
                    }
                    msleep(10);
                    if(m_udp->hasPendingDatagrams() ) {
                        m_state = ShareScreen_RecvRunning;
                        emit stateChange();
                        m_preGetWindowMSec = QDateTime::currentDateTime().toMSecsSinceEpoch();     //记录时间
                        getWindow();
                    }
                    break;
                case ShareScreen_Stop:
                    if(m_udp->hasPendingDatagrams()) {
                        m_state = ShareScreen_RecvRunning;
                        emit stateChange();
                        getWindow();
                    }
                    break;
                case ShareScreen_RecvRunning:
                    getWindow();
                    break;
                case ShareScreen_SendRunning:
                    grabWindow();
                    break;
                case ShareScreen_EnterStop:     // 由于广播,自己会受到自己消息,需要清空
                    if (m_udp->hasPendingDatagrams() ) {
                        m_udp->receiveDatagram();
                    } else {
                        m_state = ShareScreen_Stop;
                        emit stateChange();
                    }
                    break;
    
                default: break;
            }
    
        }
    }

    3.widget.cpp代码如下所示

    #include "widget.h"
    #include "ui_widget.h"
    Widget::Widget(QWidget *parent)
        : QWidget(parent),
          ui(new Ui::Widget)
    
    {
        ui->setupUi(this);
        connect(&m_thread, SIGNAL(stateChange()), this, SLOT(onStateChange()));
        m_thread.start();
    
        connect(&m_updateShow, SIGNAL(timeout()), this, SLOT(onUpdateShow()));
    
        setWindowTitle("UDP共享屏幕");
    }
    
    Widget::~Widget()
    {
        m_thread.terminate();
        delete ui;
    }
    
    void Widget::onStateChange()
    {
        qDebug()<<"onStateChange"<<m_thread.state();
        switch (m_thread.state()) {
            case ShareScreenThread::ShareScreen_None:  break;
            case ShareScreenThread::ShareScreen_Stop: ui->labelHint->setText("等待共享..."); cleanShow(); ui->comboQuality->setEnabled(true); break;
            case ShareScreenThread::ShareScreen_RecvRunning: ui->labelHint->setText("有人正在共享中?");
    
                m_pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch();     //记录的时间
                m_updateShowCnt = 0;
                m_updateShow.start(25);
                ui->comboQuality->setEnabled(false);
                break;
            case ShareScreenThread::ShareScreen_SendRunning: ui->labelHint->setText("您正在共享中?"); ui->comboQuality->setEnabled(true); break;
            default: break;
        }
    }
    
    void Widget::cleanShow()
    {
        ui->labelShow->clear();
        ui->labelByte->setText(QString("每帧: %1KB").arg(0));
        ui->labelFPS->setText("当前FPS: "+ QString("%1").arg(0));
    
    }
    
    
    void Widget::onUpdateShow()
    {
        bool getOk = false;
        int size = 0;
        QPixmap pix(m_thread.getPixmap(getOk, size));
        QSize imageSize =pix.size();
        if (size!=0)
            ui->labelByte->setText(QString("每帧: %1KB").arg(size/1024));
    
        if (getOk == false)
            return;
    
        pix = pix.scaled(ui->labelShow->size(), Qt::KeepAspectRatio);
    
        if (m_thread.state() == ShareScreenThread::ShareScreen_RecvRunning) {
            QPainter painter(&pix);
            painter.setRenderHints(QPainter::Antialiasing);
            QPixmap mouse(":/mouse");
            double xratio = pix.width() / (double)imageSize.width();
            double yratio = pix.height() / (double)imageSize.height();
            painter.drawPixmap(m_thread.getMousePos().x()*xratio, m_thread.getMousePos().y()*yratio , 25*xratio, 25*yratio, mouse);
    
        }
    
        ui->labelShow->setPixmap(pix);
    
        if (m_updateShowCnt++ >= 10) {
            qint64 tmp = QDateTime::currentDateTime().toMSecsSinceEpoch();
            qint64 durationMs = tmp - m_pressMSec;
    
            int fps = m_updateShowCnt * 1000/durationMs;
            ui->labelFPS->setText("当前FPS: "+ QString("%1").arg(fps));
    
            m_updateShowCnt = 0;
            m_pressMSec = tmp;
        }
    
    }
    
    void Widget::on_btnStartShare_clicked()
    {
        bool question;
        switch (m_thread.state()) {
            case ShareScreenThread::ShareScreen_None: customDialog::ShowMessageErr(this,"提示", "正在初始化中!"); return;
            case ShareScreenThread::ShareScreen_Stop: cleanShow(); break;
            case ShareScreenThread::ShareScreen_RecvRunning: customDialog::ShowMessageInfo(this,"提示", "有人正在共享中!"); return;
            case ShareScreenThread::ShareScreen_SendRunning:  question = customDialog::ShowMessageQuestion(this,"询问", "是否取消共享?");
                if (!question)
                    return;
        }
    
    
    
        bool myStartd = ui->btnStartShare->text().contains("停止");
    
        if (myStartd) {
            m_thread.stopGrabWindow();
            ui->btnStartShare->setText("开始共享");
            ui->labelFPS->setText("当前FPS: 0");
            m_updateShow.stop();
    
            ui->labelShow->setPixmap(QPixmap());
        } else {
            m_thread.startGrabWindow();
            ui->btnStartShare->setText("停止共享");
            m_pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch();     //记录的时间
            m_updateShowCnt = 0;
            m_updateShow.start(12);
        }
    
    }
    
    void Widget::keyPressEvent(QKeyEvent *event)
    {
    
    
       if (ui->control->isHidden() && event->key() == Qt::Key_Escape) {
            ui->control->show();
            showMaximized();
    
       }
    
    }
    
    
    void Widget::on_btnFull_clicked()
    {
        ui->control->hide();
        showFullScreen();
    
    }
    
    void Widget::on_comboQuality_currentIndexChanged(int index)
    {
    
        switch (index) {
            case 0 : m_thread.setQuality(20); break;
            case 1 : m_thread.setQuality(38); break;
            case 2 : m_thread.setQuality(50); break;
        }
    }

     

    bk
    下一篇:没有了