PlayerGLWidget.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #include "PlayerGLWidget.h"
  2. #include <QOpenGLFunctions> // 添加此行
  3. #include "LHQLogAPI.h"
  4. PlayerGLWidget::PlayerGLWidget(QWidget *parent) : QOpenGLWidget(parent)
  5. {
  6. textureY_ = nullptr;
  7. textureU_ = nullptr;
  8. textureV_ = nullptr;
  9. textureIdY_ = 0;
  10. textureIdU_ = 0;
  11. textureIdV_ = 0;
  12. Ortho2DSize_ = QSize(0, 0);
  13. shaderProgram = 0;
  14. VAO = 0;
  15. VBO = 0;
  16. EBO = 0;
  17. // QString imagePath = QApplication::applicationDirPath() + "/0.jpg";
  18. // QImage image(imagePath);
  19. // Image_YUV420 yuv420;
  20. // convertQImageToYUV420(image, yuv420);
  21. // /* 显示图片 */
  22. // updateFrame(yuv420);
  23. }
  24. PlayerGLWidget::~PlayerGLWidget()
  25. {
  26. if (textureIdY_ != 0) {
  27. glDeleteTextures(1, &textureIdY_);
  28. textureIdY_ = 0;
  29. }
  30. if (textureIdU_ != 0) {
  31. glDeleteTextures(1, &textureIdU_);
  32. textureIdU_ = 0;
  33. }
  34. if (textureIdV_ != 0) {
  35. glDeleteTextures(1, &textureIdV_);
  36. textureIdV_ = 0;
  37. }
  38. if (VAO != 0) {
  39. glDeleteVertexArrays(1, &VAO);
  40. VAO = 0;
  41. }
  42. if (VBO != 0) {
  43. glDeleteBuffers(1, &VBO);
  44. VBO = 0;
  45. }
  46. if (EBO != 0) {
  47. glDeleteBuffers(1, &EBO);
  48. EBO = 0;
  49. }
  50. if (shaderProgram != 0) {
  51. glDeleteProgram(shaderProgram);
  52. shaderProgram = 0;
  53. }
  54. delete textureY_;
  55. textureY_ = nullptr;
  56. delete textureU_;
  57. textureU_ = nullptr;
  58. delete textureV_;
  59. textureV_ = nullptr;
  60. }
  61. /* 设置一张图片,用于显示默认的图片 */
  62. void PlayerGLWidget::setImage(const QImage& image)
  63. {
  64. Image_YUV420 yuv420;
  65. convertQImageToYUV420(image, yuv420);
  66. /* 显示图片 */
  67. updateFrame(yuv420);
  68. }
  69. /* 刷新一帧 */
  70. void PlayerGLWidget::updateFrame(Image_YUV420& image)
  71. {
  72. m_yData = std::move(image.yData);
  73. m_uData = std::move(image.uData);
  74. m_vData = std::move(image.vData);
  75. m_imageSize = QSize(image.width, image.height);
  76. update();
  77. }
  78. /* 刷新一帧QImage */
  79. void PlayerGLWidget::updateFrame(Image_QImage& image)
  80. {
  81. LH_WRITE_LOG("图片宽度: " + QString::number(image.image.width()) + "图片高度: " + QString::number(image.image.height()));
  82. convertQImageToYUV420(image.image, m_YUV420);
  83. m_yData = m_YUV420.yData;
  84. m_uData = m_YUV420.uData;
  85. m_vData = m_YUV420.vData;
  86. m_imageSize = QSize(m_YUV420.width, m_YUV420.height);
  87. update();
  88. }
  89. void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
  90. {
  91. int width = image.width();
  92. int height = image.height();
  93. int frameSize = width * height;
  94. int chromaSize = frameSize / 4;
  95. uint8_t* yuv = new uint8_t[frameSize + chromaSize * 2];
  96. uint8_t* yPlane = yuv;
  97. uint8_t* uPlane = yuv + frameSize;
  98. uint8_t* vPlane = yuv + frameSize + chromaSize;
  99. auto rgb = image.bits();
  100. // for (int y = 0; y < height; ++y) {
  101. // for (int x = 0; x < width; ++x) {
  102. // QColor color = image.pixelColor(x, y);
  103. // int r = color.red();
  104. // int g = color.green();
  105. // int b = color.blue();
  106. // int yIndex = y * width + x;
  107. // yuv420.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
  108. // if (y % 2 == 0 && x % 2 == 0) {
  109. // int uvIndex = (y / 2) * (width / 2) + (x / 2);
  110. // yuv420.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
  111. // yuv420.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
  112. // }
  113. // }
  114. // }
  115. for (int j = 0; j < height; j++) {
  116. for (int i = 0; i < width; i++) {
  117. int r = rgb[(j * width + i) * 3];
  118. int g = rgb[(j * width + i) * 3 + 1];
  119. int b = rgb[(j * width + i) * 3 + 2];
  120. // int y = (0.257 * r) + (0.504 * g) + (0.098 * b) + 16;
  121. // int u = -(0.148 * r) - (0.291 * g) + (0.439 * b) + 128;
  122. // int v = (0.439 * r) - (0.368 * g) - (0.071 * b) + 128;
  123. int y = (0.299 * r) + (0.587 * g) + (0.114 * b);
  124. int u = (-0.169 * r) - (0.331 * g) + (0.5 * b) + 128;
  125. int v = (0.5 * r) - (0.419 * g) - (0.081 * b) + 128;
  126. yPlane[j * width + i] = std::clamp(y, 0, 255);
  127. if (j % 2 == 0 && i % 2 == 0) {
  128. uPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(u, 0, 255);
  129. vPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(v, 0, 255);
  130. }
  131. }
  132. }
  133. yuv420.width = width;
  134. yuv420.height = height;
  135. yuv420.yData.resize(frameSize);
  136. yuv420.uData.resize(chromaSize);
  137. yuv420.vData.resize(chromaSize);
  138. yuv420.yData.append(reinterpret_cast<char*>(yPlane), frameSize);
  139. yuv420.uData.append(reinterpret_cast<char*>(uPlane), chromaSize);
  140. yuv420.vData.append(reinterpret_cast<char*>(vPlane), chromaSize);
  141. }
  142. void PlayerGLWidget::initializeGL()
  143. {
  144. initializeOpenGLFunctions(); // 确保初始化 OpenGL 函数
  145. // 创建并编译顶点着色器
  146. const char* vertexShaderSource = R"(
  147. #version 330 core
  148. layout(location = 0) in vec3 aPos;
  149. layout(location = 1) in vec2 aTexCoord;
  150. out vec2 TexCoord;
  151. void main()
  152. {
  153. gl_Position = vec4(aPos, 1.0);
  154. TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); // 翻转纹理坐标
  155. }
  156. )";
  157. GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  158. glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
  159. glCompileShader(vertexShader);
  160. // 创建并编译片段着色器
  161. const char* fragmentShaderSource = R"(
  162. #version 330 core
  163. out vec4 FragColor;
  164. in vec2 TexCoord;
  165. uniform sampler2D textureY;
  166. uniform sampler2D textureU;
  167. uniform sampler2D textureV;
  168. void main()
  169. {
  170. float y = texture(textureY, TexCoord).r;
  171. float u = texture(textureU, TexCoord).r - 0.5;
  172. float v = texture(textureV, TexCoord).r - 0.5;
  173. float r = y + 1.402 * v;
  174. float g = y - 0.344 * u - 0.714 * v;
  175. float b = y + 1.772 * u;
  176. FragColor = vec4(r, g, b, 1.0);
  177. }
  178. )";
  179. GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  180. glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
  181. glCompileShader(fragmentShader);
  182. // 链接着色器程序
  183. shaderProgram = glCreateProgram();
  184. glAttachShader(shaderProgram, vertexShader); // 确保传递的是程序对象和着色器对象
  185. glAttachShader(shaderProgram, fragmentShader); // 确保传递的是程序对象和着色器对象
  186. glLinkProgram(shaderProgram);
  187. // 删除着色器对象
  188. glDeleteShader(vertexShader);
  189. glDeleteShader(fragmentShader);
  190. // 创建纹理
  191. glGenTextures(1, &textureIdY_);
  192. glGenTextures(1, &textureIdU_);
  193. glGenTextures(1, &textureIdV_);
  194. glBindTexture(GL_TEXTURE_2D, textureIdY_);
  195. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  196. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  197. glBindTexture(GL_TEXTURE_2D, textureIdU_);
  198. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  199. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  200. glBindTexture(GL_TEXTURE_2D, textureIdV_);
  201. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  202. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  203. // 设置顶点数据和缓冲
  204. float vertices[] = {
  205. // positions // texture coords
  206. -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
  207. 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
  208. 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
  209. -1.0f, 1.0f, 0.0f, 0.0f, 1.0f
  210. };
  211. unsigned int indices[] = {
  212. 0, 1, 2,
  213. 2, 3, 0
  214. };
  215. glGenVertexArrays(1, &VAO);
  216. glGenBuffers(1, &VBO);
  217. glGenBuffers(1, &EBO);
  218. glBindVertexArray(VAO);
  219. glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 设置纹理对齐方式
  220. glBindBuffer(GL_ARRAY_BUFFER, VBO);
  221. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  222. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  223. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  224. // 位置属性
  225. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
  226. glEnableVertexAttribArray(0);
  227. // 纹理坐标属性
  228. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
  229. glEnableVertexAttribArray(1);
  230. glBindBuffer(GL_ARRAY_BUFFER, 0);
  231. glBindVertexArray(0);
  232. }
  233. void PlayerGLWidget::resizeGL(int w, int h)
  234. {
  235. Ortho2DSize_.setWidth(w);
  236. Ortho2DSize_.setHeight(h);
  237. glViewport(0, 0, w, h);
  238. glMatrixMode(GL_PROJECTION);
  239. glLoadIdentity();
  240. glOrtho(0, Ortho2DSize_.width(), Ortho2DSize_.height(), 0, -1, 1);
  241. glMatrixMode(GL_MODELVIEW);
  242. }
  243. void PlayerGLWidget::paintGL()
  244. {
  245. glClear(GL_COLOR_BUFFER_BIT);
  246. if (m_yData.isEmpty() || m_uData.isEmpty() || m_vData.isEmpty()) {
  247. return;
  248. }
  249. int uvWidth = m_imageSize.width() / 2;
  250. int uvHeight = m_imageSize.height() / 2;
  251. // 使用着色器程序
  252. glUseProgram(shaderProgram);
  253. // 更新纹理数据
  254. glActiveTexture(GL_TEXTURE0);
  255. glBindTexture(GL_TEXTURE_2D, textureIdY_);
  256. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width(), m_imageSize.height(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_yData.data());
  257. glActiveTexture(GL_TEXTURE1);
  258. glBindTexture(GL_TEXTURE_2D, textureIdU_);
  259. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data());
  260. glActiveTexture(GL_TEXTURE2);
  261. glBindTexture(GL_TEXTURE_2D, textureIdV_);
  262. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data());
  263. // 设置纹理单元
  264. glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0);
  265. glUniform1i(glGetUniformLocation(shaderProgram, "textureU"), 1);
  266. glUniform1i(glGetUniformLocation(shaderProgram, "textureV"), 2);
  267. // 绘制四边形
  268. glBindVertexArray(VAO);
  269. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
  270. glBindVertexArray(0);
  271. }