本文使用QT中的QOpenGLFunctions(此类封装了OPenGL的方法,相当于QT版OPenGL)
其次重载 void paintGL(); void initializeGL(); void resizeGL(int width, int height);是基本操作
* 三种GLSL变量说明
* varying 顶点与片元共享
* attribute 顶点使用,由bindAttributeLocation传入
* uniform 程序传入,uniformLocation获取地址
XvideoWidget.h
#pragma once#include <QOpenGLWidget>
#include<QOpenGLFunctions>
#include<QGLShaderProgram>class XvideoWidget : public QOpenGLWidget,protected QOpenGLFunctions
{Q_OBJECTpublic:XvideoWidget(QWidget *parent);~XvideoWidget();protected://重载//刷新显示void paintGL();//初始化GLvoid initializeGL();//窗口尺寸变化void resizeGL(int width, int height);private://shader程序QGLShaderProgram program;//shader中yuv变量地址GLuint unis[3] = { 0 };//openg的 texture地址GLuint texs[3] = { 0 };//材质内存空间unsigned char *datas[3] = { 0 };int width = 352;int height = 288;};
XvideoWidget.cpp
#include "XvideoWidget.h"
#include <QDebug>
#include <QTimer>
//自动加双引号
#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4FILE *fp = NULL;//顶点shader
const char *vString = GET_STR(
attribute vec4 vertexIn; //顶点坐标
attribute vec2 textureIn; //材质坐标
varying vec2 textureOut; //顶点shader片元shader共享
void main(void)
{gl_Position = vertexIn;textureOut = textureIn;
}
);//片元shader
const char *tString = GET_STR(
varying vec2 textureOut;
uniform sampler2D tex_y;
uniform sampler2D tex_u;
uniform sampler2D tex_v;
void main(void)
{vec3 rgb;vec3 yuv;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;//YUV转RGB固定公式,利用矩阵转换rgb = mat3(1.0, 1.0, 1.0,0.0, -0.39465, 2.03211,1.13983, -0.58060, 0.0) * yuv;gl_FragColor = vec4(rgb, 1.0);
});//准备yuv数据
// ffmpeg -i v1080.mp4 -t 10 -s 240x128 -pix_fmt yuv420p out240x128.yuv
XvideoWidget::XvideoWidget(QWidget *parent): QOpenGLWidget(parent)
{
}XvideoWidget::~XvideoWidget()
{
}//初始化opengl
void XvideoWidget::initializeGL()
{qDebug() << "initializeGL";//初始化opengl (QOpenGLFunctions继承)函数 initializeOpenGLFunctions();//program加载shader(顶点和片元)脚本//片元(像素)qDebug() << program.addShaderFromSourceCode(QGLShader::Fragment, tString);//顶点shaderqDebug() << program.addShaderFromSourceCode(QGLShader::Vertex, vString);//设置顶点坐标的变量program.bindAttributeLocation("vertexIn", A_VER);//设置材质坐标program.bindAttributeLocation("textureIn", T_VER);//编译shaderqDebug() << "program.link() = " << program.link();qDebug() << "program.bind() = " << program.bind();//传递顶点和材质坐标//顶点static const GLfloat ver[] = {-1.0f,-1.0f,1.0f,-1.0f,-1.0f, 1.0f,1.0f,1.0f};//材质static const GLfloat tex[] = {0.0f, 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f, 0.0f};//顶点glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);glEnableVertexAttribArray(A_VER);//材质glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);glEnableVertexAttribArray(T_VER);//从shader获取材质unis[0] = program.uniformLocation("tex_y");unis[1] = program.uniformLocation("tex_u");unis[2] = program.uniformLocation("tex_v");//创建材质,创建三个对象glGenTextures(3, texs);//Y 绑定材质glBindTexture(GL_TEXTURE_2D, texs[0]);//放大过滤,线性插值 GL_NEAREST(效率高,但马赛克严重)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);//UglBindTexture(GL_TEXTURE_2D, texs[1]);//放大过滤,线性插值glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);//VglBindTexture(GL_TEXTURE_2D, texs[2]);//放大过滤,线性插值glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);///分配材质内存空间datas[0] = new unsigned char[width*height]; //Ydatas[1] = new unsigned char[width*height / 4]; //Udatas[2] = new unsigned char[width*height / 4]; //Vfp = fopen("VIDEO2.yuv", "rb");if (!fp){qDebug() << "VIDEO2.yuv file open failed!";}//启动定时器QTimer *ti = new QTimer(this);connect(ti, SIGNAL(timeout()), this, SLOT(update()));ti->start(40);
}//刷新显示
void XvideoWidget::paintGL()
{if (feof(fp)){fseek(fp, 0, SEEK_SET);}fread(datas[0], 1, width*height, fp);fread(datas[1], 1, width*height / 4, fp);fread(datas[2], 1, width*height / 4, fp);glActiveTexture(GL_TEXTURE0);//激活第0层glBindTexture(GL_TEXTURE_2D, texs[0]); //0层绑定到Y材质//修改材质内容(复制内存内容)glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, datas[0]);//与shader uni遍历关联glUniform1i(unis[0], 0);//0表示对应0层glActiveTexture(GL_TEXTURE0 + 1);glBindTexture(GL_TEXTURE_2D, texs[1]); //1层绑定到U材质//修改材质内容(复制内存内容)glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);//与shader uni遍历关联glUniform1i(unis[1], 1);glActiveTexture(GL_TEXTURE0 + 2);glBindTexture(GL_TEXTURE_2D, texs[2]); //2层绑定到V材质//修改材质内容(复制内存内容)glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);//与shader uni遍历关联glUniform1i(unis[2], 2);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);qDebug() << "paintGL";
}// 窗口尺寸变化
void XvideoWidget::resizeGL(int width, int height)
{qDebug() << "resizeGL " << width << ":" << height;
}
本文配套开源项目