readthread.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include "readthread.h"
  2. #include "videodecode.h"
  3. #include "videocodec.h"
  4. #include <QEventLoop>
  5. #include <QTimer>
  6. #include <QDebug>
  7. #include <qimage.h>
  8. #include <QFileInfo>
  9. #include <QMessageBox>
  10. #include <qstandardpaths.h>
  11. ReadThread::ReadThread(QObject *parent) : QThread(parent)
  12. {
  13. m_videoDecode = new VideoDecode();
  14. m_videoCodec = new VideoCodec();
  15. qRegisterMetaType<PlayState>("PlayState"); // 注册自定义枚举类型,否则信号槽无法发送
  16. }
  17. ReadThread::~ReadThread()
  18. {
  19. if(m_videoDecode)
  20. {
  21. delete m_videoDecode;
  22. }
  23. }
  24. /**
  25. * @brief 设置视频保存地址
  26. * @param path
  27. */
  28. void ReadThread::setPath(const QString &path)
  29. {
  30. if(path.isEmpty()) return;
  31. if(QFileInfo(path).suffix().isEmpty())
  32. {
  33. QMessageBox::warning(nullptr, "注意~", "输入文件没有后缀名,无法使用");
  34. m_path.clear();
  35. return;
  36. }
  37. m_path = path;
  38. }
  39. /**
  40. * @brief 传入播放的视频地址并开启线程
  41. * @param url
  42. */
  43. void ReadThread::open(const QString &url)
  44. {
  45. if(!this->isRunning())
  46. {
  47. m_url = url;
  48. emit this->start();
  49. }
  50. }
  51. /**
  52. * @brief 关闭播放
  53. */
  54. void ReadThread::close()
  55. {
  56. m_play = false;
  57. }
  58. /**
  59. * @brief 返回当前播放的地址
  60. * @return
  61. */
  62. const QString &ReadThread::url()
  63. {
  64. return m_url;
  65. }
  66. /**
  67. * @brief 非阻塞延时
  68. * @param msec 延时毫秒
  69. */
  70. void sleepMsec(int msec)
  71. {
  72. if(msec <= 0) return;
  73. QEventLoop loop; //定义一个新的事件循环
  74. QTimer::singleShot(msec, &loop, SLOT(quit()));//创建单次定时器,槽函数为事件循环的退出函数
  75. loop.exec(); //事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
  76. }
  77. void ReadThread::run()
  78. {
  79. m_path = QString("%1/%2.flv").arg(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation))
  80. .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss"));
  81. if(m_path.isEmpty()) return;
  82. bool ret = m_videoDecode->open(m_url); // 打开网络流时会比较慢,如果放到Ui线程会卡
  83. if(ret)
  84. {
  85. m_play = m_videoCodec->open(m_videoDecode->getCodecContext(), m_videoDecode->avgFrameRate(), m_path);
  86. if(!m_play)
  87. {
  88. qDebug() << "打开输出文件失败!";
  89. }
  90. else
  91. {
  92. emit playState(play);
  93. }
  94. }
  95. else
  96. {
  97. qWarning() << "打开失败!";
  98. }
  99. // 循环读取视频图像
  100. while (m_play)
  101. {
  102. AVFrame* frame = m_videoDecode->read(); // 读取视频图像
  103. if(frame)
  104. {
  105. m_videoCodec->write(frame); // 将解码后的图像数据传递给编码保存类
  106. }
  107. else
  108. {
  109. // 当前读取到无效图像时判断是否读取完成
  110. if(m_videoDecode->isEnd())
  111. {
  112. break;
  113. }
  114. sleepMsec(1); // 这里不能使用QThread::msleep()延时,否则会很不稳定
  115. }
  116. }
  117. qDebug() << "录屏结束!";
  118. m_videoDecode->close();
  119. m_videoCodec->close();
  120. emit playState(end);
  121. }