PlayerGLWidget.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #include "PlayerGLWidget.h"
  2. #include <QOpenGLFunctions> // 添加此行
  3. #include <QOpenGLContext>
  4. #include <QSurfaceFormat>
  5. #include "LHQLogAPI.h"
  6. PlayerGLWidget::PlayerGLWidget(QWidget *parent) : QOpenGLWidget(parent)
  7. {
  8. textureY_ = nullptr;
  9. textureU_ = nullptr;
  10. textureV_ = nullptr;
  11. textureIdY_ = 0;
  12. textureIdU_ = 0;
  13. textureIdV_ = 0;
  14. Ortho2DSize_ = QSize(0, 0);
  15. shaderProgram = 0;
  16. VAO = 0;
  17. VBO = 0;
  18. EBO = 0;
  19. // QString imagePath = QApplication::applicationDirPath() + "/0.jpg";
  20. // QImage image(imagePath);
  21. // Image_YUV420 yuv420;
  22. // convertQImageToYUV420(image, yuv420);
  23. // /* 显示图片 */
  24. // updateFrame(yuv420);
  25. }
  26. PlayerGLWidget::~PlayerGLWidget()
  27. {
  28. if (textureIdY_ != 0) {
  29. glDeleteTextures(1, &textureIdY_);
  30. textureIdY_ = 0;
  31. }
  32. if (textureIdU_ != 0) {
  33. glDeleteTextures(1, &textureIdU_);
  34. textureIdU_ = 0;
  35. }
  36. if (textureIdV_ != 0) {
  37. glDeleteTextures(1, &textureIdV_);
  38. textureIdV_ = 0;
  39. }
  40. if (VAO != 0) {
  41. glDeleteVertexArrays(1, &VAO);
  42. VAO = 0;
  43. }
  44. if (VBO != 0) {
  45. glDeleteBuffers(1, &VBO);
  46. VBO = 0;
  47. }
  48. if (EBO != 0) {
  49. glDeleteBuffers(1, &EBO);
  50. EBO = 0;
  51. }
  52. if (shaderProgram != 0) {
  53. glDeleteProgram(shaderProgram);
  54. shaderProgram = 0;
  55. }
  56. if(textureY_ != nullptr)
  57. {
  58. delete textureY_;
  59. textureY_ = nullptr;
  60. }
  61. if(textureU_ != nullptr)
  62. {
  63. delete textureU_;
  64. textureU_ = nullptr;
  65. }
  66. if(textureV_ != nullptr)
  67. {
  68. delete textureV_;
  69. textureV_ = nullptr;
  70. }
  71. }
  72. /* 设置一张图片,用于显示默认的图片 */
  73. void PlayerGLWidget::setImage(const QImage& image)
  74. {
  75. Image_YUV420 yuv420;
  76. convertQImageToYUV420(image, yuv420);
  77. /* 显示图片 */
  78. updateFrame(yuv420);
  79. }
  80. /* 刷新一帧 */
  81. void PlayerGLWidget::updateFrame(Image_YUV420& image)
  82. {
  83. m_yData = std::move(image.yData);
  84. m_uData = std::move(image.uData);
  85. m_vData = std::move(image.vData);
  86. m_imageSize = QSize(image.width, image.height);
  87. update();
  88. }
  89. /* 刷新一帧QImage */
  90. void PlayerGLWidget::updateFrame(Image_QImage& image)
  91. {
  92. LH_WRITE_LOG("图片宽度: " + QString::number(image.image.width()) + "图片高度: " + QString::number(image.image.height()));
  93. convertQImageToYUV420(image.image, m_YUV420);
  94. m_yData = m_YUV420.yData;
  95. m_uData = m_YUV420.uData;
  96. m_vData = m_YUV420.vData;
  97. m_imageSize = QSize(m_YUV420.width, m_YUV420.height);
  98. update();
  99. }
  100. void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
  101. {
  102. int width = image.width();
  103. int height = image.height();
  104. int frameSize = width * height;
  105. int chromaSize = frameSize / 4;
  106. uint8_t* yuv = new uint8_t[frameSize + chromaSize * 2];
  107. uint8_t* yPlane = yuv;
  108. uint8_t* uPlane = yuv + frameSize;
  109. uint8_t* vPlane = yuv + frameSize + chromaSize;
  110. auto rgb = image.bits();
  111. for (int j = 0; j < height; j++) {
  112. for (int i = 0; i < width; i++) {
  113. int r = rgb[(j * width + i) * 3];
  114. int g = rgb[(j * width + i) * 3 + 1];
  115. int b = rgb[(j * width + i) * 3 + 2];
  116. int y = (0.299 * r) + (0.587 * g) + (0.114 * b);
  117. int u = (-0.169 * r) - (0.331 * g) + (0.5 * b) + 128;
  118. int v = (0.5 * r) - (0.419 * g) - (0.081 * b) + 128;
  119. yPlane[j * width + i] = std::clamp(y, 0, 255);
  120. if (j % 2 == 0 && i % 2 == 0) {
  121. uPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(u, 0, 255);
  122. vPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(v, 0, 255);
  123. }
  124. }
  125. }
  126. yuv420.width = width;
  127. yuv420.height = height;
  128. yuv420.yData.resize(frameSize);
  129. yuv420.uData.resize(chromaSize);
  130. yuv420.vData.resize(chromaSize);
  131. yuv420.yData.append(reinterpret_cast<char*>(yPlane), frameSize);
  132. yuv420.uData.append(reinterpret_cast<char*>(uPlane), chromaSize);
  133. yuv420.vData.append(reinterpret_cast<char*>(vPlane), chromaSize);
  134. }
  135. // void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
  136. // {
  137. // int width = image.width();
  138. // int height = image.height();
  139. // int ySize = width * height;
  140. // int chromaWidth = (width + 1) / 2;
  141. // int chromaHeight = (height + 1) / 2;
  142. // int uvSize = chromaWidth * chromaHeight;
  143. // yuv420.width = width;
  144. // yuv420.height = height;
  145. // yuv420.yData.resize(ySize);
  146. // yuv420.uData.resize(uvSize);
  147. // yuv420.vData.resize(uvSize);
  148. // for (int y = 0; y < height; ++y) {
  149. // for (int x = 0; x < width; ++x) {
  150. // QColor color = image.pixelColor(x, y);
  151. // int r = color.red();
  152. // int g = color.green();
  153. // int b = color.blue();
  154. // int yIndex = y * width + x;
  155. // if (yIndex >= 0 && yIndex < ySize) {
  156. // yuv420.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
  157. // }
  158. // if (y % 2 == 0 && x % 2 == 0)
  159. // {
  160. // int uvIndex = (y / 2) * chromaWidth + (x / 2);
  161. // if (uvIndex >= 0 && uvIndex < uvSize)
  162. // {
  163. // yuv420.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
  164. // yuv420.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
  165. // }
  166. // }
  167. // }
  168. // }
  169. // }
  170. void PlayerGLWidget::initializeGL()
  171. {
  172. LH_WRITE_LOG("开始初始化OpenGL");
  173. // 打印当前实际创建到的 OpenGL 上下文信息(UOS 上用于确认是 OpenGL 还是 OpenGL ES、版本多少)
  174. if (QOpenGLContext* ctx = context()) {
  175. const QSurfaceFormat fmt = ctx->format();
  176. QString profileStr = "NoProfile";
  177. switch (fmt.profile()) {
  178. case QSurfaceFormat::CoreProfile:
  179. profileStr = "Core";
  180. break;
  181. case QSurfaceFormat::CompatibilityProfile:
  182. profileStr = "Compatibility";
  183. break;
  184. case QSurfaceFormat::NoProfile:
  185. default:
  186. profileStr = "NoProfile";
  187. break;
  188. }
  189. QString renderableStr = "Default";
  190. switch (fmt.renderableType()) {
  191. case QSurfaceFormat::OpenGL:
  192. renderableStr = "OpenGL";
  193. break;
  194. case QSurfaceFormat::OpenGLES:
  195. renderableStr = "OpenGLES";
  196. break;
  197. case QSurfaceFormat::DefaultRenderableType:
  198. default:
  199. renderableStr = "Default";
  200. break;
  201. }
  202. LH_WRITE_LOG(QString("Qt Context: renderable=%1 isOpenGLES=%2 version=%3.%4 profile=%5")
  203. .arg(renderableStr)
  204. .arg(ctx->isOpenGLES() ? "true" : "false")
  205. .arg(fmt.majorVersion())
  206. .arg(fmt.minorVersion())
  207. .arg(profileStr));
  208. } else {
  209. LH_WRITE_LOG("Qt Context: context() == nullptr (initializeGL)");
  210. }
  211. // glGetString 必须在“已 current 的上下文”里调用;某些平台直接调用全局 glGetString 可能会段错误
  212. QOpenGLContext* currentCtx = QOpenGLContext::currentContext();
  213. if (!currentCtx) {
  214. LH_WRITE_LOG("QOpenGLContext::currentContext() == nullptr (initializeGL),跳过 glGetString");
  215. return;
  216. }
  217. QOpenGLFunctions* f = currentCtx->functions();
  218. if (!f) {
  219. LH_WRITE_LOG("currentContext()->functions() == nullptr (initializeGL),跳过 glGetString");
  220. return;
  221. }
  222. const char* glVendor = reinterpret_cast<const char*>(f->glGetString(GL_VENDOR));
  223. const char* glRenderer = reinterpret_cast<const char*>(f->glGetString(GL_RENDERER));
  224. const char* glVersion = reinterpret_cast<const char*>(f->glGetString(GL_VERSION));
  225. const char* glslVersion = reinterpret_cast<const char*>(f->glGetString(GL_SHADING_LANGUAGE_VERSION));
  226. LH_WRITE_LOG(QString("GL_VENDOR: %1").arg(glVendor ? glVendor : "(null)"));
  227. LH_WRITE_LOG(QString("GL_RENDERER: %1").arg(glRenderer ? glRenderer : "(null)"));
  228. LH_WRITE_LOG(QString("GL_VERSION: %1").arg(glVersion ? glVersion : "(null)"));
  229. LH_WRITE_LOG(QString("GLSL_VERSION: %1").arg(glslVersion ? glslVersion : "(null)"));
  230. // 确保初始化 OpenGL 函数(在 OpenGL 版本不匹配时,返回 false,避免后续直接段错误)
  231. if (!initializeOpenGLFunctions()) {
  232. LH_WRITE_LOG("initializeOpenGLFunctions() 失败:当前上下文可能不支持 QOpenGLFunctions_3_3_Core 所需版本");
  233. return;
  234. }
  235. // 创建并编译顶点着色器
  236. const char* vertexShaderSource = R"(
  237. #version 330 core
  238. layout(location = 0) in vec3 aPos;
  239. layout(location = 1) in vec2 aTexCoord;
  240. out vec2 TexCoord;
  241. void main()
  242. {
  243. gl_Position = vec4(aPos, 1.0);
  244. TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); // 翻转纹理坐标
  245. }
  246. )";
  247. GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  248. glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
  249. glCompileShader(vertexShader);
  250. // 创建并编译片段着色器
  251. const char* fragmentShaderSource = R"(
  252. #version 330 core
  253. out vec4 FragColor;
  254. in vec2 TexCoord;
  255. uniform sampler2D textureY;
  256. uniform sampler2D textureU;
  257. uniform sampler2D textureV;
  258. void main()
  259. {
  260. float y = texture(textureY, TexCoord).r;
  261. float u = texture(textureU, TexCoord).r - 0.5;
  262. float v = texture(textureV, TexCoord).r - 0.5;
  263. float r = y + 1.402 * v;
  264. float g = y - 0.344 * u - 0.714 * v;
  265. float b = y + 1.772 * u;
  266. FragColor = vec4(r, g, b, 1.0);
  267. }
  268. )";
  269. GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  270. glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
  271. glCompileShader(fragmentShader);
  272. // 链接着色器程序
  273. shaderProgram = glCreateProgram();
  274. glAttachShader(shaderProgram, vertexShader); // 确保传递的是程序对象和着色器对象
  275. glAttachShader(shaderProgram, fragmentShader); // 确保传递的是程序对象和着色器对象
  276. glLinkProgram(shaderProgram);
  277. // 删除着色器对象
  278. glDeleteShader(vertexShader);
  279. glDeleteShader(fragmentShader);
  280. // 创建纹理
  281. glGenTextures(1, &textureIdY_);
  282. glGenTextures(1, &textureIdU_);
  283. glGenTextures(1, &textureIdV_);
  284. glBindTexture(GL_TEXTURE_2D, textureIdY_);
  285. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  286. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  287. glBindTexture(GL_TEXTURE_2D, textureIdU_);
  288. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  289. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  290. glBindTexture(GL_TEXTURE_2D, textureIdV_);
  291. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  292. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  293. // 设置顶点数据和缓冲
  294. float vertices[] = {
  295. // positions // texture coords
  296. -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
  297. 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
  298. 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
  299. -1.0f, 1.0f, 0.0f, 0.0f, 1.0f
  300. };
  301. unsigned int indices[] = {
  302. 0, 1, 2,
  303. 2, 3, 0
  304. };
  305. glGenVertexArrays(1, &VAO);
  306. glGenBuffers(1, &VBO);
  307. glGenBuffers(1, &EBO);
  308. glBindVertexArray(VAO);
  309. glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 设置纹理对齐方式
  310. glBindBuffer(GL_ARRAY_BUFFER, VBO);
  311. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  312. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  313. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  314. // 位置属性
  315. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
  316. glEnableVertexAttribArray(0);
  317. // 纹理坐标属性
  318. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
  319. glEnableVertexAttribArray(1);
  320. glBindBuffer(GL_ARRAY_BUFFER, 0);
  321. glBindVertexArray(0);
  322. LH_WRITE_LOG("OpenGL初始化完成");
  323. }
  324. void PlayerGLWidget::resizeGL(int w, int h)
  325. {
  326. Ortho2DSize_.setWidth(w);
  327. Ortho2DSize_.setHeight(h);
  328. glViewport(0, 0, w, h);
  329. glMatrixMode(GL_PROJECTION);
  330. glLoadIdentity();
  331. glOrtho(0, Ortho2DSize_.width(), Ortho2DSize_.height(), 0, -1, 1);
  332. glMatrixMode(GL_MODELVIEW);
  333. }
  334. void PlayerGLWidget::paintGL()
  335. {
  336. glClear(GL_COLOR_BUFFER_BIT);
  337. if (m_yData.isEmpty() || m_uData.isEmpty() || m_vData.isEmpty()) {
  338. return;
  339. }
  340. int uvWidth = m_imageSize.width() / 2;
  341. int uvHeight = m_imageSize.height() / 2;
  342. // 使用着色器程序
  343. glUseProgram(shaderProgram);
  344. // 更新纹理数据
  345. glActiveTexture(GL_TEXTURE0);
  346. glBindTexture(GL_TEXTURE_2D, textureIdY_);
  347. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width(), m_imageSize.height(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_yData.data());
  348. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  349. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  350. glGenerateMipmap(GL_TEXTURE_2D);
  351. glActiveTexture(GL_TEXTURE1);
  352. glBindTexture(GL_TEXTURE_2D, textureIdU_);
  353. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data());
  354. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  355. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  356. glGenerateMipmap(GL_TEXTURE_2D);
  357. glActiveTexture(GL_TEXTURE2);
  358. glBindTexture(GL_TEXTURE_2D, textureIdV_);
  359. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data());
  360. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  361. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  362. glGenerateMipmap(GL_TEXTURE_2D);
  363. // 设置纹理单元
  364. glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0);
  365. glUniform1i(glGetUniformLocation(shaderProgram, "textureU"), 1);
  366. glUniform1i(glGetUniformLocation(shaderProgram, "textureV"), 2);
  367. // 绘制四边形
  368. glBindVertexArray(VAO);
  369. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
  370. glBindVertexArray(0);
  371. }