Shader
生成测试yuv数据和pcm数据命令:
ffmpeg -i test.mp4 -f si6le test.pcm
ffmpeg -i 720.mp4 -pix_fmt yuv20p -s 424x240 out.yuv
具体显示yuv数据 --- 着色器语言 GLSL (运行在显卡上,不消耗cpu)
-GLSL的基本语法与C语言基本相同
-它完美支持向量和矩阵操作
-GLSL提供了大量的内置函数来提供丰富的扩展功能
-它是通过限定符操作来管理输入输出类型的
①顶点着色器:顶点着色器被使用在传统的基于顶点的操作,例如位移矩阵、计算光照方程、产生贴图坐标。顶点着色器被应用指定,应用于客户的顶点转化是针对每个顶点执行一次,用于确定顶点位置
作用:顶点坐标输出成材质坐标
②片元着色器:在片元着色器阶段只有唯一的varying 输出变量-即内建变量:gl_FragColo
是针对每个片元(可以理解为每个像素)执行一次,用于确定每个片元(像素)的颜色
作用:输出像素格式
- 顶点信息
float *vertexData = new float[12]{
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f};
// 顶点着色器 glsl代码
static const char *vertexShader = GET_STR(
attribute
vec4 aPosition; //顶点坐标
attribute
vec2 aTexCoord; //材质顶点坐标
varying
vec2 vTexCoord; //输出的材质坐标
void main() {
vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
gl_Position = aPosition;
}
);
- 材质坐标
float *textureVertexData = new float[8]{
1.0f, 0.0f,//右下
0.0f, 0.0f,//左下
1.0f, 1.0f,//右上
0.0f, 1.0f//左上
};
//yuv420p 片元着色器,软解码和部分x86硬解码
static const char *fragYUV_420P= GET_STR(
precision
mediump float; //精度
varying
vec2 vTexCoord; //顶点着色器传递的坐标
uniform
sampler2D yTexture; //输入的材质(不透明灰度,单像素)
uniform
sampler2D uTexture;
uniform
sampler2D vTexture;
void main() {
vec3 yuv;
vec3 rgb;
yuv.r = texture2D(yTexture, vTexCoord).r;
yuv.g = texture2D(uTexture, vTexCoord).r - 0.5;
yuv.b = texture2D(vTexture, vTexCoord).r - 0.5;
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);
}
);
//NV12 片元着色器 glsl代码
static const char *fragNV12 = GET_STR(
precision
mediump float; //精度
varying
vec2 vTexCoord; //顶点着色器传递的坐标
uniform
sampler2D yTexture; //输入的材质(不透明灰度,单像素)
uniform
sampler2D uvTexture;
void main() {
vec3 yuv;
vec3 rgb;
yuv.r = texture2D(yTexture, vTexCoord).r;
yuv.g = texture2D(uvTexture, vTexCoord).r - 0.5;
yuv.b = texture2D(uvTexture, vTexCoord).a - 0.5;
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转rgb
// 方法一:使用转换公式
R = Y + 1.402 (Cr-128)
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
B = Y + 1.772 (Cb-128)
// 方法二: 使用转换矩阵
(1.0, 1.0, 1.0,
0.0, -0.39465, 2.03211,
1.13983, -0.58060, 0.0)
- shader初始化代码演示
bool XShader::Init(XShaderType type) {
XLOGE("Enter XShader::Init()!");
Close();
//shader 初始化
//顶点坐标初始化
vsh = InitShader(vertexShader, GL_VERTEX_SHADER);
if (vsh == 0) {
mux.unlock();
XLOGE("InitShader GL_VERTEX_SHADER failed!");
return false;
}
XLOGE("@@@@@@@@@@@@@@@@ type: %d", type);
//片元初始化
switch (type) {
case XSHADER_yuv420P: //片元yuv420 shader初始化
fsh = InitShader(fragYUV_420P, GL_FRAGMENT_SHADER);
break;
case XSHADER_NV12: // NV12
fsh = InitShader(fragNV12, GL_FRAGMENT_SHADER);
break;
case XSHADER_NV21:
fsh = InitShader(fragNV21, GL_FRAGMENT_SHADER);
break;
default:
mux.unlock();
XLOGE("XShaderType format is error!");
break;
}
if (fsh == 0) {
mux.unlock();
XLOGE("InitShader GL_FRAGMENT_SHADER failed!");
return false;
}
//创建渲染程序
program = glCreateProgram();
if (program == 0) {
mux.unlock();
XLOGE("===========>>glCreateProgram failed! ");
return false;
}
//渲染程序中加入着色器代码
glAttachShader(program, vsh);
glAttachShader(program, fsh);
//连接程序
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
mux.unlock();
XLOGE("=========>> glLinkProgram failed!");
return false;
}
//激活渲染程序
glUseProgram(program);
/////////////////////////////////////////////////////
//加入三维顶点数据 两个三角形组成正方形
static float ver[] = {
1.0f, -1.f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f
};
GLuint apos = glGetAttribLocation(program, "aPosition");
glEnableVertexAttribArray(apos);
//传递值
glVertexAttribPointer(apos, 3, GL_FLOAT, GL_FALSE, 12, ver);
//加入材质坐标
static float txts[] = {
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLuint atex = glGetAttribLocation(program, "aTexCoord");
glEnableVertexAttribArray(atex);
glVertexAttribPointer(atex, 2, GL_FLOAT, GL_FALSE, 8, txts);
//材质纹理初始化
//设置纹理层
glUniform1i(glGetUniformLocation(program, "yTexture"), 0); //纹理层第一层
switch (type) {
case XSHADER_yuv420P:
glUniform1i(glGetUniformLocation(program, "uTexture"), 1); //纹理层第二层
glUniform1i(glGetUniformLocation(program, "vTexture"), 2); //纹理层第三层
break;
case XSHADER_NV12:
case XSHADER_NV21:
glUniform1i(glGetUniformLocation(program, "uvTexture"), 1); //纹理层第二层
break;
}
mux.unlock();
XLOGE("InitShader success!");
return true;
}
//shader 初始化
static GLuint InitShader(const char *code, GLint type) {
GLuint sh = glCreateShader(type);
if (sh == 0) {
XLOGE("====>> InitShader failed! %d", type);
return 0;
}
//加载shader
glShaderSource(sh,
1, //shader 数量
&code,//shader代码
//代码长度
0);
//编译shader
glCompileShader(sh);
//获取编译情况
GLint status;
glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
if (status == 0) {
XLOGE("glGetShaderiv failed!");
return 0;
}
XLOGE("glGetShaderiv succee!");
return sh;
}
- 开始绘制 代码演示
virtual void Draw(unsigned char *data[], int width, int height) {
// XLOGE("XTexture Draw!");
// XLOGE("width %d height %d", width, height);
mux.lock();
shader.GetTexture(0, width, height, data[0]); //y
if (XSHADER_yuv420P == textureType) {
shader.GetTexture(1, width / 2, height / 2, data[1]); //u
shader.GetTexture(2, width / 2, height / 2, data[2]); //v
} else {
shader.GetTexture(1, width / 2, height / 2, data[1], true); //uv
}
shader.Draw();
if (xegl) {
xegl->Draw();
}
mux.unlock();
}
void XShader::GetTexture(unsigned int index, int width, int height, unsigned char *buf, bool isa) {
// XLOGE("XShader width %d height %d", width, height);
//默认灰度图GL_LUMINANCE,透明通道GL_LUMINANCE_ALPHA
unsigned int format = isa ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
mux.lock();
if (texts[index] == 0) {
glGenTextures(1, &texts[index]);//创建纹理
//设置纹理属性
glBindTexture(GL_TEXTURE_2D, texts[index]);
//缩小过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//放大过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理格式和大小
glTexImage2D(GL_TEXTURE_2D,
0,//细节基本 0默认
format,//gpu内部格式,灰度图
width, height,//尺寸是2的次方
0,//边框
format,//数据的像素格式 亮度,灰度图 要与上面一致
GL_UNSIGNED_BYTE,//像素的数据类型
NULL//纹理的数据
);
}
glActiveTexture(GL_TEXTURE0 + index);//激活第index层纹理
glBindTexture(GL_TEXTURE_2D, texts[index]);//绑定到创建的opengl纹理
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE,
buf);//替换纹理内容
mux.unlock();
}
void XShader::Draw() {
// XLOGE("XShader Draw!");dra
mux.lock();
if (program == 0) {
mux.unlock();
XLOGE("Program is NUll when call Draw of Xshader!");
return;
}
//三维绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
mux.unlock();
}