前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >65.QT-UDP组播实现多人共享桌面(同时支持收发显示)

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

作者头像
诺谦
发布2021-06-29 10:59:00
1.8K1
发布2021-06-29 10:59:00
举报
文章被收录于专栏:Linux驱动Linux驱动

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

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

1.Demo介绍

截图如下所示:

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

功能介绍

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

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

2.sharescreenthread.cpp代码如下所示

代码语言:javascript
复制
#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代码如下所示

代码语言:javascript
复制
#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;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-06-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档