opengl渲染yuv支持改变宽高

This commit is contained in:
Barry 2018-10-28 22:53:14 +08:00
parent ea8f88b672
commit 2bcd3e08cb
3 changed files with 157 additions and 142 deletions

View file

@ -45,7 +45,7 @@ Dialog::Dialog(QWidget *parent) :
{
ui->setupUi(this);
w2 = new YUVGLWidget(this);
w2 = new YUVGLWidget(this);
w2->resize(ui->imgLabel->size());
w2->move(230, 20);
@ -73,12 +73,8 @@ Dialog::Dialog(QWidget *parent) :
frames.lock();
const AVFrame *frame = frames.consumeRenderedFrame();
//saveAVFrame_YUV_ToTempFile(frame);
w2->setFrameSize(frame->width, frame->height);
w2->setYPixels(frame->data[0], frame->linesize[0]);
w2->setUPixels(frame->data[1], frame->linesize[1]);
w2->setVPixels(frame->data[2], frame->linesize[2]);
w2->update();
w2->setFrameSize(QSize(frame->width, frame->height));
w2->updateTextures(frame->data[0], frame->data[1], frame->data[2], frame->linesize[0], frame->linesize[1], frame->linesize[2]);
frames.unLock();
},Qt::QueuedConnection);
}

View file

