ShaderYUV420.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #include "ShaderYUV420.h"
  2. #include <QOpenGLWidget>
  3. #include <QOpenGLFunctions_3_3_Core>
  4. #include <qopengltexture.h>
  5. #include "spdlog/spdlog.h"
  6. Image_YUV420P::Image_YUV420P(Image_YUV420P&& other): width(other.width), height(other.height),
  7. yData(std::move(other.yData)), uData(std::move(other.uData)), vData(std::move(other.vData))
  8. {}
  9. Image_YUV420P::Image_YUV420P(const Image_YUV420P& other)
  10. : width(other.width), height(other.height),
  11. yData(other.yData), uData(other.uData), vData(other.vData)
  12. {}
  13. Image_YUV420P& Image_YUV420P::operator=(Image_YUV420P&& other)
  14. {
  15. if (this != &other) {
  16. width = other.width;
  17. height = other.height;
  18. yData = std::move(other.yData);
  19. uData = std::move(other.uData);
  20. vData = std::move(other.vData);
  21. }
  22. return *this;
  23. }
  24. Image_YUV420P& Image_YUV420P::operator=(const Image_YUV420P& other)
  25. {
  26. if (this != &other) {
  27. width = other.width;
  28. height = other.height;
  29. yData = other.yData;
  30. uData = other.uData;
  31. vData = other.vData;
  32. }
  33. return *this;
  34. }
  35. bool Image_YUV420P::isValid() const
  36. {
  37. return width > 0 && height > 0 && !yData.isEmpty() && !uData.isEmpty() && !vData.isEmpty();
  38. }
  39. void Image_YUV420P::clear()
  40. {
  41. width = 0;
  42. height = 0;
  43. yData.clear();
  44. uData.clear();
  45. vData.clear();
  46. }
  47. ShaderYUV420::ShaderYUV420()
  48. {
  49. }
  50. ShaderYUV420::~ShaderYUV420()
  51. {
  52. QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
  53. if (m_VAO != 0) {
  54. if (gl) {
  55. gl->glDeleteVertexArrays(1, &m_VAO);
  56. gl->glDeleteBuffers(1, &m_VBO);
  57. gl->glDeleteBuffers(1, &m_EBO);
  58. }
  59. }
  60. }
  61. /* 初始化形状 */
  62. GLuint ShaderYUV420::initShape()
  63. {
  64. const int vertexCount = 4; // 顶点数量
  65. const int vertexSize = 8; // 顶点大小
  66. /* 矩形位置,铺满屏幕 */
  67. float vertices [vertexCount * vertexSize] {
  68. /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
  69. -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 左下
  70. 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // 右下
  71. 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  72. -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // 右上
  73. };
  74. const int indexCount = 6; // 索引数量
  75. /* 顶点顺序 */
  76. uint32_t indices [indexCount] {
  77. 0, 1, 2, // 第一个三角形
  78. 2, 3, 0 // 第二个三角形
  79. };
  80. QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
  81. if (!gl) {
  82. SPDLOG_ERROR("Failed to get OpenGL functions");
  83. return 0;
  84. }
  85. /* -------------------------------------------------------------------------------------
  86. * 顶点数组对象
  87. * ------------------------------------------------------------------------------------ */
  88. gl->glGenVertexArrays(1, &m_VAO); // 生成一个VAO,返回的ID存储在VAO1中
  89. gl->glBindVertexArray(m_VAO); // 绑定VAO
  90. /* -------------------------------------------------------------------------------------
  91. * 创建顶点数组缓冲区
  92. * ------------------------------------------------------------------------------------ */
  93. gl->glGenBuffers(1, &m_VBO);
  94. gl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO); // 绑定VBO
  95. gl->glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize * sizeof(float), vertices, GL_STATIC_DRAW);
  96. /* -------------------------------------------------------------------------------------
  97. * 创建EBO
  98. * ------------------------------------------------------------------------------------ */
  99. gl->glGenBuffers(1, &m_EBO);
  100. gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
  101. gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(uint32_t), indices, GL_STATIC_DRAW); // 绑定EBO
  102. /* -------------------------------------------------------------------------------------
  103. * 链接顶点属性
  104. * ------------------------------------------------------------------------------------ */
  105. // 设置顶点属性指针,告诉OpenGL如何解析顶点数据
  106. gl->glVertexAttribPointer(
  107. 0, /* 顶点属性位置,0表示第一个属性 */
  108. 3, /* 每个顶点属性的大小,这里是3,表示x、y、z坐标 */
  109. GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
  110. vertexSize * sizeof(float), /* 步长,表示每个顶点属性之间的间隔 */
  111. (void*)0 /* 偏移量,表示该属性(顶点坐标)从第0个字节开始 */
  112. );
  113. /* 启用顶点属性 */
  114. gl->glEnableVertexAttribArray(0);
  115. // 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔8个字节
  116. gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(3*sizeof(float)));
  117. gl->glEnableVertexAttribArray(1);
  118. /* 设置纹理位置 */
  119. gl->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
  120. gl->glEnableVertexAttribArray(2); // 启用纹理坐标属性
  121. return m_VAO;
  122. }
  123. /* 初始化纹理对象 */
  124. bool ShaderYUV420::initTextures()
  125. {
  126. int unit = 0;
  127. unit = createTexture(m_textureYName, 0);
  128. if(unit < 0) {
  129. SPDLOG_ERROR("Failed to create Y texture");
  130. return false;
  131. }
  132. unit = createTexture(m_textureUName, 1);
  133. if(unit < 0) {
  134. SPDLOG_ERROR("Failed to create U texture");
  135. return false;
  136. }
  137. unit = createTexture(m_textureVName, 2);
  138. if(unit < 0) {
  139. SPDLOG_ERROR("Failed to create V texture");
  140. return false;
  141. }
  142. return true;
  143. }
  144. /* 绘制图形 */
  145. void ShaderYUV420::drawShape()
  146. {
  147. QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
  148. /* 需要在使用时手动绑定VAO,绘制图形 */
  149. gl->glBindVertexArray(m_VAO); // 绑定VAO
  150. gl->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形
  151. gl->glBindVertexArray(0); // 解绑VAO
  152. }
  153. /* 刷新一帧 */
  154. bool ShaderYUV420::refreshFrameYUV420(const Image_YUV420P& yuvData)
  155. {
  156. if (!yuvData.isValid()) {
  157. SPDLOG_ERROR("Invalid YUV420 data");
  158. return false;
  159. }
  160. QOpenGLTexture *textureY = m_mapTexture.find(0)->second;
  161. QOpenGLTexture *textureU = m_mapTexture.find(1)->second;
  162. QOpenGLTexture *textureV = m_mapTexture.find(2)->second;
  163. if(textureY == nullptr || textureU == nullptr || textureV == nullptr) {
  164. SPDLOG_ERROR("Failed to get YUV textures");
  165. return false;
  166. }
  167. if(yuvData.width != m_lastYUVSize.width() || yuvData.height != m_lastYUVSize.height())
  168. {
  169. /* 如果YUV数据的大小发生变化,则需要重新创建纹理 */
  170. textureY->destroy();
  171. textureU->destroy();
  172. textureV->destroy();
  173. textureY->create();
  174. textureU->create();
  175. textureV->create();
  176. textureY->setSize(yuvData.width, yuvData.height, 1); // 设置Y分量纹理大小
  177. textureY->setFormat(QOpenGLTexture::R8_UNorm); // 设置Y分量纹理格式
  178. textureY->allocateStorage(); // 分配Y分量纹理存储空间
  179. textureU->setSize(yuvData.width / 2, yuvData.height / 2, 1); // 设置U分量纹理大小
  180. textureU->setFormat(QOpenGLTexture::R8_UNorm); // 设置U分量纹理格式
  181. textureU->allocateStorage(); // 分配U分量纹理存储空间
  182. textureV->setSize(yuvData.width / 2, yuvData.height / 2, 1); // 设置V分量纹理大小
  183. textureV->setFormat(QOpenGLTexture::R8_UNorm); // 设置V分量纹理格式
  184. textureV->allocateStorage(); // 分配V分量纹理存储空间
  185. m_lastYUVSize = QSize(yuvData.width, yuvData.height);
  186. }
  187. /* 设置Y分量纹理 */
  188. textureY->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yuvData.yData.constData());
  189. textureY->generateMipMaps(); // 生成多级渐远纹理
  190. textureY->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
  191. textureY->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
  192. /* 设置U分量纹理 */
  193. textureU->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yuvData.uData.constData());
  194. textureU->generateMipMaps(); // 生成多级渐远纹理
  195. textureU->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
  196. textureU->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
  197. /* 设置V分量纹理 */
  198. textureV->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yuvData.vData.constData());
  199. textureV->generateMipMaps(); // 生成多级渐远纹理
  200. textureV->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
  201. textureV->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
  202. printGLerror("ShaderYUV420::refreshFrameYUV420");
  203. return true;
  204. }
  205. /* 刷新一帧 */
  206. bool ShaderYUV420::refreshFrameRGBA(const QImage& image, int textureUnit)
  207. {
  208. m_yuvData.clear(); // 清空YUV数据
  209. convertRGBAToYUV420(image, m_yuvData);
  210. refreshFrameYUV420(m_yuvData);
  211. return true;
  212. }
  213. /* RGBA转换成YUV420 */
  214. bool ShaderYUV420::convertRGBAToYUV420(const QImage& image, Image_YUV420P& yuvData)
  215. {
  216. int width = image.width();
  217. int height = image.height();
  218. const int ySize = yuvData.width * yuvData.height;
  219. const int uvSize = ySize / 4;
  220. QImage image_rgb(width, height, QImage::Format_RGB888);
  221. yuvData.width = width;
  222. yuvData.height = height;
  223. yuvData.yData.resize(ySize);
  224. yuvData.uData.resize(uvSize);
  225. yuvData.vData.resize(uvSize);
  226. for (int y = 0; y < height; ++y) {
  227. for (int x = 0; x < width; ++x) {
  228. QColor color = image.pixelColor(x, y);
  229. int r = color.red();
  230. int g = color.green();
  231. int b = color.blue();
  232. int yIndex = y * width + x;
  233. yuvData.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
  234. if (y % 2 == 0 && x % 2 == 0) {
  235. int uvIndex = (y / 2) * (width / 2) + (x / 2);
  236. yuvData.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
  237. yuvData.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
  238. }
  239. }
  240. }
  241. return true;
  242. }