我试图将解码后的帧从FFMPEG渲染到QOpenGLWindow。 FFMPEG给我NV12 AVFrame或YUV420p或RGB。 我选择最简单的RGB。
我创建了一个继承自QOpenGLWindow和QOpenGLFunctions_3_3的c_gl_video_yuv类。
我想使用着色器绘制矩形并使用视频帧对其进行纹理处理。 (对于YUV,我希望sader将其转换为RGB并应用纹理)
我的c_gl_video_yuv类定义如下:
class c_gl_video_yuv : public QOpenGLWindow,protected QOpenGLFunctions_3_3_Core
{
public:
c_gl_video_yuv();
~c_gl_video_yuv();
---
void update_texture(AVFrame *frame, int w, int h);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void paintEvent(QPaintEvent *);
private:
---
GLuint textures[2];
---
// Shader program
QOpenGLShaderProgram *m_program;
GLint locVertices;
GLint locTexcoord;
};
我初始化OpenGL:
void c_gl_video_yuv::initializeGL()
{
// Init shader program
initializeOpenGLFunctions();
glGenTextures(2, textures);
/* Apply some filter on the texture */
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
qDebug() << "c_gl_video_yuv::initializeGL() initialise shader"<< endl;
m_program = new QOpenGLShaderProgram(this);
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/Ressources/vertex_yuv.glsl");
m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/Ressources/rgb_to_rgb_shader .glsl");
m_program->link();
// /* Grab location of shader attributes. */
locVertices = m_program->attributeLocation("position");
locTexcoord = m_program->attributeLocation("texpos");
/* Enable vertex arrays to push the data. */
glEnableVertexAttribArray(locVertices);
glEnableVertexAttribArray(locTexcoord);
/* set data in the arrays. */
glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0,
&vertices[0][0]);
glVertexAttribPointer(locTexcoord, 2, GL_FLOAT, GL_FALSE, 0,
&texcoords[0][0]);
// GL options
glEnable(GL_DEPTH_TEST);
}
我渲染
void c_gl_video_yuv::paintGL()
{
qDebug() << "paintGL() set viewport "<<endl;
glViewport(0, 0, width(), height());
/* Clear background. */
glClearColor(0.5f,0.5f,0.5f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if(first_frame)
{
qDebug() << "paintGL() Bind shader" << endl;
m_program->bind();
/* Get Ytex attribute to associate to TEXTURE0 */
m_program->bindAttributeLocation("Ytex",0);
m_program->bindAttributeLocation("UVtex",1);
qDebug() << "paintGL() Bind texture" << endl;
if(!is_init)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, frame_width, frame_height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0] );
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, frame_width, frame_height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0] );
is_init = true;
}
else
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, frame_width, frame_height, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, frame_width, frame_height, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0]);
}
glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(locTexcoord, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
m_program->release();
}
}
顶点着色器是:
#version 330 core
attribute vec3 position;
attribute vec2 texpos;
varying vec2 opos;
void main(void)
{
opos = texpos;
gl_Position = vec4(position, 1.0);
}
和Fragment着色器是:
version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D YImage;
uniform sampler2D UVImage;
const vec3 r_c = vec3(1.164383, 0.000000, 1.596027);
const vec3 g_c = vec3(1.164383, -0.391762, -0.812968);
const vec3 b_c = vec3(1.164383, 2.017232, 0.000000);
const vec3 offset = vec3(-0.0625, -0.5, -0.5);
void main()
{
float y_val = texture(YImage, TexCoords).r;
float u_val = texture(UVImage, TexCoords).r;
float v_val = texture(UVImage, TexCoords).g;
vec3 yuv = vec3(y_val, u_val, v_val);
yuv += offset;
color.r = dot(yuv, r_c);
color.g = dot(yuv, g_c);
color.b = dot(yuv, b_c);
color.a = 1.0;
};
(对于RGB帧a替换thevec3(1.164383,0.000000,1.596027);由vec3(1.0,1.00000000,1.0);
所以在我收到一个框架之前它什么也没渲染,只是一个灰色的窗口 - 没有 收到帧后,纹理会上传,着色器会正常创建播放器。但是没有任何东西看起来甚至没有黑色矩形,只是简单的灰色。
有什么问题? 它不是上传纹理的正确方法,或者我的顶点不是创建的? 当然,我宣布我的vetrtices eand texture coordonate
const GLfloat vertices[][2] = {
{-1.f, -1.f},
{1.f, -1.f},
{-1.f, 1.f},
{1.f, 1.f}
};
const GLfloat texcoords[][2] = {
{0.0f, 1.0f},
{1.0f, 1.0f},
{0.0f, 0.0f},
{1.0f, 0.0f}
};
我对OpenGL很陌生,所以它在我脑海中非常模糊,但我认为绘制一个带有流纹理的矩形并不是很难。 也许我应该使用vbo或fbo但我仍然不能理解这一点。
如果有人可以帮助我,我将不胜感激! 感谢