opengl_video_widget.cpp 19 KB

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