#include "PlayerGLWidget.h" #include // 添加此行 #include "LHQLogAPI.h" PlayerGLWidget::PlayerGLWidget(QWidget *parent) : QOpenGLWidget(parent) { // QString imagePath = QApplication::applicationDirPath() + "/0.jpg"; // QImage image(imagePath); // Image_YUV420 yuv420; // convertQImageToYUV420(image, yuv420); // /* 显示图片 */ // updateFrame(yuv420); } PlayerGLWidget::~PlayerGLWidget() { } /* 设置一张图片,用于显示默认的图片 */ void PlayerGLWidget::setImage(const QImage& image) { Image_YUV420 yuv420; convertQImageToYUV420(image, yuv420); /* 显示图片 */ updateFrame(yuv420); } /* 刷新一帧 */ void PlayerGLWidget::updateFrame(Image_YUV420& image) { m_yData = std::move(image.yData); m_uData = std::move(image.uData); m_vData = std::move(image.vData); m_imageSize = QSize(image.width, image.height); update(); } /* 刷新一帧QImage */ void PlayerGLWidget::updateFrame(Image_QImage& image) { LH_WRITE_LOG("图片宽度: " + QString::number(image.image.width()) + "图片高度: " + QString::number(image.image.height())); convertQImageToYUV420(image.image, m_YUV420); m_yData = m_YUV420.yData; m_uData = m_YUV420.uData; m_vData = m_YUV420.vData; m_imageSize = QSize(m_YUV420.width, m_YUV420.height); update(); } void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420) { int width = image.width(); int height = image.height(); int ySize = width * height; int uvSize = ySize / 4; yuv420.width = width; yuv420.height = height; yuv420.yData.resize(ySize); yuv420.uData.resize(uvSize); yuv420.vData.resize(uvSize); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { QColor color = image.pixelColor(x, y); int r = color.red(); int g = color.green(); int b = color.blue(); int yIndex = y * width + x; yuv420.yData[yIndex] = static_cast((0.257 * r) + (0.504 * g) + (0.098 * b) + 16); if (y % 2 == 0 && x % 2 == 0) { int uvIndex = (y / 2) * (width / 2) + (x / 2); yuv420.uData[uvIndex] = static_cast((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128); yuv420.vData[uvIndex] = static_cast((0.439 * r) - (0.368 * g) - (0.071 * b) + 128); } } } } void PlayerGLWidget::initializeGL() { initializeOpenGLFunctions(); // 确保初始化 OpenGL 函数 // 创建并编译顶点着色器 const char* vertexShaderSource = R"( #version 330 core layout(location = 0) in vec3 aPos; layout(location = 1) in vec2 aTexCoord; out vec2 TexCoord; void main() { gl_Position = vec4(aPos, 1.0); TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); // 翻转纹理坐标 } )"; GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); glCompileShader(vertexShader); // 创建并编译片段着色器 const char* fragmentShaderSource = R"( #version 330 core out vec4 FragColor; in vec2 TexCoord; uniform sampler2D textureY; uniform sampler2D textureU; uniform sampler2D textureV; void main() { float y = texture(textureY, TexCoord).r; float u = texture(textureU, TexCoord).r - 0.5; float v = texture(textureV, TexCoord).r - 0.5; float r = y + 1.402 * v; float g = y - 0.344 * u - 0.714 * v; float b = y + 1.772 * u; FragColor = vec4(r, g, b, 1.0); } )"; GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader); // 链接着色器程序 shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); // 确保传递的是程序对象和着色器对象 glAttachShader(shaderProgram, fragmentShader); // 确保传递的是程序对象和着色器对象 glLinkProgram(shaderProgram); // 删除着色器对象 glDeleteShader(vertexShader); glDeleteShader(fragmentShader); // 创建纹理 glGenTextures(1, &textureIdY_); glGenTextures(1, &textureIdU_); glGenTextures(1, &textureIdV_); glBindTexture(GL_TEXTURE_2D, textureIdY_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, textureIdU_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, textureIdV_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 设置顶点数据和缓冲 float vertices[] = { // positions // texture coords -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f }; unsigned int indices[] = { 0, 1, 2, 2, 3, 0 }; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 位置属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 纹理坐标属性 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void PlayerGLWidget::resizeGL(int w, int h) { Ortho2DSize_.setWidth(w); Ortho2DSize_.setHeight(h); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, Ortho2DSize_.width(), Ortho2DSize_.height(), 0, -1, 1); glMatrixMode(GL_MODELVIEW); } void PlayerGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT); if (m_yData.isEmpty() || m_uData.isEmpty() || m_vData.isEmpty()) { return; } // 使用着色器程序 glUseProgram(shaderProgram); // 更新纹理数据 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureIdY_); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width(), m_imageSize.height(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_yData.data()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureIdU_); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width() / 2, m_imageSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureIdV_); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width() / 2, m_imageSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data()); // 设置纹理单元 glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0); glUniform1i(glGetUniformLocation(shaderProgram, "textureU"), 1); glUniform1i(glGetUniformLocation(shaderProgram, "textureV"), 2); // 绘制四边形 glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); }