PlayerGLWidget.cpp 10 KB

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