65.QT-UDP组播实现多人共享桌面(同时支持收发显示)
程序员文章站
2022-06-21 22:50:56
这里我们只是简单学习下通过udp组播如何共享桌面demo.帧率上面比较低,毕竟没有用推流,只是简单的将图片发送到组播地址,而加入组播地址的客户端去取数据显示而已. 主要是为了学习UDP知识而写的,真的想要做共享桌面的话,建议还是使用qt FFmpeg推流.速度上会快很多(后续有时间再来出) 1.De ......
这里我们只是简单学习下通过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; } }
上一篇: 行书是古代书法统称,它如何在楷书的基础上发展起来?
下一篇: vue3常用的API使用简介