|
|
@@ -111,93 +111,93 @@ void PlayerGLWidget::updateFrame(Image_QImage& image)
|
|
|
update();
|
|
|
}
|
|
|
|
|
|
-void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
|
|
|
-{
|
|
|
- int width = image.width();
|
|
|
- int height = image.height();
|
|
|
+// void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
|
|
|
+// {
|
|
|
+// int width = image.width();
|
|
|
+// int height = image.height();
|
|
|
|
|
|
- int frameSize = width * height;
|
|
|
- int chromaSize = frameSize / 4;
|
|
|
+// int frameSize = width * height;
|
|
|
+// int chromaSize = frameSize / 4;
|
|
|
|
|
|
- uint8_t* yuv = new uint8_t[frameSize + chromaSize * 2];
|
|
|
- uint8_t* yPlane = yuv;
|
|
|
- uint8_t* uPlane = yuv + frameSize;
|
|
|
- uint8_t* vPlane = yuv + frameSize + chromaSize;
|
|
|
+// uint8_t* yuv = new uint8_t[frameSize + chromaSize * 2];
|
|
|
+// uint8_t* yPlane = yuv;
|
|
|
+// uint8_t* uPlane = yuv + frameSize;
|
|
|
+// uint8_t* vPlane = yuv + frameSize + chromaSize;
|
|
|
|
|
|
- auto rgb = image.bits();
|
|
|
+// auto rgb = image.bits();
|
|
|
|
|
|
- for (int j = 0; j < height; j++) {
|
|
|
- for (int i = 0; i < width; i++) {
|
|
|
- int r = rgb[(j * width + i) * 3];
|
|
|
- int g = rgb[(j * width + i) * 3 + 1];
|
|
|
- int b = rgb[(j * width + i) * 3 + 2];
|
|
|
+// for (int j = 0; j < height; j++) {
|
|
|
+// for (int i = 0; i < width; i++) {
|
|
|
+// int r = rgb[(j * width + i) * 3];
|
|
|
+// int g = rgb[(j * width + i) * 3 + 1];
|
|
|
+// int b = rgb[(j * width + i) * 3 + 2];
|
|
|
|
|
|
- int y = (0.299 * r) + (0.587 * g) + (0.114 * b);
|
|
|
- int u = (-0.169 * r) - (0.331 * g) + (0.5 * b) + 128;
|
|
|
- int v = (0.5 * r) - (0.419 * g) - (0.081 * b) + 128;
|
|
|
+// int y = (0.299 * r) + (0.587 * g) + (0.114 * b);
|
|
|
+// int u = (-0.169 * r) - (0.331 * g) + (0.5 * b) + 128;
|
|
|
+// int v = (0.5 * r) - (0.419 * g) - (0.081 * b) + 128;
|
|
|
|
|
|
- yPlane[j * width + i] = std::clamp(y, 0, 255);
|
|
|
+// yPlane[j * width + i] = std::clamp(y, 0, 255);
|
|
|
|
|
|
- if (j % 2 == 0 && i % 2 == 0) {
|
|
|
- uPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(u, 0, 255);
|
|
|
- vPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(v, 0, 255);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+// if (j % 2 == 0 && i % 2 == 0) {
|
|
|
+// uPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(u, 0, 255);
|
|
|
+// vPlane[(j / 2) * (width / 2) + (i / 2)] = std::clamp(v, 0, 255);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
|
|
|
- yuv420.width = width;
|
|
|
- yuv420.height = height;
|
|
|
- yuv420.yData.resize(frameSize);
|
|
|
- yuv420.uData.resize(chromaSize);
|
|
|
- yuv420.vData.resize(chromaSize);
|
|
|
+// yuv420.width = width;
|
|
|
+// yuv420.height = height;
|
|
|
+// yuv420.yData.resize(frameSize);
|
|
|
+// yuv420.uData.resize(chromaSize);
|
|
|
+// yuv420.vData.resize(chromaSize);
|
|
|
|
|
|
- yuv420.yData.append(reinterpret_cast<char*>(yPlane), frameSize);
|
|
|
- yuv420.uData.append(reinterpret_cast<char*>(uPlane), chromaSize);
|
|
|
- yuv420.vData.append(reinterpret_cast<char*>(vPlane), chromaSize);
|
|
|
+// yuv420.yData.append(reinterpret_cast<char*>(yPlane), frameSize);
|
|
|
+// yuv420.uData.append(reinterpret_cast<char*>(uPlane), chromaSize);
|
|
|
+// yuv420.vData.append(reinterpret_cast<char*>(vPlane), chromaSize);
|
|
|
|
|
|
-}
|
|
|
+// }
|
|
|
|
|
|
|
|
|
-// void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
|
|
|
-// {
|
|
|
-// int width = image.width();
|
|
|
-// int height = image.height();
|
|
|
-// int ySize = width * height;
|
|
|
-// int chromaWidth = (width + 1) / 2;
|
|
|
-// int chromaHeight = (height + 1) / 2;
|
|
|
-// int uvSize = chromaWidth * chromaHeight;
|
|
|
+void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
|
|
|
+{
|
|
|
+ int width = image.width();
|
|
|
+ int height = image.height();
|
|
|
+ int ySize = width * height;
|
|
|
+ int chromaWidth = (width + 1) / 2;
|
|
|
+ int chromaHeight = (height + 1) / 2;
|
|
|
+ int uvSize = chromaWidth * chromaHeight;
|
|
|
|
|
|
-// yuv420.width = width;
|
|
|
-// yuv420.height = height;
|
|
|
+ yuv420.width = width;
|
|
|
+ yuv420.height = height;
|
|
|
|
|
|
-// yuv420.yData.resize(ySize);
|
|
|
-// yuv420.uData.resize(uvSize);
|
|
|
-// yuv420.vData.resize(uvSize);
|
|
|
+ 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();
|
|
|
+ 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;
|
|
|
-// if (yIndex >= 0 && yIndex < ySize) {
|
|
|
-// yuv420.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
|
|
|
-// }
|
|
|
+ int yIndex = y * width + x;
|
|
|
+ if (yIndex >= 0 && yIndex < ySize) {
|
|
|
+ yuv420.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
|
|
|
+ }
|
|
|
|
|
|
-// if (y % 2 == 0 && x % 2 == 0)
|
|
|
-// {
|
|
|
-// int uvIndex = (y / 2) * chromaWidth + (x / 2);
|
|
|
-// if (uvIndex >= 0 && uvIndex < uvSize)
|
|
|
-// {
|
|
|
-// yuv420.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
|
|
|
-// yuv420.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
+ if (y % 2 == 0 && x % 2 == 0)
|
|
|
+ {
|
|
|
+ int uvIndex = (y / 2) * chromaWidth + (x / 2);
|
|
|
+ if (uvIndex >= 0 && uvIndex < uvSize)
|
|
|
+ {
|
|
|
+ yuv420.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
|
|
|
+ yuv420.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
void PlayerGLWidget::initializeGL()
|
|
|
{
|
|
|
@@ -382,51 +382,62 @@ 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 (shaderProgram == 0 || VAO == 0 || textureIdY_ == 0 || textureIdU_ == 0 || textureIdV_ == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (m_yData.isEmpty() || m_uData.isEmpty() || m_vData.isEmpty()) {
|
|
|
return;
|
|
|
}
|
|
|
int uvWidth = m_imageSize.width() / 2;
|
|
|
int uvHeight = m_imageSize.height() / 2;
|
|
|
|
|
|
+ // 仅对“缩小显示”启用 mipmap + 三线性过滤,减少锯齿/闪烁;放大显示则保持线性过滤
|
|
|
+ const bool downscaling = (width() > 0 && height() > 0) &&
|
|
|
+ (width() < m_imageSize.width() || height() < m_imageSize.height());
|
|
|
+
|
|
|
// 使用着色器程序
|
|
|
glUseProgram(shaderProgram);
|
|
|
|
|
|
+ // 设置纹理单元
|
|
|
+ glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0);
|
|
|
+ glUniform1i(glGetUniformLocation(shaderProgram, "textureU"), 1);
|
|
|
+ glUniform1i(glGetUniformLocation(shaderProgram, "textureV"), 2);
|
|
|
+
|
|
|
// 更新纹理数据
|
|
|
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());
|
|
|
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
+ // OpenGL 3.3 Core 下 GL_LUMINANCE 已移除,使用 GL_RED/GL_R8
|
|
|
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, m_imageSize.width(), m_imageSize.height(), 0, GL_RED, GL_UNSIGNED_BYTE, m_yData.data());
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
- glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, downscaling ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
|
|
+ if (downscaling) {
|
|
|
+ glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
+ }
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
glBindTexture(GL_TEXTURE_2D, textureIdU_);
|
|
|
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data());
|
|
|
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, uvWidth, uvHeight, 0, GL_RED, GL_UNSIGNED_BYTE, m_uData.data());
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
- glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, downscaling ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
|
|
+ if (downscaling) {
|
|
|
+ glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
+ }
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE2);
|
|
|
glBindTexture(GL_TEXTURE_2D, textureIdV_);
|
|
|
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data());
|
|
|
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, uvWidth, uvHeight, 0, GL_RED, GL_UNSIGNED_BYTE, m_vData.data());
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
- glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
-
|
|
|
- // 设置纹理单元
|
|
|
- glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0);
|
|
|
- glUniform1i(glGetUniformLocation(shaderProgram, "textureU"), 1);
|
|
|
- glUniform1i(glGetUniformLocation(shaderProgram, "textureV"), 2);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, downscaling ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
|
|
+ if (downscaling) {
|
|
|
+ glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
+ }
|
|
|
|
|
|
// 绘制四边形
|
|
|
glBindVertexArray(VAO);
|