欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-25 15:50:54
这里我们只是简单学习下通过udp组播如何共享桌面demo.帧率上面比较低,毕竟没有用推流,只是简单的将图片发送到组播地址,而加入组播地址的客户端去取数据显示而已. 主要是为了学习UDP知识而写的,真的想要做共享桌面的话,建议还是使用qt FFmpeg推流.速度上会快很多(后续有时间再来出) 1.De ......

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

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

1.demo介绍

截图如下所示:

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

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

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

功能介绍

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

 

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

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

 

 

 

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;
    }
}