avopenglwidget.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. #include "avopenglwidget.h"
  2. #include <QDebug>
  3. #include <QFont>
  4. #include <QFontMetrics>
  5. #include <QPainter>
  6. #include <QTimer>
  7. #include <climits>
  8. #include <new>
  9. AVOpenGLWidget::AVOpenGLWidget(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. // 设置OpenGL组件的尺寸策略,确保有足够的显示空间
  39. setMinimumSize(320, 240);
  40. setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  41. // setAttribute(Qt::WA_NoSystemBackground, true);
  42. // setAttribute(Qt::WA_OpaquePaintEvent, true);
  43. // setAutoFillBackground(false);
  44. // 设置顶点坐标
  45. m_vertices[0] = -1.0f;
  46. m_vertices[1] = -1.0f;
  47. m_vertices[2] = 1.0f;
  48. m_vertices[3] = -1.0f;
  49. m_vertices[4] = -1.0f;
  50. m_vertices[5] = 1.0f;
  51. m_vertices[6] = 1.0f;
  52. m_vertices[7] = 1.0f;
  53. // 设置纹理坐标
  54. m_texCoords[0] = 0.0f;
  55. m_texCoords[1] = 1.0f;
  56. m_texCoords[2] = 1.0f;
  57. m_texCoords[3] = 1.0f;
  58. m_texCoords[4] = 0.0f;
  59. m_texCoords[5] = 0.0f;
  60. m_texCoords[6] = 1.0f;
  61. m_texCoords[7] = 0.0f;
  62. // 3D文本旋转动画定时器
  63. m_tipTimer = new QTimer(this);
  64. connect(m_tipTimer, &QTimer::timeout, this, [this]() {
  65. m_tipAngle += 2.0f;
  66. if (m_tipAngle > 360.0f)
  67. m_tipAngle -= 360.0f;
  68. update();
  69. });
  70. m_tipTimer->start(30);
  71. // 初始化时生成一次纹理,防止初次显示时未生成
  72. m_frameData = nullptr;
  73. m_frameUpdated = false;
  74. m_tipImage = QImage();
  75. m_tipTexture = 0;
  76. }
  77. AVOpenGLWidget::~AVOpenGLWidget()
  78. {
  79. Close();
  80. }
  81. bool AVOpenGLWidget::Open(unsigned int width, unsigned int height)
  82. {
  83. QMutexLocker locker(&m_mutex);
  84. m_frameWidth = width;
  85. m_frameHeight = height;
  86. // 如果已经有数据,释放它
  87. if (m_frameData) {
  88. delete[] m_frameData;
  89. }
  90. // 分配新的内存
  91. m_frameData = new unsigned char[width * height * 4]; // RGBA格式
  92. memset(m_frameData, 0, width * height * 4);
  93. return true;
  94. }
  95. void AVOpenGLWidget::Close()
  96. {
  97. makeCurrent();
  98. if (m_textureId) {
  99. glDeleteTextures(1, &m_textureId);
  100. m_textureId = 0;
  101. }
  102. if (m_program) {
  103. delete m_program;
  104. m_program = nullptr;
  105. }
  106. doneCurrent();
  107. // 释放帧数据
  108. QMutexLocker locker(&m_mutex);
  109. if (m_frameData) {
  110. delete[] m_frameData;
  111. m_frameData = nullptr;
  112. }
  113. m_frameWidth = 0;
  114. m_frameHeight = 0;
  115. m_frameUpdated = false;
  116. m_initialized = false;
  117. }
  118. void AVOpenGLWidget::initializeGL()
  119. {
  120. initializeOpenGLFunctions();
  121. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  122. // 创建统一shader,支持多特效
  123. if (m_program) {
  124. delete m_program;
  125. m_program = nullptr;
  126. }
  127. m_program = new QOpenGLShaderProgram();
  128. m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
  129. "attribute vec2 vertexIn;\n"
  130. "attribute vec2 textureIn;\n"
  131. "varying vec2 textureOut;\n"
  132. "void main(void)\n"
  133. "{\n"
  134. " gl_Position = vec4(vertexIn, 0.0, 1.0);\n"
  135. " textureOut = textureIn;\n"
  136. "}\n");
  137. m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
  138. R"Raw(
  139. varying vec2 textureOut;
  140. uniform sampler2D texture;
  141. uniform vec2 uTextureSize;
  142. uniform bool uGray;
  143. uniform bool uThreshold;
  144. uniform float uThresholdValue;
  145. uniform bool uBlur;
  146. uniform float uBlurRadius;
  147. uniform bool uReverse;
  148. uniform bool uColorReduce;
  149. uniform int uColorReduceLevel;
  150. uniform bool uGamma;
  151. uniform float uGammaValue;
  152. uniform bool uContrastBright;
  153. uniform float uContrast;
  154. uniform float uBrightness;
  155. uniform bool uMirror;
  156. void main(void)
  157. {
  158. vec2 uv = textureOut;
  159. if (uMirror) {
  160. uv.x = 1.0 - uv.x;
  161. }
  162. vec4 color = texture2D(texture, uv);
  163. // 灰度
  164. if (uGray) {
  165. float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
  166. color = vec4(gray, gray, gray, color.a);
  167. }
  168. // 二值化
  169. if (uThreshold) {
  170. float v = dot(color.rgb, vec3(0.299, 0.587, 0.114));
  171. float th = v > uThresholdValue ? 1.0 : 0.0;
  172. color = vec4(th, th, th, color.a);
  173. }
  174. // 简单3x3均值模糊
  175. if (uBlur) {
  176. vec2 tex_offset = vec2(1.0) / uTextureSize;
  177. vec4 sum = vec4(0.0);
  178. for (int dx = -1; dx <= 1; ++dx)
  179. for (int dy = -1; dy <= 1; ++dy)
  180. sum += texture2D(texture, uv + vec2(dx, dy) * tex_offset * uBlurRadius);
  181. color = sum / 9.0;
  182. }
  183. // 反色
  184. if (uReverse) {
  185. color.rgb = vec3(1.0) - color.rgb;
  186. }
  187. // 色彩减少
  188. if (uColorReduce) {
  189. color.rgb = floor(color.rgb * float(uColorReduceLevel)) / float(uColorReduceLevel);
  190. }
  191. // 伽马
  192. if (uGamma) {
  193. color.rgb = pow(color.rgb, vec3(1.0 / uGammaValue));
  194. }
  195. // 对比度/亮度
  196. if (uContrastBright) {
  197. color.rgb = color.rgb * uContrast + uBrightness;
  198. }
  199. gl_FragColor = color;
  200. }
  201. )Raw");
  202. m_program->bindAttributeLocation("vertexIn", 0);
  203. m_program->bindAttributeLocation("textureIn", 1);
  204. m_program->link();
  205. // 创建纹理
  206. glGenTextures(1, &m_textureId);
  207. glBindTexture(GL_TEXTURE_2D, m_textureId);
  208. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  209. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  210. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  211. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  212. glBindTexture(GL_TEXTURE_2D, 0);
  213. m_initialized = true;
  214. }
  215. void AVOpenGLWidget::resizeGL(int width, int height)
  216. {
  217. glViewport(0, 0, width, height);
  218. }
  219. // 文本转OpenGL纹理
  220. void AVOpenGLWidget::updateTipTexture()
  221. {
  222. // 在进行任何GL调用前,确保上下文已当前
  223. bool needMakeCurrent = (QOpenGLContext::currentContext() != context());
  224. if (needMakeCurrent) makeCurrent();
  225. QFont font;
  226. font.setPointSize(48);
  227. font.setBold(true);
  228. QFontMetrics fm(font);
  229. int w = fm.horizontalAdvance(m_noVideoTip) + 40;
  230. int h = fm.height() + 40;
  231. QImage img(w, h, QImage::Format_ARGB32_Premultiplied);
  232. img.fill(Qt::transparent);
  233. QPainter p(&img);
  234. p.setFont(font);
  235. p.setPen(Qt::white);
  236. p.setRenderHint(QPainter::Antialiasing);
  237. p.drawText(img.rect(), Qt::AlignCenter, m_noVideoTip);
  238. p.end();
  239. m_tipImage = img;
  240. if (m_tipTexture) {
  241. glDeleteTextures(1, &m_tipTexture);
  242. }
  243. glGenTextures(1, &m_tipTexture);
  244. glActiveTexture(GL_TEXTURE0);
  245. glBindTexture(GL_TEXTURE_2D, m_tipTexture);
  246. glTexImage2D(GL_TEXTURE_2D,
  247. 0,
  248. GL_RGBA,
  249. img.width(),
  250. img.height(),
  251. 0,
  252. GL_BGRA,
  253. GL_UNSIGNED_BYTE,
  254. img.bits());
  255. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  256. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  257. glBindTexture(GL_TEXTURE_2D, 0);
  258. if (needMakeCurrent) doneCurrent();
  259. }
  260. // 3D绘制方法
  261. void AVOpenGLWidget::drawNoVideoTip3D()
  262. {
  263. glClearColor(0, 0, 0, 1);
  264. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  265. glEnable(GL_DEPTH_TEST);
  266. glEnable(GL_TEXTURE_2D);
  267. glActiveTexture(GL_TEXTURE0);
  268. glBindTexture(GL_TEXTURE_2D, m_tipTexture);
  269. glMatrixMode(GL_PROJECTION);
  270. glLoadIdentity();
  271. float aspect = float(width()) / float(height());
  272. glOrtho(-aspect, aspect, -1, 1, -10, 10);
  273. glMatrixMode(GL_MODELVIEW);
  274. glLoadIdentity();
  275. glTranslatef(0, 0, 0);
  276. glRotatef(m_tipAngle, 0, 1, 0);
  277. float w = float(m_tipImage.width()) / width();
  278. float h = float(m_tipImage.height()) / height();
  279. glBegin(GL_QUADS);
  280. glTexCoord2f(0, 1);
  281. glVertex3f(-w, -h, 0);
  282. glTexCoord2f(1, 1);
  283. glVertex3f(w, -h, 0);
  284. glTexCoord2f(1, 0);
  285. glVertex3f(w, h, 0);
  286. glTexCoord2f(0, 0);
  287. glVertex3f(-w, h, 0);
  288. glEnd();
  289. glBindTexture(GL_TEXTURE_2D, 0);
  290. glDisable(GL_TEXTURE_2D);
  291. glDisable(GL_DEPTH_TEST);
  292. }
  293. void AVOpenGLWidget::paintGL()
  294. {
  295. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  296. QMutexLocker locker(&m_mutex);
  297. if (!m_frameData || m_frameWidth <= 0 || m_frameHeight <= 0 || !m_frameUpdated) {
  298. if (m_tipTexture == 0)
  299. updateTipTexture();
  300. drawNoVideoTip3D();
  301. return;
  302. }
  303. // 绑定纹理并更新数据
  304. glActiveTexture(GL_TEXTURE0);
  305. glBindTexture(GL_TEXTURE_2D, m_textureId);
  306. // 设置像素对齐,避免部分驱动在行对齐处理上造成花屏
  307. GLint oldUnpackAlign = 4;
  308. glGetIntegerv(GL_UNPACK_ALIGNMENT, &oldUnpackAlign);
  309. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  310. // 仅当尺寸变化时重新定义纹理,否则使用 glTexSubImage2D 提升稳定性与性能
  311. if (m_texWidth != m_frameWidth || m_texHeight != m_frameHeight) {
  312. glTexImage2D(GL_TEXTURE_2D,
  313. 0,
  314. GL_RGBA,
  315. m_frameWidth,
  316. m_frameHeight,
  317. 0,
  318. GL_RGBA,
  319. GL_UNSIGNED_BYTE,
  320. m_frameData);
  321. m_texWidth = m_frameWidth;
  322. m_texHeight = m_frameHeight;
  323. } else {
  324. glTexSubImage2D(GL_TEXTURE_2D,
  325. 0,
  326. 0,
  327. 0,
  328. m_frameWidth,
  329. m_frameHeight,
  330. GL_RGBA,
  331. GL_UNSIGNED_BYTE,
  332. m_frameData);
  333. }
  334. // 还原像素对齐
  335. glPixelStorei(GL_UNPACK_ALIGNMENT, oldUnpackAlign);
  336. m_program->bind();
  337. m_program->setUniformValue("texture", 0);
  338. m_program->setUniformValue("uTextureSize", QVector2D(m_frameWidth, m_frameHeight));
  339. m_program->setUniformValue("uGray", m_gray);
  340. m_program->setUniformValue("uThreshold", m_threshold);
  341. m_program->setUniformValue("uThresholdValue", m_thresholdValue);
  342. m_program->setUniformValue("uBlur", m_blur);
  343. m_program->setUniformValue("uBlurRadius", m_blurRadius);
  344. m_program->setUniformValue("uReverse", m_reverse);
  345. m_program->setUniformValue("uColorReduce", m_colorReduce);
  346. m_program->setUniformValue("uColorReduceLevel", m_colorReduceLevel);
  347. m_program->setUniformValue("uGamma", m_gamma);
  348. m_program->setUniformValue("uGammaValue", m_gammaValue);
  349. m_program->setUniformValue("uContrastBright", m_contrastBright);
  350. m_program->setUniformValue("uContrast", m_contrast);
  351. m_program->setUniformValue("uBrightness", m_brightness);
  352. m_program->setUniformValue("uMirror", m_mirror);
  353. m_program->enableAttributeArray(0);
  354. m_program->enableAttributeArray(1);
  355. m_program->setAttributeArray(0, m_vertices, 2);
  356. m_program->setAttributeArray(1, m_texCoords, 2);
  357. // 保持比例
  358. if (m_keepAspectRatio) {
  359. QSize widgetSize = size();
  360. double widgetRatio = double(widgetSize.width()) / widgetSize.height();
  361. double videoRatio = double(m_frameWidth) / m_frameHeight;
  362. int x = 0, y = 0, w = widgetSize.width(), h = widgetSize.height();
  363. if (widgetRatio > videoRatio) {
  364. w = int(h * videoRatio);
  365. x = (widgetSize.width() - w) / 2;
  366. } else {
  367. h = int(w / videoRatio);
  368. y = (widgetSize.height() - h) / 2;
  369. }
  370. glViewport(x, y, w, h);
  371. } else {
  372. glViewport(0, 0, width(), height());
  373. }
  374. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  375. m_program->disableAttributeArray(0);
  376. m_program->disableAttributeArray(1);
  377. m_program->release();
  378. glBindTexture(GL_TEXTURE_2D, 0);
  379. }
  380. void AVOpenGLWidget::updateFrame(const AVOpenGLWidget::RGBAFrame& frame)
  381. {
  382. if (!frame.data || frame.width <= 0 || frame.height <= 0)
  383. return;
  384. QMutexLocker locker(&m_mutex);
  385. // 如果尺寸变化,重新分配内存
  386. if (m_frameWidth != frame.width || m_frameHeight != frame.height) {
  387. if (m_frameData) {
  388. delete[] m_frameData;
  389. m_frameData = nullptr;
  390. }
  391. m_frameWidth = frame.width;
  392. m_frameHeight = frame.height;
  393. // 检查内存分配大小是否合理
  394. size_t dataSize = static_cast<size_t>(m_frameWidth) * m_frameHeight * 4;
  395. if (dataSize > 0 && dataSize < SIZE_MAX / 4) {
  396. try {
  397. m_frameData = new unsigned char[dataSize]; // RGBA格式
  398. } catch (const std::bad_alloc&) {
  399. m_frameData = nullptr;
  400. return;
  401. }
  402. } else {
  403. return;
  404. }
  405. }
  406. // 确保m_frameData已正确分配
  407. if (!m_frameData) {
  408. return;
  409. }
  410. // 复制帧数据
  411. memcpy(m_frameData, frame.data, m_frameWidth * m_frameHeight * 4);
  412. m_frameUpdated = true;
  413. // 请求重绘
  414. update();
  415. }
  416. bool AVOpenGLWidget::convertFromAVFrame(AVFrame* frame)
  417. {
  418. if (!frame || frame->width <= 0 || frame->height <= 0 || !frame->data[0])
  419. return false;
  420. QMutexLocker locker(&m_mutex);
  421. // 如果尺寸变化,重新分配内存
  422. if (m_frameWidth != frame->width || m_frameHeight != frame->height) {
  423. if (m_frameData) {
  424. delete[] m_frameData;
  425. m_frameData = nullptr;
  426. }
  427. m_frameWidth = frame->width;
  428. m_frameHeight = frame->height;
  429. // 检查内存分配大小是否合理
  430. size_t dataSize = static_cast<size_t>(m_frameWidth) * m_frameHeight * 4;
  431. if (dataSize > 0 && dataSize < SIZE_MAX / 4) {
  432. try {
  433. m_frameData = new unsigned char[dataSize]; // RGBA格式
  434. } catch (const std::bad_alloc&) {
  435. m_frameData = nullptr;
  436. return false;
  437. }
  438. } else {
  439. return false;
  440. }
  441. }
  442. // 确保m_frameData已正确分配,即使尺寸没有变化
  443. if (!m_frameData) {
  444. // 尺寸没有变化但m_frameData为空,需要重新分配
  445. size_t dataSize = static_cast<size_t>(m_frameWidth) * m_frameHeight * 4;
  446. if (dataSize > 0 && dataSize < SIZE_MAX / 4) {
  447. try {
  448. m_frameData = new unsigned char[dataSize]; // RGBA格式
  449. } catch (const std::bad_alloc&) {
  450. m_frameData = nullptr;
  451. return false;
  452. }
  453. } else {
  454. return false;
  455. }
  456. }
  457. // 检查源数据是否有效(防止frame.data[0]为空字符或无效数据)
  458. if (!frame->data[0] || frame->linesize[0] <= 0) {
  459. qDebug() << "Invalid frame data or linesize";
  460. return false;
  461. }
  462. // 根据不同的像素格式进行转换
  463. switch (frame->format) {
  464. case AV_PIX_FMT_RGBA: {
  465. // 直接复制RGBA数据
  466. for (int y = 0; y < frame->height; y++) {
  467. memcpy(m_frameData + y * m_frameWidth * 4,
  468. frame->data[0] + y * frame->linesize[0],
  469. frame->width * 4);
  470. }
  471. } break;
  472. case AV_PIX_FMT_RGB24: {
  473. // RGB24转RGBA
  474. for (int y = 0; y < frame->height; y++) {
  475. uint8_t* src = frame->data[0] + y * frame->linesize[0];
  476. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  477. for (int x = 0; x < frame->width; x++) {
  478. *dst++ = *src++; // R
  479. *dst++ = *src++; // G
  480. *dst++ = *src++; // B
  481. *dst++ = 255; // A
  482. }
  483. }
  484. } break;
  485. case AV_PIX_FMT_BGR0:
  486. case AV_PIX_FMT_BGRA: {
  487. // BGRA转RGBA
  488. for (int y = 0; y < frame->height; y++) {
  489. uint8_t* src = frame->data[0] + y * frame->linesize[0];
  490. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  491. for (int x = 0; x < frame->width; x++) {
  492. uint8_t b = *src++;
  493. uint8_t g = *src++;
  494. uint8_t r = *src++;
  495. uint8_t a = *src++;
  496. *dst++ = r;
  497. *dst++ = g;
  498. *dst++ = b;
  499. *dst++ = a;
  500. }
  501. }
  502. } break;
  503. case AV_PIX_FMT_BGR24: {
  504. // BGR24转RGBA
  505. for (int y = 0; y < frame->height; y++) {
  506. uint8_t* src = frame->data[0] + y * frame->linesize[0];
  507. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  508. for (int x = 0; x < frame->width; x++) {
  509. uint8_t b = *src++;
  510. uint8_t g = *src++;
  511. uint8_t r = *src++;
  512. *dst++ = r; // R
  513. *dst++ = g; // G
  514. *dst++ = b; // B
  515. *dst++ = 255; // A (设为不透明)
  516. }
  517. }
  518. } break;
  519. case AV_PIX_FMT_YUV420P: // 添加对YUV420P格式的支持
  520. {
  521. // 检查YUV平面数据是否有效
  522. if (!frame->data[1] || !frame->data[2])
  523. return false;
  524. // YUV420P转RGBA
  525. for (int y = 0; y < frame->height; y++) {
  526. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  527. for (int x = 0; x < frame->width; x++) {
  528. int Y = frame->data[0][y * frame->linesize[0] + x];
  529. int U = frame->data[1][(y / 2) * frame->linesize[1] + (x / 2)];
  530. int V = frame->data[2][(y / 2) * frame->linesize[2] + (x / 2)];
  531. // YUV转RGB公式
  532. int C = Y - 16;
  533. int D = U - 128;
  534. int E = V - 128;
  535. int R = (298 * C + 409 * E + 128) >> 8;
  536. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  537. int B = (298 * C + 516 * D + 128) >> 8;
  538. // 限制RGB值在0-255范围内
  539. R = R < 0 ? 0 : (R > 255 ? 255 : R);
  540. G = G < 0 ? 0 : (G > 255 ? 255 : G);
  541. B = B < 0 ? 0 : (B > 255 ? 255 : B);
  542. *dst++ = R; // R
  543. *dst++ = G; // G
  544. *dst++ = B; // B
  545. *dst++ = 255; // A
  546. }
  547. }
  548. } break;
  549. case AV_PIX_FMT_NV12: {
  550. // 检查NV12平面数据是否有效
  551. if (!frame->data[1])
  552. return false;
  553. // NV12转RGBA
  554. for (int y = 0; y < frame->height; y++) {
  555. uint8_t* dst = m_frameData + y * m_frameWidth * 4;
  556. for (int x = 0; x < frame->width; x++) {
  557. int Y = frame->data[0][y * frame->linesize[0] + x];
  558. int U = frame->data[1][(y / 2) * frame->linesize[1] + (x / 2) * 2];
  559. int V = frame->data[1][(y / 2) * frame->linesize[1] + (x / 2) * 2 + 1];
  560. // YUV转RGB公式
  561. int C = Y - 16;
  562. int D = U - 128;
  563. int E = V - 128;
  564. int R = (298 * C + 409 * E + 128) >> 8;
  565. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  566. int B = (298 * C + 516 * D + 128) >> 8;
  567. // 限制RGB值在0-255范围内
  568. R = R < 0 ? 0 : (R > 255 ? 255 : R);
  569. G = G < 0 ? 0 : (G > 255 ? 255 : G);
  570. B = B < 0 ? 0 : (B > 255 ? 255 : B);
  571. *dst++ = R; // R
  572. *dst++ = G; // G
  573. *dst++ = B; // B
  574. *dst++ = 255; // A
  575. }
  576. }
  577. } break;
  578. default:
  579. // 对于其他格式,可以考虑使用FFmpeg的sws_scale函数
  580. qDebug() << "Unsupported pixel format:" << frame->format;
  581. return false;
  582. }
  583. m_frameUpdated = true;
  584. update();
  585. return true;
  586. }
  587. bool AVOpenGLWidget::Render(AVFrame* frame)
  588. {
  589. if (!m_initialized && isValid()) {
  590. makeCurrent();
  591. initializeGL();
  592. doneCurrent();
  593. }
  594. if (!frame) {
  595. update(); // 仅刷新显示
  596. return true;
  597. }
  598. bool result = convertFromAVFrame(frame);
  599. // 释放传入的AVFrame,因为现在使用QueuedConnection异步调用
  600. // 需要在这里释放内存,避免内存泄漏
  601. av_frame_free(&frame);
  602. return result;
  603. }
  604. void AVOpenGLWidget::clearFrame()
  605. {
  606. QMutexLocker locker(&m_mutex);
  607. m_frameUpdated = false;
  608. update();
  609. }
  610. void AVOpenGLWidget::setGray(bool on)
  611. {
  612. if (m_gray != on) {
  613. m_gray = on;
  614. update();
  615. }
  616. }
  617. void AVOpenGLWidget::setThreshold(bool on, float value)
  618. {
  619. if (m_threshold != on || m_thresholdValue != value) {
  620. m_threshold = on;
  621. m_thresholdValue = value;
  622. update();
  623. }
  624. }
  625. void AVOpenGLWidget::setBlur(bool on, float radius)
  626. {
  627. if (m_blur != on || m_blurRadius != radius) {
  628. m_blur = on;
  629. m_blurRadius = radius;
  630. update();
  631. }
  632. }
  633. void AVOpenGLWidget::setReverse(bool on)
  634. {
  635. if (m_reverse != on) {
  636. m_reverse = on;
  637. update();
  638. }
  639. }
  640. void AVOpenGLWidget::setColorReduce(bool on, int level)
  641. {
  642. if (m_colorReduce != on || m_colorReduceLevel != level) {
  643. m_colorReduce = on;
  644. m_colorReduceLevel = level;
  645. update();
  646. }
  647. }
  648. void AVOpenGLWidget::setGamma(bool on, float gamma)
  649. {
  650. if (m_gamma != on || m_gammaValue != gamma) {
  651. m_gamma = on;
  652. m_gammaValue = gamma;
  653. update();
  654. }
  655. }
  656. void AVOpenGLWidget::setContrastBright(bool on, float contrast, float brightness)
  657. {
  658. if (m_contrastBright != on || m_contrast != contrast || m_brightness != brightness) {
  659. m_contrastBright = on;
  660. m_contrast = contrast;
  661. m_brightness = brightness;
  662. update();
  663. }
  664. }
  665. void AVOpenGLWidget::setMirror(bool on)
  666. {
  667. if (m_mirror != on) {
  668. m_mirror = on;
  669. update();
  670. }
  671. }
  672. void AVOpenGLWidget::setNoVideoTip(const QString& tip)
  673. {
  674. if (m_noVideoTip != tip) {
  675. m_noVideoTip = tip;
  676. updateTipTexture();
  677. update();
  678. }
  679. }
  680. void AVOpenGLWidget::showEndTip(const QString& tip)
  681. {
  682. QMutexLocker locker(&m_mutex);
  683. m_noVideoTip = tip;
  684. if (m_tipTexture) {
  685. glDeleteTextures(1, &m_tipTexture);
  686. m_tipTexture = 0;
  687. }
  688. m_frameUpdated = false;
  689. if (m_frameData) {
  690. delete[] m_frameData;
  691. m_frameData = nullptr;
  692. }
  693. // 重置纹理尺寸缓存,确保下次帧到来时重新定义纹理
  694. m_texWidth = 0;
  695. m_texHeight = 0;
  696. updateTipTexture();
  697. update();
  698. }
  699. void AVOpenGLWidget::onShowYUV(QSharedPointer<VideoFrame> frame)
  700. {
  701. if (!frame || frame->getPixelW() <= 0 || frame->getPixelH() <= 0) {
  702. return;
  703. }
  704. QMutexLocker locker(&m_mutex);
  705. uint32_t width = frame->getPixelW();
  706. uint32_t height = frame->getPixelH();
  707. // 如果尺寸变化,重新分配内存
  708. if (m_frameWidth != static_cast<int>(width) || m_frameHeight != static_cast<int>(height)) {
  709. if (m_frameData) {
  710. delete[] m_frameData;
  711. m_frameData = nullptr;
  712. }
  713. m_frameWidth = static_cast<int>(width);
  714. m_frameHeight = static_cast<int>(height);
  715. // 检查内存分配大小是否合理
  716. size_t dataSize = static_cast<size_t>(m_frameWidth) * m_frameHeight * 4;
  717. if (dataSize > 0 && dataSize < SIZE_MAX / 4) {
  718. try {
  719. m_frameData = new unsigned char[dataSize]; // RGBA格式
  720. } catch (const std::bad_alloc&) {
  721. m_frameData = nullptr;
  722. return;
  723. }
  724. } else {
  725. return;
  726. }
  727. // 尺寸变更,强制重定义纹理
  728. m_texWidth = 0;
  729. m_texHeight = 0;
  730. }
  731. // 确保m_frameData已正确分配
  732. if (!m_frameData) {
  733. size_t dataSize = static_cast<size_t>(m_frameWidth) * m_frameHeight * 4;
  734. if (dataSize > 0 && dataSize < SIZE_MAX / 4) {
  735. try {
  736. m_frameData = new unsigned char[dataSize]; // RGBA格式
  737. } catch (const std::bad_alloc&) {
  738. m_frameData = nullptr;
  739. return;
  740. }
  741. } else {
  742. return;
  743. }
  744. }
  745. AVPixelFormat fmt = frame->getFormat();
  746. uint8_t* y = frame->getData(0);
  747. uint8_t* u = frame->getData(1);
  748. uint8_t* v = frame->getData(2);
  749. int lsY = frame->getLineSize(0);
  750. int lsU = frame->getLineSize(1);
  751. int lsV = frame->getLineSize(2);
  752. if (!y)
  753. return;
  754. auto clamp = [](int v) { return v < 0 ? 0 : (v > 255 ? 255 : v); };
  755. switch (fmt) {
  756. case AV_PIX_FMT_YUV420P:
  757. case AV_PIX_FMT_YUVJ420P:
  758. if (!u || !v)
  759. return;
  760. for (int yy = 0; yy < m_frameHeight; ++yy) {
  761. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  762. const uint8_t* srcY = y + yy * lsY;
  763. const uint8_t* srcU = u + (yy / 2) * lsU;
  764. const uint8_t* srcV = v + (yy / 2) * lsV;
  765. for (int xx = 0; xx < m_frameWidth; ++xx) {
  766. int Y = srcY[xx];
  767. int Uc = srcU[xx / 2];
  768. int Vc = srcV[xx / 2];
  769. int C = Y - 16, D = Uc - 128, E = Vc - 128;
  770. int R = (298 * C + 409 * E + 128) >> 8;
  771. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  772. int B = (298 * C + 516 * D + 128) >> 8;
  773. *dst++ = clamp(R);
  774. *dst++ = clamp(G);
  775. *dst++ = clamp(B);
  776. *dst++ = 255;
  777. }
  778. }
  779. break;
  780. case AV_PIX_FMT_YUV422P:
  781. case AV_PIX_FMT_YUVJ422P:
  782. if (!u || !v)
  783. return;
  784. for (int yy = 0; yy < m_frameHeight; ++yy) {
  785. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  786. const uint8_t* srcY = y + yy * lsY;
  787. const uint8_t* srcU = u + yy * lsU;
  788. const uint8_t* srcV = v + yy * lsV;
  789. for (int xx = 0; xx < m_frameWidth; ++xx) {
  790. int Y = srcY[xx];
  791. int Uc = srcU[xx / 2];
  792. int Vc = srcV[xx / 2];
  793. int C = Y - 16, D = Uc - 128, E = Vc - 128;
  794. int R = (298 * C + 409 * E + 128) >> 8;
  795. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  796. int B = (298 * C + 516 * D + 128) >> 8;
  797. *dst++ = clamp(R);
  798. *dst++ = clamp(G);
  799. *dst++ = clamp(B);
  800. *dst++ = 255;
  801. }
  802. }
  803. break;
  804. case AV_PIX_FMT_YUYV422: // Packed: Y0 U Y1 V
  805. for (int yy = 0; yy < m_frameHeight; ++yy) {
  806. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  807. const uint8_t* row = y + yy * lsY;
  808. for (int xx = 0; xx < m_frameWidth; xx += 2) {
  809. int Y0 = row[xx * 2 + 0];
  810. int Uc = row[xx * 2 + 1];
  811. int Y1 = row[xx * 2 + 2];
  812. int Vc = row[xx * 2 + 3];
  813. // pixel 0
  814. {
  815. int C = Y0 - 16, D = Uc - 128, E = Vc - 128;
  816. int R = (298 * C + 409 * E + 128) >> 8;
  817. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  818. int B = (298 * C + 516 * D + 128) >> 8;
  819. *dst++ = clamp(R);
  820. *dst++ = clamp(G);
  821. *dst++ = clamp(B);
  822. *dst++ = 255;
  823. }
  824. // pixel 1 shares U/V
  825. {
  826. int C = Y1 - 16, D = Uc - 128, E = Vc - 128;
  827. int R = (298 * C + 409 * E + 128) >> 8;
  828. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  829. int B = (298 * C + 516 * D + 128) >> 8;
  830. *dst++ = clamp(R);
  831. *dst++ = clamp(G);
  832. *dst++ = clamp(B);
  833. *dst++ = 255;
  834. }
  835. }
  836. }
  837. break;
  838. case AV_PIX_FMT_UYVY422: // Packed: U Y0 V Y1
  839. for (int yy = 0; yy < m_frameHeight; ++yy) {
  840. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  841. const uint8_t* row = y + yy * lsY;
  842. for (int xx = 0; xx < m_frameWidth; xx += 2) {
  843. int Uc = row[xx * 2 + 0];
  844. int Y0 = row[xx * 2 + 1];
  845. int Vc = row[xx * 2 + 2];
  846. int Y1 = row[xx * 2 + 3];
  847. // pixel 0
  848. {
  849. int C = Y0 - 16, D = Uc - 128, E = Vc - 128;
  850. int R = (298 * C + 409 * E + 128) >> 8;
  851. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  852. int B = (298 * C + 516 * D + 128) >> 8;
  853. *dst++ = clamp(R);
  854. *dst++ = clamp(G);
  855. *dst++ = clamp(B);
  856. *dst++ = 255;
  857. }
  858. // pixel 1 shares U/V
  859. {
  860. int C = Y1 - 16, D = Uc - 128, E = Vc - 128;
  861. int R = (298 * C + 409 * E + 128) >> 8;
  862. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  863. int B = (298 * C + 516 * D + 128) >> 8;
  864. *dst++ = clamp(R);
  865. *dst++ = clamp(G);
  866. *dst++ = clamp(B);
  867. *dst++ = 255;
  868. }
  869. }
  870. }
  871. break;
  872. case AV_PIX_FMT_YUV444P:
  873. if (!u || !v)
  874. return;
  875. for (int yy = 0; yy < m_frameHeight; ++yy) {
  876. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  877. const uint8_t* srcY = y + yy * lsY;
  878. const uint8_t* srcU = u + yy * lsU;
  879. const uint8_t* srcV = v + yy * lsV;
  880. for (int xx = 0; xx < m_frameWidth; ++xx) {
  881. int Y = srcY[xx];
  882. int Uc = srcU[xx];
  883. int Vc = srcV[xx];
  884. int C = Y - 16, D = Uc - 128, E = Vc - 128;
  885. int R = (298 * C + 409 * E + 128) >> 8;
  886. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  887. int B = (298 * C + 516 * D + 128) >> 8;
  888. *dst++ = clamp(R);
  889. *dst++ = clamp(G);
  890. *dst++ = clamp(B);
  891. *dst++ = 255;
  892. }
  893. }
  894. break;
  895. case AV_PIX_FMT_NV12: // Y + UV interleaved
  896. if (!u)
  897. return;
  898. for (int yy = 0; yy < m_frameHeight; ++yy) {
  899. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  900. const uint8_t* srcY = y + yy * lsY;
  901. const uint8_t* srcUV = u + (yy / 2) * lsU;
  902. for (int xx = 0; xx < m_frameWidth; ++xx) {
  903. int Y = srcY[xx];
  904. int Uc = srcUV[(xx / 2) * 2 + 0];
  905. int Vc = srcUV[(xx / 2) * 2 + 1];
  906. int C = Y - 16, D = Uc - 128, E = Vc - 128;
  907. int R = (298 * C + 409 * E + 128) >> 8;
  908. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  909. int B = (298 * C + 516 * D + 128) >> 8;
  910. *dst++ = clamp(R);
  911. *dst++ = clamp(G);
  912. *dst++ = clamp(B);
  913. *dst++ = 255;
  914. }
  915. }
  916. break;
  917. case AV_PIX_FMT_NV21: // Y + VU interleaved
  918. if (!u)
  919. return;
  920. for (int yy = 0; yy < m_frameHeight; ++yy) {
  921. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  922. const uint8_t* srcY = y + yy * lsY;
  923. const uint8_t* srcVU = u + (yy / 2) * lsU;
  924. for (int xx = 0; xx < m_frameWidth; ++xx) {
  925. int Y = srcY[xx];
  926. int Vc = srcVU[(xx / 2) * 2 + 0];
  927. int Uc = srcVU[(xx / 2) * 2 + 1];
  928. int C = Y - 16, D = Uc - 128, E = Vc - 128;
  929. int R = (298 * C + 409 * E + 128) >> 8;
  930. int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
  931. int B = (298 * C + 516 * D + 128) >> 8;
  932. *dst++ = clamp(R);
  933. *dst++ = clamp(G);
  934. *dst++ = clamp(B);
  935. *dst++ = 255;
  936. }
  937. }
  938. break;
  939. case AV_PIX_FMT_GRAY8:
  940. for (int yy = 0; yy < m_frameHeight; ++yy) {
  941. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  942. const uint8_t* srcY = y + yy * lsY;
  943. for (int xx = 0; xx < m_frameWidth; ++xx) {
  944. int Y = srcY[xx];
  945. *dst++ = Y;
  946. *dst++ = Y;
  947. *dst++ = Y;
  948. *dst++ = 255;
  949. }
  950. }
  951. break;
  952. case AV_PIX_FMT_RGB24:
  953. for (int yy = 0; yy < m_frameHeight; ++yy) {
  954. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  955. const uint8_t* src = y + yy * lsY;
  956. for (int xx = 0; xx < m_frameWidth; ++xx) {
  957. uint8_t r = src[xx * 3 + 0];
  958. uint8_t g = src[xx * 3 + 1];
  959. uint8_t b = src[xx * 3 + 2];
  960. *dst++ = r;
  961. *dst++ = g;
  962. *dst++ = b;
  963. *dst++ = 255;
  964. }
  965. }
  966. break;
  967. case AV_PIX_FMT_RGBA:
  968. for (int yy = 0; yy < m_frameHeight; ++yy) {
  969. uint8_t* dst = m_frameData + yy * m_frameWidth * 4;
  970. const uint8_t* src = y + yy * lsY;
  971. memcpy(dst, src, m_frameWidth * 4);
  972. }
  973. break;
  974. default:
  975. // 不支持的格式:尝试走现有 convertFromAVFrame 流程(如果可用),否则返回
  976. // 这里无法拿到 AVFrame*,先简单忽略
  977. return;
  978. }
  979. m_frameUpdated = true;
  980. update();
  981. }