@ -1,50 +1,8 @@
#include <QOpenGLShaderProgram>
#include "yuvglwidget.h"
YUVGLWidget::YUVGLWidget(QWidget *parent) :
QOpenGLWidget(parent)
{
// 设置opengl兼容性格式为CoreProfile
QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat();
defaultFormat.setProfile(QSurfaceFormat::CoreProfile);
defaultFormat.setVersion(3, 3); // Adapt to your system
QSurfaceFormat::setDefaultFormat(defaultFormat);
setFormat(defaultFormat);
}
YUVGLWidget::~YUVGLWidget()
{
makeCurrent();
if (y_tex) glDeleteTextures(1, &y_tex);
if (u_tex) glDeleteTextures(1, &u_tex);
if (v_tex) glDeleteTextures(1, &v_tex);
doneCurrent();
}
QSize YUVGLWidget::minimumSizeHint() const
{
return QSize(50, 50);
}
QSize YUVGLWidget::sizeHint() const
{
return QSize(3840, 2160); // 4k video
}
void YUVGLWidget::setFrameSize(unsigned int width, unsigned int height)
{
m_frameWidth = width;
m_frameHeight = height;
}
void YUVGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glDisable(GL_DEPTH_TEST);
initializeTextures();
QString vert = R"(
static QString vertShader = R"(
#version 150 core
uniform mat4 u_pm;
uniform vec4 draw_pos;
@ -75,7 +33,7 @@ void YUVGLWidget::initializeGL()
}
)";
QString frag = R"(
static QString fragShader = R"(
#version 150 core
uniform sampler2D y_tex;
uniform sampler2D u_tex;
@ -101,23 +59,49 @@ void YUVGLWidget::initializeGL()
fragcolor.b = dot(yuv, B_cf);
}
)";
// Setup shaders
m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vert);
m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, frag);
// m_program.bindAttributeLocation("y_tex", 0);
// m_program.bindAttributeLocation("u_tex", 1);
// m_program.bindAttributeLocation("v_tex", 2);
YUVGLWidget::YUVGLWidget(QWidget *parent) :
QOpenGLWidget(parent)
{
/*
// 设置opengl兼容性格式为CoreProfile
QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat();
defaultFormat.setProfile(QSurfaceFormat::CoreProfile);
defaultFormat.setVersion(3, 3); // Adapt to your system
QSurfaceFormat::setDefaultFormat(defaultFormat);
setFormat(defaultFormat);
*/
}
m_program.link();
m_program.bind();
YUVGLWidget::~YUVGLWidget()
{
makeCurrent();
deInitTextures();
doneCurrent();
}
m_program.setUniformValue("y_tex", 0);
m_program.setUniformValue("u_tex", 1);
m_program.setUniformValue("v_tex", 2);
QSize YUVGLWidget::minimumSizeHint() const
{
return QSize(50, 50);
}
u_pos = m_program.uniformLocation("draw_pos");
QSize YUVGLWidget::sizeHint() const
{
return size();
}
void YUVGLWidget::setFrameSize(const QSize& frameSize)
{
if (m_frameSize != frameSize) {
m_frameSize = frameSize;
m_needInit = true;
}
}
void YUVGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glDisable(GL_DEPTH_TEST);
m_vao.create();
}
@ -125,86 +109,120 @@ void YUVGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// init
if (m_needInit) {
initShader();
initTextures();
m_needInit = false;
}
m_vao.bind();
QMatrix4x4 m;
m.ortho(0, width(), height(), 0, 0.0, 100.0f);
m_program.setUniformValue("u_pm", m);
glUniform4f(u_pos, 0, 0, width(), height());
if (m_program) {
QMatrix4x4 matrix;
matrix.ortho(0, width(), height(), 0, 0.0, 100.0f);
m_program->setUniformValue("u_pm", matrix);
glUniform4f(m_drawPos, 0, 0, width(), height());
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, y_tex);
glBindTexture(GL_TEXTURE_2D, m_texture[Texture_Y]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, u_tex);
glBindTexture(GL_TEXTURE_2D, m_texture[Texture_U]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, v_tex);
glBindTexture(GL_TEXTURE_2D, m_texture[Texture_V]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void YUVGLWidget::setYPixels(uint8_t* pixels, int stride)
void YUVGLWidget::resizeGL(int width, int height)
{
bindPixelTexture(y_tex, YTexture, pixels, stride);
glViewport(0, 0, width, height);
}
void YUVGLWidget::setUPixels(uint8_t* pixels, int stride)
void YUVGLWidget::initShader()
{
bindPixelTexture(u_tex, UTexture, pixels, stride);
if (m_program) {
m_program->release();
delete m_program;
m_program = Q_NULLPTR;
}
m_program = new QOpenGLShaderProgram(this);
// Setup shaders
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertShader);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragShader);
m_program->link();
m_program->bind();
m_program->setUniformValue("y_tex", Texture_Y);
m_program->setUniformValue("u_tex", Texture_U);
m_program->setUniformValue("v_tex", Texture_V);
m_drawPos = m_program->uniformLocation("draw_pos");
}
void YUVGLWidget::setVPixels(uint8_t* pixels, int stride)
void YUVGLWidget::updateTextures(quint8 *dataY, quint8 *dataU, quint8 *dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV)
{
bindPixelTexture(v_tex, VTexture, pixels, stride);
bindPixelTexture(m_texture[Texture_Y], Texture_Y, dataY, linesizeY);
bindPixelTexture(m_texture[Texture_U], Texture_U, dataU, linesizeU);
bindPixelTexture(m_texture[Texture_V], Texture_V, dataV, linesizeV);
update();
}
void YUVGLWidget::initializeTextures()
{
//TODO: use FBO?
// Setup textures
glGenTextures(1, &y_tex);
glBindTexture(GL_TEXTURE_2D, y_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, m_frameWidth, m_frameHeight, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glGenTextures(1, &u_tex);
glBindTexture(GL_TEXTURE_2D, u_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, m_frameWidth/2, m_frameHeight/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glGenTextures(1, &v_tex);
glBindTexture(GL_TEXTURE_2D, v_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, m_frameWidth/2, m_frameHeight/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
}
void YUVGLWidget::bindPixelTexture(GLuint texture, YUVGLWidget::YUVTextureType textureType, uint8_t* pixels, int stride)
void YUVGLWidget::bindPixelTexture(GLuint texture, YUVTextureType textureType, quint8* pixels, quint32 stride)
{
if (!pixels)
return;
unsigned int const width = textureType == YTexture ? m_frameWidth : m_frameWidth/2;
unsigned int const height = textureType == YTexture ? m_frameHeight : m_frameHeight/2;
QSize size(0, 0);
calcTextureSize(textureType, size);
makeCurrent();
glBindTexture(GL_TEXTURE_2D, texture);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, pixels);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, m_frameWidth/2, m_frameHeight/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), GL_RED, GL_UNSIGNED_BYTE, pixels);
doneCurrent();
}
void YUVGLWidget::initTexture(qint32 textureType)
{
if (Texture_NULL >= textureType || Texture_Size <= textureType) {
return;
}
glGenTextures(1, &m_texture[textureType]);
glBindTexture(GL_TEXTURE_2D, m_texture[textureType]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
QSize size(0, 0);
calcTextureSize(textureType, size);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size.width(), size.height(), 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
}
void YUVGLWidget::initTextures()
{
//TODO: use FBO?
deInitTextures();
for (int i = Texture_Y; i < Texture_Size; i++) {
initTexture(i);
}
}
void YUVGLWidget::deInitTextures()
{
glDeleteTextures(3, m_texture);
memset(m_texture, 0, Texture_Size);
}
void YUVGLWidget::calcTextureSize(qint32 textureType, QSize &size)
{
if (Texture_NULL >= textureType || Texture_Size <= textureType) {
return;
}
if (Texture_Y == textureType) {
size = m_frameSize;
} else {
size = m_frameSize / 2;
}
}

View file

@ -2,11 +2,11 @@
#define YUVGLWIDGET_H
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLWidget>
#include <QSurfaceFormat>
//#include <QSurfaceFormat>
class QOpenGLShaderProgram;
class YUVGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
@ -17,39 +17,40 @@ public:
QSize minimumSizeHint() const override;
QSize sizeHint() const override;
void setFrameSize(unsigned int width, unsigned int height);
void setYPixels(uint8_t* pixels, int stride);
void setUPixels(uint8_t* pixels, int stride);
void setVPixels(uint8_t* pixels, int stride);
void setFrameSize(const QSize& frameSize);
void updateTextures(quint8* dataY, quint8* dataU, quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV);
protected:
void initializeGL() override;
void paintGL() override;
//void resizeGL(int width, int height) override;
void resizeGL(int width, int height) override;
private:
enum YUVTextureType {
YTexture,
UTexture,
VTexture
Texture_NULL = -1,
Texture_Y,
Texture_U,
Texture_V,
Texture_Size
};
void initializeTextures();
void bindPixelTexture(GLuint texture, YUVTextureType textureType, uint8_t* pixels, int stride);
void initShader();
void initTexture(qint32 textureType);
void initTextures();
void deInitTextures();
void calcTextureSize(qint32 textureType, QSize& size);
QOpenGLShaderProgram m_program;
void bindPixelTexture(GLuint texture, YUVTextureType textureType, quint8* pixels, quint32 stride);
private:
QSize m_frameSize = {0, 0};
bool m_needInit = false;
QOpenGLShaderProgram* m_program = Q_NULLPTR;
QOpenGLVertexArrayObject m_vao;
//unsigned int m_frameWidth {3840}; // 4k
//unsigned int m_frameHeight {2160};
unsigned int m_frameWidth {2160};
unsigned int m_frameHeight {1080};
GLuint y_tex {0};
GLuint u_tex {0};
GLuint v_tex {0};
GLint u_pos {0};
// yuv texture
GLuint m_texture[Texture_Size] = {0};
GLint m_drawPos = -1;
};
#endif // YUVGLWIDGET_H