经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
65.QT-UDP组播实现多人共享桌面(同时支持收发显示)
来源:cnblogs  作者:诺谦  时间:2021/6/28 9:42:42  对本文有异议

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

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

1.Demo介绍

截图如下所示:

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

功能介绍

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

 

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

 

 

 

2.sharescreenthread.cpp代码如下所示

  1. #include "sharescreenthread.h"
  2. ShareScreenThread::ShareScreenThread(QThread *parent) : QThread(parent),
  3. m_state(ShareScreen_None),
  4. groupAddress("239.255.43.21"),
  5. m_runCnt(0),
  6. m_canRead(false),
  7. m_sendQuality(20)
  8. {
  9. m_recvQueue.clear();
  10. }
  11. bool ShareScreenThread::startGrabWindow()
  12. {
  13. QMutexLocker locker(&m_mutex);
  14. if (m_state == ShareScreen_Stop || m_state == ShareScreen_SendRunning) {
  15. m_state = ShareScreen_SendRunning;
  16. emit stateChange();
  17. return true;
  18. }
  19. return false;
  20. }
  21. bool ShareScreenThread::stopGrabWindow()
  22. {
  23. QMutexLocker locker(&m_mutex);
  24. if (m_state == ShareScreen_SendRunning || m_state == ShareScreen_Stop) {
  25. m_state = ShareScreen_EnterStop;
  26. return true;
  27. }
  28. return false;
  29. }
  30. void ShareScreenThread::run()
  31. {
  32. m_udp = new QUdpSocket();
  33. qDebug()<<"绑定:"<<m_udp->bind(QHostAddress::AnyIPv4, 44544, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
  34. qDebug()<<"加入:"<<m_udp->joinMulticastGroup(groupAddress);
  35. while(1) {
  36. switch (m_state) {
  37. case ShareScreen_None:
  38. m_runCnt++;
  39. if (m_runCnt > 100) {
  40. m_state = ShareScreen_Stop;
  41. m_preGetWindowMSec = QDateTime::currentDateTime().toMSecsSinceEpoch(); //记录时间
  42. emit stateChange();
  43. }
  44. msleep(10);
  45. if(m_udp->hasPendingDatagrams() ) {
  46. m_state = ShareScreen_RecvRunning;
  47. emit stateChange();
  48. m_preGetWindowMSec = QDateTime::currentDateTime().toMSecsSinceEpoch(); //记录时间
  49. getWindow();
  50. }
  51. break;
  52. case ShareScreen_Stop:
  53. if(m_udp->hasPendingDatagrams()) {
  54. m_state = ShareScreen_RecvRunning;
  55. emit stateChange();
  56. getWindow();
  57. }
  58. break;
  59. case ShareScreen_RecvRunning:
  60. getWindow();
  61. break;
  62. case ShareScreen_SendRunning:
  63. grabWindow();
  64. break;
  65. case ShareScreen_EnterStop: // 由于广播,自己会受到自己消息,需要清空
  66. if (m_udp->hasPendingDatagrams() ) {
  67. m_udp->receiveDatagram();
  68. } else {
  69. m_state = ShareScreen_Stop;
  70. emit stateChange();
  71. }
  72. break;
  73. default: break;
  74. }
  75. }
  76. }

3.widget.cpp代码如下所示

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. Widget::Widget(QWidget *parent)
  4. : QWidget(parent),
  5. ui(new Ui::Widget)
  6. {
  7. ui->setupUi(this);
  8. connect(&m_thread, SIGNAL(stateChange()), this, SLOT(onStateChange()));
  9. m_thread.start();
  10. connect(&m_updateShow, SIGNAL(timeout()), this, SLOT(onUpdateShow()));
  11. setWindowTitle("UDP共享屏幕");
  12. }
  13. Widget::~Widget()
  14. {
  15. m_thread.terminate();
  16. delete ui;
  17. }
  18. void Widget::onStateChange()
  19. {
  20. qDebug()<<"onStateChange"<<m_thread.state();
  21. switch (m_thread.state()) {
  22. case ShareScreenThread::ShareScreen_None: break;
  23. case ShareScreenThread::ShareScreen_Stop: ui->labelHint->setText("等待共享..."); cleanShow(); ui->comboQuality->setEnabled(true); break;
  24. case ShareScreenThread::ShareScreen_RecvRunning: ui->labelHint->setText("有人正在共享中?");
  25. m_pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch(); //记录的时间
  26. m_updateShowCnt = 0;
  27. m_updateShow.start(25);
  28. ui->comboQuality->setEnabled(false);
  29. break;
  30. case ShareScreenThread::ShareScreen_SendRunning: ui->labelHint->setText("您正在共享中?"); ui->comboQuality->setEnabled(true); break;
  31. default: break;
  32. }
  33. }
  34. void Widget::cleanShow()
  35. {
  36. ui->labelShow->clear();
  37. ui->labelByte->setText(QString("每帧: %1KB").arg(0));
  38. ui->labelFPS->setText("当前FPS: "+ QString("%1").arg(0));
  39. }
  40. void Widget::onUpdateShow()
  41. {
  42. bool getOk = false;
  43. int size = 0;
  44. QPixmap pix(m_thread.getPixmap(getOk, size));
  45. QSize imageSize =pix.size();
  46. if (size!=0)
  47. ui->labelByte->setText(QString("每帧: %1KB").arg(size/1024));
  48. if (getOk == false)
  49. return;
  50. pix = pix.scaled(ui->labelShow->size(), Qt::KeepAspectRatio);
  51. if (m_thread.state() == ShareScreenThread::ShareScreen_RecvRunning) {
  52. QPainter painter(&pix);
  53. painter.setRenderHints(QPainter::Antialiasing);
  54. QPixmap mouse(":/mouse");
  55. double xratio = pix.width() / (double)imageSize.width();
  56. double yratio = pix.height() / (double)imageSize.height();
  57. painter.drawPixmap(m_thread.getMousePos().x()*xratio, m_thread.getMousePos().y()*yratio , 25*xratio, 25*yratio, mouse);
  58. }
  59. ui->labelShow->setPixmap(pix);
  60. if (m_updateShowCnt++ >= 10) {
  61. qint64 tmp = QDateTime::currentDateTime().toMSecsSinceEpoch();
  62. qint64 durationMs = tmp - m_pressMSec;
  63. int fps = m_updateShowCnt * 1000/durationMs;
  64. ui->labelFPS->setText("当前FPS: "+ QString("%1").arg(fps));
  65. m_updateShowCnt = 0;
  66. m_pressMSec = tmp;
  67. }
  68. }
  69. void Widget::on_btnStartShare_clicked()
  70. {
  71. bool question;
  72. switch (m_thread.state()) {
  73. case ShareScreenThread::ShareScreen_None: customDialog::ShowMessageErr(this,"提示", "正在初始化中!"); return;
  74. case ShareScreenThread::ShareScreen_Stop: cleanShow(); break;
  75. case ShareScreenThread::ShareScreen_RecvRunning: customDialog::ShowMessageInfo(this,"提示", "有人正在共享中!"); return;
  76. case ShareScreenThread::ShareScreen_SendRunning: question = customDialog::ShowMessageQuestion(this,"询问", "是否取消共享?");
  77. if (!question)
  78. return;
  79. }
  80. bool myStartd = ui->btnStartShare->text().contains("停止");
  81. if (myStartd) {
  82. m_thread.stopGrabWindow();
  83. ui->btnStartShare->setText("开始共享");
  84. ui->labelFPS->setText("当前FPS: 0");
  85. m_updateShow.stop();
  86. ui->labelShow->setPixmap(QPixmap());
  87. } else {
  88. m_thread.startGrabWindow();
  89. ui->btnStartShare->setText("停止共享");
  90. m_pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch(); //记录的时间
  91. m_updateShowCnt = 0;
  92. m_updateShow.start(12);
  93. }
  94. }
  95. void Widget::keyPressEvent(QKeyEvent *event)
  96. {
  97. if (ui->control->isHidden() && event->key() == Qt::Key_Escape) {
  98. ui->control->show();
  99. showMaximized();
  100. }
  101. }
  102. void Widget::on_btnFull_clicked()
  103. {
  104. ui->control->hide();
  105. showFullScreen();
  106. }
  107. void Widget::on_comboQuality_currentIndexChanged(int index)
  108. {
  109. switch (index) {
  110. case 0 : m_thread.setQuality(20); break;
  111. case 1 : m_thread.setQuality(38); break;
  112. case 2 : m_thread.setQuality(50); break;
  113. }
  114. }

 

原文链接:http://www.cnblogs.com/lifexy/p/14926509.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号