这里提供一个c++使用opengl将yuv渲染到widget窗口中的完整程序示例:
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QFile>
class YUVRenderer : public QOpenGLWidget, protected QOpenGLFunctions {
public:
YUVRenderer(QWidget *parent = nullptr) : QOpenGLWidget(parent), m_program(nullptr),
m_yTexture(nullptr), m_uTexture(nullptr), m_vTexture(nullptr) {}
virtual ~YUVRenderer() {}
void initializeGL() override {
initializeOpenGLFunctions();
// 创建着色器程序
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/yuv.vert");
m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/yuv.frag");
m_program->link();
// 获取着色器中的变量位置
m_positionAttr = m_program->attributeLocation("aPosition");
m_texCoordAttr = m_program->attributeLocation("aTexCoord");
m_yTextureUniform = m_program->uniformLocation("uYTexture");
m_uTextureUniform = m_program->uniformLocation("uUTexture");
m_vTextureUniform = m_program->uniformLocation("uVTexture");
// 创建纹理对象并设置参数
m_yTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_uTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_vTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_yTexture->setMinificationFilter(QOpenGLTexture::Nearest);
m_yTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
m_uTexture->setMinificationFilter(QOpenGLTexture::Nearest);
m_uTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
m_vTexture->setMinificationFilter(QOpenGLTexture::Nearest);
m_vTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
// 加载测试yuv数据
loadYUV(":/test.yuv", 1920, 1080);
}
void paintGL() override {
glClearColor(0.1f, 0.2f, 0.3f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_program->bind();
glEnableVertexAttribArray(m_positionAttr);
glVertexAttribPointer(m_positionAttr, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, m_vertices);
glEnableVertexAttribArray(m_texCoordAttr);
glVertexAttribPointer(m_texCoordAttr, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, m_vertices + 2);
// 绑定纹理并设置采样器参数
m_yTexture->bind(0);
m_yTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
m_yTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
m_program->setUniformValue(m_yTextureUniform, 0);
m_uTexture->bind(1);
m_uTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
m_uTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
m_program->setUniformValue(m_uTextureUniform, 1);
m_vTexture->bind(2);
m_vTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
m_vTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
m_program->setUniformValue(m_vTextureUniform, 2);
// 绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(m_positionAttr);
glDisableVertexAttribArray(m_texCoordAttr);
m_program->release();
}
private:
void loadYUV(const QString &path, int width, int height) {
QFile file(path);
if (!file.open(QFile::ReadOnly)) {
qWarning("Failed to open YUV file.");
return;
}
QByteArray data = file.readAll();
if (data.size() != width * height * 3 / 2) {
qWarning("Invalid YUV data size.");
return;
}
const uchar *yData = reinterpret_cast<const uchar *>(data.constData());
const uchar *uData = yData + width * height;
const uchar *vData = uData + width * height / 4;
m_yTexture->setSize(width, height);
m_uTexture->setSize(width / 2, height / 2);
m_vTexture->setSize(width / 2, height / 2);
m_yTexture->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yData);
m_uTexture->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, uData);
m_vTexture->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, vData);
// 设置顶点数据
m_vertices[0] = -1.f;
m_vertices[1] = 1.f;
m_vertices[2] = 0.f;
m_vertices[3] = 1.f;
m_vertices[4] = -1.f;
m_vertices[5] = -1.f;
m_vertices[6] = 0.f;
m_vertices[7] = 0.f;
m_vertices[8] = 1.f;
m_vertices[9] = 1.f;
m_vertices[10] = 1.f;
m_vertices[11] = 1.f;
m_vertices[12] = 1.f;
m_vertices[13] = -1.f;
m_vertices[14] = 1.f;
m_vertices[15] = 0.f;
}
QOpenGLShaderProgram *m_program;
int m_positionAttr;
int m_texCoordAttr;
int m_yTextureUniform;
int m_uTextureUniform;
int m_vTextureUniform;
QOpenGLTexture *m_yTexture;
QOpenGLTexture *m_uTexture;
QOpenGLTexture *m_vTexture;
float m_vertices[16];
};
其中,YUVRenderer
类继承自QOpenGLWidget
,并实现了initializeGL()
和paintGL()
方法。在initializeGL()
方法中,我们创建着色器程序,获取变量位置,并创建纹理对象并设置参数。另外,为了简化示例代码,我们加入了一个loadYUV()
方法来加载测试yuv数据,并设置顶点数据。
在paintGL()
方法中,我们首先清空颜色缓存和深度缓存,然后绑定着色器程序、顶点属性和纹理,并绘制。最后,我们解绑顶点属性和纹理,并释放着色器程序。
需要注意的是,这里使用了一个yuv.vert
和一个yuv.frag
着色器文件,你需要将这两个文件放到工程资源文件中,并在.pro
文件中添加以下语句:
RESOURCES += \
shaders.qrc
其中,shaders.qrc
为资源文件,你可以根据自己的需要进行设置。具体的.qrc
文件格式和用法,请参考Qt官方文档。
yuv.vert
文件内容如下:
attribute vec2 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
vTexCoord = aTexCoord;
}
yuv.frag
文件内容如下:
uniform sampler2D uYTexture;
uniform sampler2D uUTexture;
uniform sampler2D uVTexture;
varying vec2 vTexCoord;
const mat3 yuv2rgb = mat3(
1.164383561643836, 0, 1.5960267857142858,
1.164383561643836, -0.391762290094913, -0.8129676472377709,
1.164383561643836, 2.0172321428571428, 0
);
void main() {
float y = texture2D(uYTexture, vTexCoord).r;
float u = texture2D(uUTexture, vTexCoord / 2.0).r - 0.5;
float v = texture2D(uVTexture, vTexCoord / 2.0).r - 0.5;
vec3 yuv = vec3(y, u, v);
vec3 rgb = yuv2rgb * yuv;
gl_FragColor = vec4(rgb, 1.0);
}
这两个着色器文件实现了将yuv转换为rgb的功能,具体实现方式可以参考yuv.frag
中的代码。
最后,在主函数中创建一个YUVRenderer
对象,并将其设置为主窗口的中心组件即可:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
YUVRenderer renderer(&window);
window.setCentralWidget(&renderer);
window.resize(1920, 1080);
window.show();
return app.exec();
}
以上就是一个c++使用opengl将yuv渲染到widget窗口中的完整程序示例。当你运行这个程序时,就会看到一个显示yuv数据的窗口。