VideoPlayer.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. #include "VideoPlayer.h"
  2. #include "DecodeVedio.h"
  3. #include <QPainter>
  4. #include <QResizeEvent>
  5. #include <QEventLoop>
  6. #include "spdlog/spdlog.h"
  7. VideoPlayer::VideoPlayer(QWidget *parent) : QWidget(parent)
  8. {
  9. /* 初始化解码线程 */
  10. m_threadDecode = new QThread(this);
  11. m_decodeVedio = new DecodeVedio(m_threadDecode);
  12. m_semRefresh = new QSemaphore(30);
  13. m_semRefresh->release(30);
  14. m_timerRefreshUI.setSingleShot(false);
  15. /* 设置精度毫秒级 */
  16. m_timerRefreshUI.setTimerType(Qt::PreciseTimer);
  17. connect(&m_timerRefreshUI, &QTimer::timeout, this, &VideoPlayer::do_refreshUI);
  18. connect(m_decodeVedio, &DecodeVedio::signal_oneImage, this, &VideoPlayer::do_refreshOneUI);
  19. SPDLOG_TRACE("UI线程ID:{}", QThread::currentThreadId());
  20. }
  21. VideoPlayer::~VideoPlayer()
  22. {
  23. if(m_timerRefreshUI.isActive())
  24. {
  25. m_timerRefreshUI.stop();
  26. }
  27. delete m_decodeVedio;
  28. if(m_image)
  29. {
  30. delete m_image;
  31. }
  32. }
  33. /**
  34. * @brief 设置播放视频,启动定时器,定时器间隔决定播放的速度
  35. * 视频的宽和高使用QImage进行缩放
  36. * 视频大小在直接设置这个类的resize即可,有最小大小限制
  37. *
  38. * @param fileName
  39. */
  40. void VideoPlayer::setPlayVedio(const QString& fileName)
  41. {
  42. m_fileName = fileName;
  43. isSetVedioFile = true;
  44. m_decodeVedio->initFFmpeg(m_fileName);
  45. /* 获取原始视频信息 */
  46. m_srcWidth = m_decodeVedio->getVideoWidth();
  47. m_srcHeight = m_decodeVedio->getVideoHeight();
  48. m_frameCount = m_decodeVedio->getFrameCount();
  49. SPDLOG_DEBUG("视频宽:{} 高:{} 帧数:{}", m_srcWidth, m_srcHeight, m_frameCount);
  50. /* 设置视频宽和高的最小大小 */
  51. this->setMinimumSize(160,90);
  52. /* 开启定时器刷新 */
  53. if(m_frameCount < 0)
  54. {
  55. /* HEVC帧率,获取不到,就按照24帧来刷新 */
  56. if(m_frameCount == -2)
  57. {
  58. m_frameCount = 24;
  59. }
  60. else {
  61. m_frameCount = 25;
  62. }
  63. }
  64. else if(m_frameCount == 0)
  65. {
  66. m_frameCount = 25;
  67. }
  68. SPDLOG_INFO("帧率:{}", m_frameCount);
  69. /* 开启解码,手动刷新第一帧 */
  70. m_decodeVedio->startDecodeVedio();
  71. m_semRefresh->release(1);
  72. // m_timerRefreshUI.setSingleShot(true);
  73. // m_timerRefreshUI.start(500);
  74. }
  75. /* 播放视频 */
  76. bool VideoPlayer::play()
  77. {
  78. if(!isSetVedioFile)
  79. {
  80. SPDLOG_ERROR("文件名为空");
  81. return false;
  82. }
  83. if(m_playStatus)
  84. {
  85. return false;
  86. }
  87. /* 设置刷新时间 */
  88. m_timerRefreshUI.setSingleShot(false);
  89. m_interval = 1000/m_frameCount;
  90. if(1000 % m_frameCount > 5)
  91. {
  92. m_frameCount += 1;
  93. }
  94. SPDLOG_TRACE("刷新UI的定时间隔:{}",m_interval);
  95. m_timerRefreshUI.start(m_interval);
  96. m_playStatus = true;
  97. return true;
  98. }
  99. /* 暂停播放 */
  100. void VideoPlayer::pause()
  101. {
  102. if(!m_playStatus)
  103. {
  104. return;
  105. }
  106. m_timerRefreshUI.stop();
  107. m_playStatus = false;
  108. }
  109. /* 停止播放,停止后停止解码,清空队列,渲染一帧黑屏 */
  110. void VideoPlayer::stop()
  111. {
  112. SPDLOG_DEBUG("...停止播放...");
  113. m_fileName = QString();
  114. if(m_timerRefreshUI.isActive())
  115. {
  116. m_timerRefreshUI.stop();
  117. }
  118. SPDLOG_DEBUG("...停止解码...");
  119. m_decodeVedio->stopDecodeVedio();
  120. /* 绘制黑帧 */
  121. SPDLOG_DEBUG("绘制黑帧");
  122. m_image = new QImage(m_nowWidth, m_nowHeight, QImage::Format_RGB32);
  123. m_image->fill(Qt::black);
  124. update();
  125. m_playStatus = false;
  126. isSetVedioFile = false;
  127. }
  128. /* 获取视频时长 */
  129. qint64 VideoPlayer::getDuration()
  130. {
  131. return m_decodeVedio->getDuration();
  132. }
  133. /* 获取当前播放位置 */
  134. qint64 VideoPlayer::getCurrentPos()
  135. {
  136. return m_decodeVedio->getCurrentPos();
  137. }
  138. /* 设置当前播放位置 */
  139. void VideoPlayer::setCurrentPos(quint64 pos)
  140. {
  141. /* 先停止播放 */
  142. bool temp = m_playStatus;
  143. if(m_playStatus)
  144. {
  145. m_timerRefreshUI.stop();
  146. m_playStatus = false;
  147. }
  148. m_decodeVedio->setCurrentPos(pos);
  149. /* 继续播放 */
  150. if(temp)
  151. {
  152. m_timerRefreshUI.start(m_interval);
  153. m_playStatus = true;
  154. }else
  155. {
  156. /* 刷新三张照片,防止第一张是跳转前的时间段 */
  157. m_semRefresh->release(3);
  158. }
  159. }
  160. void VideoPlayer::paintEvent(QPaintEvent *event)
  161. {
  162. if(m_image)
  163. {
  164. // SPDLOG_TRACE("开始绘制画面...");
  165. QPainter painter(this);
  166. painter.drawImage(0, 0, *m_image);
  167. }
  168. }
  169. void VideoPlayer::resizeEvent(QResizeEvent *event)
  170. {
  171. SPDLOG_TRACE("窗口大小改变...");
  172. m_nowWidth = event->size().width();
  173. m_nowHeight = event->size().height();
  174. QWidget::resizeEvent(event);
  175. }
  176. /* 刷新一张图片,直到有图片为止 */
  177. void VideoPlayer::refreshOneUIUntilHave()
  178. {
  179. if(m_decodeVedio != nullptr)
  180. {
  181. // SPDLOG_DEBUG("取出一帧图片...");
  182. /* 删除上一帧图片 */
  183. if(m_image != nullptr)
  184. {
  185. delete m_image;
  186. m_image = nullptr;
  187. }
  188. /* 如果没有图片,这个函数会阻塞 */
  189. m_image = m_decodeVedio->getOneImageUntilHave();
  190. if(m_image)
  191. {
  192. if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight)
  193. {
  194. *m_image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  195. }
  196. // SPDLOG_DEBUG("绘制画面...");
  197. update();
  198. }
  199. m_decodeVedio->wakeUpCondQueueNoEmpty();
  200. }
  201. }
  202. /* 取出画面,刷新UI */
  203. void VideoPlayer::do_refreshUI()
  204. {
  205. if(m_decodeVedio != nullptr)
  206. {
  207. // SPDLOG_DEBUG("取出一帧图片...");
  208. /* 删除上一帧图片 */
  209. if(m_image != nullptr)
  210. {
  211. delete m_image;
  212. m_image = nullptr;
  213. }
  214. m_image = m_decodeVedio->getOneImage();
  215. if(m_image)
  216. {
  217. if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight)
  218. {
  219. *m_image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  220. }
  221. // SPDLOG_DEBUG("绘制画面...");
  222. update();
  223. }
  224. m_decodeVedio->wakeUpCondQueueNoEmpty();
  225. }
  226. }
  227. /* 通过信号刷新第一张图片 */
  228. void VideoPlayer::do_refreshOneUI()
  229. {
  230. if(!m_semRefresh->tryAcquire(1))
  231. {
  232. return;
  233. }
  234. /* 取出第一张 */
  235. if(m_decodeVedio != nullptr)
  236. {
  237. // SPDLOG_DEBUG("取出一帧图片...");
  238. /* 删除上一帧图片 */
  239. if(m_image != nullptr)
  240. {
  241. delete m_image;
  242. m_image = nullptr;
  243. }
  244. m_image = m_decodeVedio->getOneImage();
  245. if(m_image)
  246. {
  247. if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight)
  248. {
  249. *m_image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  250. }
  251. // SPDLOG_DEBUG("绘制画面...");
  252. update();
  253. }
  254. m_decodeVedio->wakeUpCondQueueNoEmpty();
  255. }
  256. }