opengl_video_widget.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. #include "opengl_video_widget.h"
  2. #include <QDebug>
  3. #include <QFont>
  4. #include <QFontMetrics>
  5. #include <QPainter>
  6. #include <QTimer>
  7. OpenGLVideoWidget::OpenGLVideoWidget(QWidget* parent)
  8. : QOpenGLWidget(parent)
  9. , m_program(nullptr)
  10. , m_textureId(0)
  11. , m_frameData(nullptr)
  12. , m_frameWidth(0)
  13. , m_frameHeight(0)
  14. , m_frameFormat(0)
  15. , m_frameUpdated(false)
  16. , m_initialized(false)
  17. , m_keepAspectRatio(true)
  18. , m_gray(false)
  19. , m_threshold(false)
  20. , m_thresholdValue(0.5f)
  21. , m_blur(false)
  22. , m_blurRadius(1.0f)
  23. , m_reverse(false)
  24. , m_colorReduce(false)
  25. , m_colorReduceLevel(0)
  26. , m_gamma(false)
  27. , m_gammaValue(1.0f)
  28. , m_contrastBright(false)
  29. , m_contrast(1.0f)
  30. , m_brightness(0.0f)
  31. , m_mirror(false)
  32. , m_noVideoTip(QStringLiteral("视频未开始"))
  33. , m_tipTexture(0)
  34. , m_tipAngle(0.0f)
  35. {
  36. // 设置顶点坐标
  37. m_vertices[0] = -1.0f; m_vertices[1] = -1.0f;
  38. m_vertices[2] = 1.0f; m_vertices[3] = -1.0f;
  39. m_vertices[4] = -1.0f; m_vertices[5] = 1.0f;
  40. m_vertices[6] = 1.0f; m_vertices[7] = 1.0f;
  41. // 设置纹理坐标
  42. m_texCoords[0] = 0.0f; m_texCoords[1] = 1.0f;
  43. m_texCoords[2] = 1.0f; m_texCoords[3] = 1.0f;
  44. m_texCoords[4] = 0.0f; m_texCoords[5] = 0.0f;
  45. m_texCoords[6] = 1.0f; m_texCoords[7] = 0.0f;
  46. // 3D文本旋转动画定时器
  47. m_tipTimer = new QTimer(this);
  48. connect(m_tipTimer, &QTimer::timeout, this, [this](){
  49. m_tipAngle += 2.0f;
  50. if (m_tipAngle > 360.0f) m_tipAngle -= 360.0f;
  51. update();
  52. });
  53. m_tipTimer->start(30);
  54. // 初始化时生成一次纹理,防止初次显示时未生成
  55. m_frameData = nullptr;
  56. m_frameUpdated = false;
  57. m_tipImage = QImage();
  58. m_tipTexture = 0;
  59. }
  60. OpenGLVideoWidget::~OpenGLVideoWidget()
  61. {
  62. Close();
  63. }
  64. bool OpenGLVideoWidget::Open(unsigned int width, unsigned int height)
  65. {
  66. QMutexLocker locker(&m_mutex);
  67. m_frameWidth = width;
  68. m_frameHeight = height;
  69. // 如果已经有数据,释放它
  70. if (m_frameData) {
  71. delete[] m_frameData;
  72. }
  73. // 分配新的内存
  74. m_frameData = new unsigned char[width * height * 4]; // RGBA格式
  75. memset(m_frameData, 0, width * height * 4);
  76. return true;
  77. }
  78. void OpenGLVideoWidget::Close()
  79. {
  80. makeCurrent();
  81. if (m_textureId) {
  82. glDeleteTextures(1, &m_textureId);
  83. m_textureId = 0;
  84. }
  85. if (m_program) {
  86. delete m_program;
  87. m_program = nullptr;
  88. }
  89. doneCurrent();
  90. // 释放帧数据
  91. QMutexLocker locker(&m_mutex);
  92. if (m_frameData) {
  93. delete[] m_frameData;
  94. m_frameData = nullptr;
  95. }
  96. m_frameWidth = 0;
  97. m_frameHeight = 0;
  98. m_frameUpdated = false;
  99. m_initialized = false;
  100. }
  101. void OpenGLVideoWidget::initializeGL()
  102. {
  103. initializeOpenGLFunctions();
  104. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  105. // 创建统一shader,支持多特效
  106. if (m_program) { delete m_program; m_program = nullptr; }
  107. m_program = new QOpenGLShaderProgram();
  108. m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
  109. "attribute vec2 vertexIn;\n"
  110. "attribute vec2 textureIn;\n"
  111. "varying vec2 textureOut;\n"
  112. "void main(void)\n"
  113. "{\n"
  114. " gl_Position = vec4(vertexIn, 0.0, 1.0);\n"
  115. " textureOut = textureIn;\n"
  116. "}\n");
  117. m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
  118. R"Raw(
  119. varying vec2 textureOut;
  120. uniform sampler2D texture;
  121. uniform bool uGray;
  122. uniform bool uThreshold;
  123. uniform float uThresholdValue;
  124. uniform bool uBlur;
  125. uniform float uBlurRadius;
  126. uniform bool uReverse;
  127. uniform bool uColorReduce;
  128. uniform int uColorReduceLevel;
  129. uniform bool uGamma;
  130. uniform float uGammaValue;
  131. uniform bool uContrastBright;
  132. uniform float uContrast;
  133. uniform float uBrightness;
  134. uniform bool uMirror;
  135. void main(void)
  136. {
  137. vec2 uv = textureOut;
  138. if (uMirror) {
  139. uv.x = 1.0 - uv.x;
  140. }
  141. vec4 color = texture2D(texture, uv);
  142. // 灰度
  143. if (uGray) {
  144. float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
  145. color = vec4(gray, gray, gray, color.a);
  146. }
  147. // 二值化
  148. if (uThreshold) {
  149. float v = dot(color.rgb, vec3(0.299, 0.587, 0.114));
  150. float th = v > uThresholdValue ? 1.0 : 0.0;
  151. color = vec4(th, th, th, color.a);
  152. }
  153. // 简单3x3均值模糊
  154. if (uBlur) {
  155. vec2 tex_offset = vec2(1.0) / vec2(textureSize2D(texture, 0));
  156. vec4 sum = vec4(0.0);
  157. for (int dx = -1; dx <= 1; ++dx)
  158. for (int dy = -1; dy <= 1; ++dy)
  159. sum += texture2D(texture, uv + vec2(dx, dy) * tex_offset * uBlurRadius);
  160. color = sum / 9.0;
  161. }
  162. // 反色
  163. if (uReverse) {
  164. color.rgb = vec3(1.0) - color.rgb;
  165. }
  166. // 色彩减少
  167. if (uColorReduce) {
  168. color.rgb = floor(color.rgb * float(uColorReduceLevel)) / float(uColorReduceLevel);
  169. }
  170. // 伽马
  171. if (uGamma) {
  172. color.rgb = pow(color.rgb, vec3(1.0 / uGammaValue));
  173. }
  174. // 对比度/亮度
  175. if (uContrastBright) {
  176. color.rgb = color.rgb * uContrast + uBrightness;
  177. }
  178. gl_FragColor = color;
  179. }
  180. )Raw");
  181. m_program->bindAttributeLocation("vertexIn", 0);
  182. m_program->bindAttributeLocation("textureIn", 1);
  183. m_program->link();
  184. // 创建纹理
  185. glGenTextures(1, &m_textureId);
  186. glBindTexture(GL_TEXTURE_2D, m_textureId);
  187. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  188. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  189. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  190. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  191. glBindTexture(GL_TEXTURE_2D, 0);
  192. m_initialized = true;
  193. }
  194. void OpenGLVideoWidget::resizeGL(int width, int height)
  195. {
  196. glViewport(0, 0, width, height);
  197. }
  198. // 文本转OpenGL纹理
  199. void OpenGLVideoWidget::updateTipTexture()
  200. {
  201. QFont font;
  202. font.setPointSize(48);
  203. font.setBold(true);
  204. QFontMetrics fm(font);
  205. int w = fm.horizontalAdvance(m_noVideoTip) + 40;
  206. int h = fm.height() + 40;
  207. QImage img(w, h, QImage::Format_ARGB32_Premultiplied);
  208. img.fill(Qt::transparent);
  209. QPainter p(&img);
  210. p.setFont(font);
  211. p.setPen(Qt::white);
  212. p.setRenderHint(QPainter::Antialiasing);
  213. p.drawText(img.rect(), Qt::AlignCenter, m_noVideoTip);
  214. p.end();
  215. m_tipImage = img;
  216. if (m_tipTexture) {
  217. glDeleteTextures(1, &m_tipTexture);
  218. }
  219. glGenTextures(1, &m_tipTexture);
  220. glBindTexture(GL_TEXTURE_2D, m_tipTexture);
  221. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, img.bits());
  222. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  223. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  224. glBindTexture(GL_TEXTURE_2D, 0);
  225. }
  226. // 3D绘制方法
  227. void OpenGLVideoWidget::drawNoVideoTip3D()
  228. {
  229. glClearColor(0, 0, 0, 1);
  230. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  231. glEnable(GL_DEPTH_TEST);
  232. glEnable(GL_TEXTURE_2D);
  233. glBindTexture(GL_TEXTURE_2D, m_tipTexture);
  234. glMatrixMode(GL_PROJECTION);
  235. glLoadIdentity();
  236. float aspect = float(width()) / float(height());
  237. glOrtho(-aspect, aspect, -1, 1, -10, 10);
  238. glMatrixMode(GL_MODELVIEW);
  239. glLoadIdentity();
  240. glTranslatef(0, 0, 0);
  241. glRotatef(m_tipAngle, 0, 1, 0);
  242. float w = float(m_tipImage.width()) / width();
  243. float h = float(m_tipImage.height()) / height();
  244. glBegin(GL_QUADS);
  245. glTexCoord2f(0, 1); glVertex3f(-w, -h, 0);
  246. glTexCoord2f(1, 1); glVertex3f(w, -h, 0);
  247. glTexCoord2f(1, 0); glVertex3f(w, h, 0);
  248. glTexCoord2f(0, 0); glVertex3f(-w, h, 0);
  249. glEnd();
  250. glBindTexture(GL_TEXTURE_2D, 0);
  251. glDisable(GL_TEXTURE_2D);
  252. glDisable(GL_DEPTH_TEST);
  253. }
  254. void OpenGLVideoWidget::paintGL()
  255. {
  256. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  257. QMutexLocker locker(&m_mutex);
  258. if (!m_frameData || m_frameWidth <= 0 || m_frameHeight <= 0 || !m_frameUpdated) {
  259. if (m_tipTexture == 0) updateTipTexture();
  260. drawNoVideoTip3D();
  261. return;
  262. }
  263. // 绑定纹理并更新数据
  264. glBindTexture(GL_TEXTURE_2D, m_textureId);
  265. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_frameWidth, m_frameHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_frameData);
  266. m_program->bind();
  267. m_program->setUniformValue("texture", 0);
  268. m_program->setUniformValue("uGray", m_gray);
  269. m_program->setUniformValue("uThreshold", m_threshold);
  270. m_program->setUniformValue("uThresholdValue", m_thresholdValue);
  271. m_program->setUniformValue("uBlur", m_blur);
  272. m_program->setUniformValue("uBlurRadius", m_blurRadius);
  273. m_program->setUniformValue("uReverse", m_reverse);
  274. m_program->setUniformValue("uColorReduce", m_colorReduce);
  275. m_program->setUniformValue("uColorReduceLevel", m_colorReduceLevel);
  276. m_program->setUniformValue("uGamma", m_gamma);
  277. m_program->setUniformValue("uGammaValue", m_gammaValue);
  278. m_program->setUniformValue("uContrastBright", m_contrastBright);
  279. m_program->setUniformValue("uContrast", m_contrast);
  280. m_program->setUniformValue("uBrightness", m_brightness);
  281. m_program->setUniformValue("uMirror", m_mirror);
  282. m_program->enableAttributeArray(0);
  283. m_program->enableAttributeArray(1);
  284. m_program->setAttributeArray(0, m_vertices, 2);
  285. m_program->setAttributeArray(1, m_texCoords, 2);
  286. // 保持比例
  287. if (m_keepAspectRatio) {
  288. QSize widgetSize = size();
  289. double widgetRatio = double(widgetSize.width()) / widgetSize.height();
  290. double videoRatio = double(m_frameWidth) / m_frameHeight;
  291. int x = 0, y = 0, w = widgetSize.width(), h = widgetSize.height();
  292. if (widgetRatio > videoRatio) {
  293. w = int(h * videoRatio);
  294. x = (widgetSize.width() - w) / 2;
  295. } else {
  296. h = int(w / videoRatio);
  297. y = (widgetSize.height() - h) / 2;
  298. }
  299. glViewport(x, y, w, h);
  300. } else {
  301. glViewport(0, 0, width(), height());
  302. }
  303. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  304. m_program->disableAttributeArray(0);
  305. m_program->disableAttributeArray(1);
  306. m_program->release();
  307. glBindTexture(GL_TEXTURE_2D, 0);
  308. }
  309. void OpenGLVideoWidget::updateFrame(const VideoFrame& frame)
  310. {
  311. if (!frame.data || frame.width <= 0 || frame.height <= 0)
  312. return;
  313. QMutexLocker locker(&m_mutex);
  314. // 如果尺寸变化,重新分配内存
  315. if (m_frameWidth != frame.width || m_frameHeight != frame.height) {
  316. if (m_frameData) {
  317. delete[] m_frameData;
  318. }
  319. m_frameWidth = frame.width;
  320. m_frameHeight = frame.height;
  321. m_frameData = new unsigned char[m_frameWidth * m_frameHeight * 4]; // RGBA格式
  322. }
  323. // 复制帧数据
  324. memcpy(m_frameData, frame.data, m_frameWidth * m_frameHeight * 4);
  325. m_frameUpdated = true;
  326. // 请求重绘
  327. update();
  328. }
  329. bool OpenGLVideoWidget::convertFromAVFrame(AVFrame* frame)
  330. {
  331. if (!frame || frame->width <= 0 || frame->height <= 0)
  332. return false;
  333. QMutexLocker locker(&m_mutex);
  334. // 如果尺寸变化,重新分配内存
  335. if (m_frameWidth != frame->width || m_frameHeight != frame->height) {
  336. if (m_frameData) {
  337. delete[] m_frameData;
  338. }
  339. m_frameWidth = frame->width;
  340. m_frameHeight = frame->height;
  341. m_frameData = new unsigned char[m_frameWidth * m_frameHeight * 4]; // RGBA格式
  342. }
  343. // 根据不同的像素格式进行转换
  344. switch (frame->format) {
  345. case AV_PIX_FMT_RGBA: {
  346. // 直接复制RGBA数据
  347. for (int y = 0; y < frame->height; y++) {
  348. memcpy(m_frameData + y * m_frameWidth * 4,
  349. frame->data[0] + y * frame->linesize[0],
  350. frame->width * 4);
  351. }
  352. } break;
  353. case AV_PIX_FMT_RGB24: {
  354. // RGB24转RGBA
  355. for (int y = 0; y < frame->height; y++) {
  356. uint8_t* src = frame->data[0] + y * frame->linesize[0];
  357. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  358. for (int x = 0; x < frame->width; x++) {
  359. *dst++ = *src++; // R
  360. *dst++ = *src++; // G
  361. *dst++ = *src++; // B
  362. *dst++ = 255; // A
  363. }
  364. }
  365. } break;
  366. case AV_PIX_FMT_BGR0:
  367. case AV_PIX_FMT_BGRA: {
  368. // BGRA转RGBA
  369. for (int y = 0; y < frame->height; y++) {
  370. uint8_t* src = frame->data[0] + y * frame->linesize[0];
  371. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  372. for (int x = 0; x < frame->width; x++) {
  373. uint8_t b = *src++;
  374. uint8_t g = *src++;
  375. uint8_t r = *src++;
  376. uint8_t a = *src++;
  377. *dst++ = r;
  378. *dst++ = g;
  379. *dst++ = b;
  380. *dst++ = a;
  381. }
  382. }
  383. } break;
  384. case AV_PIX_FMT_BGR24: {
  385. // BGR24转RGBA
  386. for (int y = 0; y < frame->height; y++) {
  387. uint8_t* src = frame->data[0] + y * frame->linesize[0];
  388. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  389. for (int x = 0; x < frame->width; x++) {
  390. uint8_t b = *src++;
  391. uint8_t g = *src++;
  392. uint8_t r = *src++;
  393. *dst++ = r; // R
  394. *dst++ = g; // G
  395. *dst++ = b; // B
  396. *dst++ = 255; // A (设为不透明)
  397. }
  398. }
  399. } break;
  400. case AV_PIX_FMT_YUV420P: // 添加对YUV420P格式的支持
  401. {
  402. // YUV420P转RGBA
  403. for (int y = 0; y < frame->height; y++) {
  404. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  405. for (int x = 0; x < frame->width; x++) {
  406. int Y = frame->data[0][y * frame->linesize[0] + x];
  407. int U = frame->data[1][(y / 2) * frame->linesize[1] + (x / 2)];
  408. int V = frame->data[2][(y / 2) * frame->linesize[2] + (x / 2)];
  409. // YUV转RGB公式
  410. int C = Y - 16;
  411. int D = U - 128;
  412. int E = V - 128;
  413. int R = (298 * C + 409 * E + 128) >> 8;
  414. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  415. int B = (298 * C + 516 * D + 128) >> 8;
  416. // 限制RGB值在0-255范围内
  417. R = R < 0 ? 0 : (R > 255 ? 255 : R);
  418. G = G < 0 ? 0 : (G > 255 ? 255 : G);
  419. B = B < 0 ? 0 : (B > 255 ? 255 : B);
  420. *dst++ = R; // R
  421. *dst++ = G; // G
  422. *dst++ = B; // B
  423. *dst++ = 255; // A
  424. }
  425. }
  426. } break;
  427. case AV_PIX_FMT_NV12: {
  428. // NV12转RGBA
  429. for (int y = 0; y < frame->height; y++) {
  430. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  431. for (int x = 0; x < frame->width; x++) {
  432. int Y = frame->data[0][y * frame->linesize[0] + x];
  433. int U = frame->data[1][(y / 2) * frame->linesize[1] + (x / 2) * 2];
  434. int V = frame->data[1][(y / 2) * frame->linesize[1] + (x / 2) * 2 + 1];
  435. // YUV转RGB公式
  436. int C = Y - 16;
  437. int D = U - 128;
  438. int E = V - 128;
  439. int R = (298 * C + 409 * E + 128) >> 8;
  440. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  441. int B = (298 * C + 516 * D + 128) >> 8;
  442. // 限制RGB值在0-255范围内
  443. R = R < 0 ? 0 : (R > 255 ? 255 : R);
  444. G = G < 0 ? 0 : (G > 255 ? 255 : G);
  445. B = B < 0 ? 0 : (B > 255 ? 255 : B);
  446. *dst++ = R; // R
  447. *dst++ = G; // G
  448. *dst++ = B; // B
  449. *dst++ = 255; // A
  450. }
  451. }
  452. } break;
  453. default:
  454. // 对于其他格式,可以考虑使用FFmpeg的sws_scale函数
  455. qDebug() << "Unsupported pixel format:" << frame->format;
  456. return false;
  457. }
  458. m_frameUpdated = true;
  459. update();
  460. return true;
  461. }
  462. bool OpenGLVideoWidget::Render(AVFrame* frame)
  463. {
  464. if (!m_initialized && isValid()) {
  465. makeCurrent();
  466. initializeGL();
  467. doneCurrent();
  468. }
  469. if (!frame) {
  470. update(); // 仅刷新显示
  471. return true;
  472. }
  473. return convertFromAVFrame(frame);
  474. }
  475. void OpenGLVideoWidget::clearFrame()
  476. {
  477. QMutexLocker locker(&m_mutex);
  478. m_frameUpdated = false;
  479. update();
  480. }
  481. void OpenGLVideoWidget::setGray(bool on) {
  482. if (m_gray != on) { m_gray = on; update(); }
  483. }
  484. void OpenGLVideoWidget::setThreshold(bool on, float value) {
  485. if (m_threshold != on || m_thresholdValue != value) { m_threshold = on; m_thresholdValue = value; update(); }
  486. }
  487. void OpenGLVideoWidget::setBlur(bool on, float radius) {
  488. if (m_blur != on || m_blurRadius != radius) { m_blur = on; m_blurRadius = radius; update(); }
  489. }
  490. void OpenGLVideoWidget::setReverse(bool on) {
  491. if (m_reverse != on) { m_reverse = on; update(); }
  492. }
  493. void OpenGLVideoWidget::setColorReduce(bool on, int level) {
  494. if (m_colorReduce != on || m_colorReduceLevel != level) { m_colorReduce = on; m_colorReduceLevel = level; update(); }
  495. }
  496. void OpenGLVideoWidget::setGamma(bool on, float gamma) {
  497. if (m_gamma != on || m_gammaValue != gamma) { m_gamma = on; m_gammaValue = gamma; update(); }
  498. }
  499. void OpenGLVideoWidget::setContrastBright(bool on, float contrast, float brightness) {
  500. if (m_contrastBright != on || m_contrast != contrast || m_brightness != brightness) {
  501. m_contrastBright = on; m_contrast = contrast; m_brightness = brightness; update();
  502. }
  503. }
  504. void OpenGLVideoWidget::setMirror(bool on) {
  505. if (m_mirror != on) { m_mirror = on; update(); }
  506. }
  507. void OpenGLVideoWidget::setNoVideoTip(const QString& tip)
  508. {
  509. if (m_noVideoTip != tip) {
  510. m_noVideoTip = tip;
  511. updateTipTexture();
  512. update();
  513. }
  514. }
  515. void OpenGLVideoWidget::showEndTip(const QString& tip)
  516. {
  517. QMutexLocker locker(&m_mutex);
  518. m_noVideoTip = tip;
  519. if (m_tipTexture) {
  520. glDeleteTextures(1, &m_tipTexture);
  521. m_tipTexture = 0;
  522. }
  523. m_frameUpdated = false;
  524. if (m_frameData) {
  525. delete[] m_frameData;
  526. m_frameData = nullptr;
  527. }
  528. updateTipTexture();
  529. update();
  530. }