You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
7.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "glyuvwidget.h"
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QDebug>
#include <QFile>
#define VERTEXIN 0
#define TEXTUREIN 1
GLYuvWidget::GLYuvWidget(QWidget *parent):
QOpenGLWidget(parent)
{
}
GLYuvWidget::~GLYuvWidget()
{
makeCurrent();
m_vbo.destroy();
m_textureY->destroy();
m_textureU->destroy();
m_textureV->destroy();
doneCurrent();
}
void GLYuvWidget::slotShowYuv(QByteArray buffer, uint width, uint height)
{
m_videoWidth = width;
m_videoHeight = height;
QFile *file = new QFile;
file->setFileName("android.yuv");
bool ok = file->open(QIODevice::WriteOnly | QIODevice::Append);
if(ok) {
QDataStream out(file);
//out.setVersion(QDataStream::Qt_5_7);
out << buffer;
file->close();
delete(file);
}
m_buffer.setRawData(buffer, buffer.size());
m_yuvPtr = m_buffer.data();
update();
}
void GLYuvWidget::initializeGL()
{
initializeOpenGLFunctions();
glDisable(GL_DEPTH_TEST); // 关闭深度缓冲测试对于2D图形来说没用
static const GLfloat vertices[]{
// 顶点坐标(-1.0,1.0)
-1.0f,-1.0f,
-1.0f,+1.0f,
+1.0f,+1.0f,
+1.0f,-1.0f,
// 纹理坐标(0.0,1.0)
0.0f,1.0f,
0.0f,0.0f,
1.0f,0.0f,
1.0f,1.0f,
};
// 初始化顶点缓冲
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(vertices,sizeof(vertices));
// 顶点着色器
QOpenGLShader *vShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
// 顶点着色器源码
const char *vertexSrc =
"attribute vec4 vertexIn; \
attribute vec2 textureIn; \
varying vec2 textureOut; \
void main(void) \
{ \
gl_Position = vertexIn; \
textureOut = textureIn; \
}";
vShader->compileSourceCode(vertexSrc);
// 片段着色器
QOpenGLShader *fShader = new QOpenGLShader(QOpenGLShader::Fragment, this);
// 片段着色器源码
const char *fragmentSrc =
"varying vec2 textureOut; \
uniform sampler2D tex_y; \
uniform sampler2D tex_u; \
uniform sampler2D tex_v; \
void main(void) \
{ \
vec3 yuv; \
vec3 rgb; \
yuv.x = texture2D(tex_y, textureOut).r; \
yuv.y = texture2D(tex_u, textureOut).r - 0.5; \
yuv.z = texture2D(tex_v, textureOut).r - 0.5; \
rgb = mat3( 1, 1, 1, \
0, -0.39465, 2.03211, \
1.13983, -0.58060, 0) * yuv; \
gl_FragColor = vec4(rgb, 1); \
}";
fShader->compileSourceCode(fragmentSrc);
// 着色器程序
m_shaderProgram = new QOpenGLShaderProgram(this);
// 添加着色器
m_shaderProgram->addShader(vShader);
m_shaderProgram->addShader(fShader);
m_shaderProgram->bindAttributeLocation("vertexIn",VERTEXIN);
m_shaderProgram->bindAttributeLocation("textureIn",TEXTUREIN);
// 链接着色器
m_shaderProgram->link();
m_shaderProgram->bind();
m_shaderProgram->enableAttributeArray(VERTEXIN);
m_shaderProgram->enableAttributeArray(TEXTUREIN);
m_shaderProgram->setAttributeBuffer(VERTEXIN, GL_FLOAT, 0, 2, 2*sizeof(GLfloat));
m_shaderProgram->setAttributeBuffer(TEXTUREIN, GL_FLOAT, 8*sizeof(GLfloat), 2, 2*sizeof(GLfloat));
// 着色器程序中取得yuv纹理位置
m_textureUniformY = m_shaderProgram->uniformLocation("tex_y");
m_textureUniformU = m_shaderProgram->uniformLocation("tex_u");
m_textureUniformV = m_shaderProgram->uniformLocation("tex_v");
m_textureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_textureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_textureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_textureY->create();
m_textureU->create();
m_textureV->create();
m_idY = m_textureY->textureId();
m_idU = m_textureU->textureId();
m_idV = m_textureV->textureId();
glClearColor(0.0,0.0,0.0,0.0);
}
void GLYuvWidget::inittexture()
{
//QMatrix4x4 m;
//m.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f );//透视矩阵随距离的变化,图形跟着变化。屏幕平面中心就是视点(摄像头),需要将图形移向屏幕里面一定距离。
//近裁剪平面是一个矩形,矩形左下角点三维空间坐标是left,bottom,-near,右上角点是right,top,-near所以此处为负表示z轴最大为10
//远裁剪平面也是一个矩形,左下角点空间坐标是left,bottom,-far,右上角点是right,top,-far所以此处为正表示z轴最小为-10
//此时坐标中心还是在屏幕水平面中间,只是前后左右的距离已限制。
//m.ortho(-2,+2,-2,+2,-10,10);
glActiveTexture(GL_TEXTURE0); //激活纹理单元GL_TEXTURE0,系统里面的
glBindTexture(GL_TEXTURE_2D, m_idY); //绑定y分量纹理对象id到激活的纹理单元
//使用内存中的数据创建真正的y分量纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth, m_videoHeight, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr);
//https://blog.csdn.net/xipiaoyouzi/article/details/53584798 纹理参数解析
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glActiveTexture(GL_TEXTURE1); //激活纹理单元GL_TEXTURE1
glBindTexture(GL_TEXTURE1, m_idU);
//使用内存中的数据创建真正的u分量纹理数据
glTexImage2D(GL_TEXTURE_2D,0,GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glActiveTexture(GL_TEXTURE2); //激活纹理单元GL_TEXTURE2
glBindTexture(GL_TEXTURE_2D, m_idV);
//使用内存中的数据创建真正的v分量纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight * 5 / 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
}
void GLYuvWidget::paintGL()
{
inittexture();
//指定y纹理要使用新值
glUniform1i(m_textureUniformY, 0);
//指定u纹理要使用新值
glUniform1i(m_textureUniformU, 1);
//指定v纹理要使用新值
glUniform1i(m_textureUniformV, 2);
//使用顶点数组方式绘制图形
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}