65.QT-UDP组播实现多人共享桌面(同时支持收发显示)
这里我们只是简单学习下通过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;
}
}
65.QT-UDP组播实现多人共享桌面(同时支持收发显示)的更多相关文章
- QT Udp组播(穿透)
http://blog.csdn.net/victoryknight/article/details/7814243 主题 UDPQt路由器 局域网内的两台机器如果隔有路由器,那么这两台机器之间不 ...
- Android设备一对多录屏直播--(UDP组播连接,Tcp传输)
原文:https://blog.csdn.net/sunmmer123/article/details/82734245 近期需要学习流媒体知识,做一个Android设备相互投屏Demo,因此找到了这 ...
- ffmpeg笔记——UDP组播接收总结
ffmpeg在avformat_open_input里面已经实现了UDP的协议,所以只需要设置好参数,将url传递进去就可以了. 和打开文件的方式基本一样: 01 AVCodecContext *pV ...
- C# 使用UDP组播实现局域网桌面共享
最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. 需求:将一台机器的桌面通过网络显示到多个客户端的屏幕上,显示内容可能为PPT,Word文档之类 ...
- Android上UDP组播无法接收数据的问题
最近,想做一个跨平台的局域网的文件传输软件,思路是组播设备信息,TCP连接传输文件.于是进行了一次简单的UDP组播测试,发现Android对于UDP组播接收数据的支持即极为有限. 部分代码如下 pac ...
- 【网络开发】UDP组播接收端解析
UDP组播接收端解析 网络中的一台主机如果希望能够接收到来自网络中其它主机发往某一个组播组的数据报,那么这么主机必须先加入该组播组,然后就可以从组地址接收数据包.在广域网中,还涉及到路由器支持组播路由 ...
- 多网卡情况下接收udp组播
多网卡下接收udp组播 往往会接收失败 因为用错了网卡 例如我想要接收2网段 其他电脑出的udp组播 我电脑有有线网和wifi在window下可以这样 route add 230.0.0.1 mas ...
- (转)C# 使用UDP组播实现局域网桌面共享
转:http://www.cnblogs.com/mobwiz/p/3715743.html 最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. ...
- QT的UDP组播技术
一 UDP介绍 UDP是一种简单轻量级的传输层协议,提供无连接的,不可靠的报文传输.适合下面4种情况: 网络数据大多为短消息. 拥有大量客户端. 对数据安全性无特殊要求 网络负担非常重,但对响应速度要 ...
随机推荐
- 在 Linux 如何优雅的统计程序运行时间?恕我直言,你运行的可能是假 time
最近在使用 time 命令时,无意间发现了一些隐藏的小秘密和强大功能,今天分享给大家. time 在 Linux 下是比较常用的命令,可以帮助我们方便的计算程序的运行时间,对比采用不同方案时程序的运行 ...
- Python数模笔记-Sklearn(4)线性回归
1.什么是线性回归? 回归分析(Regression analysis)是一种统计分析方法,研究自变量和因变量之间的定量关系.回归分析不仅包括建立数学模型并估计模型参数,检验数学模型的可信度,也包括利 ...
- ruby基础(四)
ruby基础知识 模块 模块是ruby的特色功能之一.如果说类是事物的实体以及行为,那么模块表现的 就是事物的行为部分,模块和类有以下两点不同: 模块不能拥有实例 模块不能被继承 模块的使用方法 mo ...
- 网速测试利器-iperf3
网速测试利器-iperf3 使用工具 简介 iperf3是一个网络速度测试工具,支持IPv4与IPv6,支持TCP.UDP.SCTP传输协议,可在Windows.Mac OS X.Linux.Fr ...
- 使用sosreport命令生成诊断包
[RHEL]-7-常用系统状态检测命令 引言 这篇文章介绍RHEL中最常用的几个系统状态检测命令,包括:网络状态.内存.主机名及其架构.系统负载及其用户登录状态等. 文章目录 0×1.查看网络状态 0 ...
- Docker——基本使用及常用命令
Docker 是一个开源的应用容器引擎,而一个容器其实是一个虚拟化的独立的环境,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. ...
- debian用户手册-20200317
https://www.debian.org/doc/manuals/debian-reference/ 文档与使用手册在每一个操作系统中都是很重要的一部份,是描述程序操作和使用的技术手册.正由于说明 ...
- Centos7.4永久修改系统时间
[root@V3B01-zsy yum.repos.d]# date -s "2019-09-24 17:02:30" 2019年 09月 24日 星期二 17:02:30 CST ...
- golang快速入门(六)特有程序结构
提示:本系列文章适合对Go有持续冲动的读者 阅前须知:在程序结构这章,更多会关注golang中特有结构,与其他语言如C.python中相似结构(命名.声明.赋值.作用域等)不再赘述. 一.golang ...
- 如何写新的Python OP
如何写新的Python OP Paddle 通过 py_func 接口支持在Python端自定义OP. py_func的设计原理在于Paddle中的Tensor可以与numpy数组可以方便的互相转换, ...