这里我们只是简单学习下通过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组播实现多人共享桌面(同时支持收发显示)的更多相关文章

  1. QT Udp组播(穿透)

      http://blog.csdn.net/victoryknight/article/details/7814243 主题 UDPQt路由器 局域网内的两台机器如果隔有路由器,那么这两台机器之间不 ...

  2. Android设备一对多录屏直播--(UDP组播连接,Tcp传输)

    原文:https://blog.csdn.net/sunmmer123/article/details/82734245 近期需要学习流媒体知识,做一个Android设备相互投屏Demo,因此找到了这 ...

  3. ffmpeg笔记——UDP组播接收总结

    ffmpeg在avformat_open_input里面已经实现了UDP的协议,所以只需要设置好参数,将url传递进去就可以了. 和打开文件的方式基本一样: 01 AVCodecContext *pV ...

  4. C# 使用UDP组播实现局域网桌面共享

    最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. 需求:将一台机器的桌面通过网络显示到多个客户端的屏幕上,显示内容可能为PPT,Word文档之类 ...

  5. Android上UDP组播无法接收数据的问题

    最近,想做一个跨平台的局域网的文件传输软件,思路是组播设备信息,TCP连接传输文件.于是进行了一次简单的UDP组播测试,发现Android对于UDP组播接收数据的支持即极为有限. 部分代码如下 pac ...

  6. 【网络开发】UDP组播接收端解析

    UDP组播接收端解析 网络中的一台主机如果希望能够接收到来自网络中其它主机发往某一个组播组的数据报,那么这么主机必须先加入该组播组,然后就可以从组地址接收数据包.在广域网中,还涉及到路由器支持组播路由 ...

  7. 多网卡情况下接收udp组播

    多网卡下接收udp组播 往往会接收失败 因为用错了网卡 例如我想要接收2网段 其他电脑出的udp组播  我电脑有有线网和wifi在window下可以这样 route add 230.0.0.1 mas ...

  8. (转)C# 使用UDP组播实现局域网桌面共享

    转:http://www.cnblogs.com/mobwiz/p/3715743.html 最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. ...

  9. QT的UDP组播技术

    一 UDP介绍 UDP是一种简单轻量级的传输层协议,提供无连接的,不可靠的报文传输.适合下面4种情况: 网络数据大多为短消息. 拥有大量客户端. 对数据安全性无特殊要求 网络负担非常重,但对响应速度要 ...

随机推荐

  1. 基于RestAssured实现接口自动化

    RestAssured是一款强大的接口自动化框架, 旨在使用方便的DSL,简化的接口自动化. 下面是基于RestAssured扩展的一个简单框架示例, 先看看用例的风格: package testca ...

  2. 语音降噪论文“A Hybrid Approach for Speech Enhancement Using MoG Model and Neural Network Phoneme Classifier”的研读

    最近认真的研读了这篇关于降噪的论文.它是一种利用混合模型降噪的方法,即既利用了生成模型(MoG高斯模型),也利用了判别模型(神经网络NN模型).本文根据自己的理解对原理做了梳理. 论文是基于" ...

  3. 通过CRM系统改变传统工作模式

    在现在这个互联网时代,同行业的竞争越发激烈,因此许多企业都选择使用CRM来提高企业的销售业绩.CRM客户关系管理系统是能够优化企业的销售流程.维护良好的客户关系.对销售流程进行管理的强大工具.但是很多 ...

  4. CRM系统推动教育行业数字化转型

    目前,教育培训的潜在市场规模巨大,并且保持着迅猛的发展态势.同时,随着众多外资企业不断涌入中国市场,与国内大大小小的培训机构展开竞争,所以教育行业的竞争也是非常的激烈.传统的教育行业亟待数字化转型,才 ...

  5. ln -s 新目录(最后一个目录新建images) 旧目录(删除最后的images目录)

    sudo yum install libvirt virt-install qemu-kvm 默认安装会启用一个NAT模式的bridgevirbr0 启动激活libvirtd服务 systemctl ...

  6. DOCKER学习_018:Docker-Compose文件简介

    Docker-Compose文件 通过之前的示例,其实我们可以看到,所有服务的管理,都是依靠docker-compose.yml文件来实现的.那么我们接下来就详细说一说docker-compose.y ...

  7. Docker-Compose入门-(转载)

    Compose 是一个用户定义和运行多个容器的 Docker 应用程序.在 Compose 中你可以使用 YAML 文件来配置你的应用服务.然后,只需要一个简单的命令,就可以创建并启动你配置的所有服务 ...

  8. IDEA 怎么统计项目代码行数

    引言 IDEA 统计项目代码行数,主要是使用 Statistic 插件来统计 第一步 点击 File->Settings,如下图所示: 第二步 点击 install 安装 Statistic 插 ...

  9. STM32电路设计注意

    以后画STM32的电路板 VDDA一定要接 张JF说  VDDA是给内部的时钟电路供电的 还有一定要留 串口或者  下载调试口(串口) 或者显示器接口 输入输出设备最好都留着 这样才能方便调试

  10. osi七层模型与tcp/ip四层模型的差别

    OSI 七层协议 应用层 表示层 会话层 运输层 网络层 数据链路层 物理层 TCP/IP 四层协议 应用层 运输层 网际层 网络接口层 五层协议: 应用层 为用户的应用进程提供服务 HTTP SMT ...