opengl_video_widget.cpp 21 KB

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