avopenglwidget.cpp 29 KB

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