内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010339039/article/details/88628687
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010339039/article/details/88628687
前一篇我们讨论了如何渲染一个普通图片(rgb)
现在我们来讨论如何渲染一个yuv图片。
什么是yuv我们这里有一个说的不错的文章
我们摄像头采集到的,最后我们用来显示的都是yuv数据。所以我们必须的理解yuv格式,yuv有很多种格式,什么yuv420p,yuv422等。需要学习的就在上面的连接进行学习。
我们先看看下面效果图:
我们直接来看看对应的着色器代码:
顶点着色器:
attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
//这个1.0 - aTexCoord.y 是让yuv图像倒一个方向。
vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
gl_Position = aPosition;
}
aPosition:让顶点坐标传递进来的变量
aTexCoord:让纹理坐标传递进来的变量
vTexCoord:将纹理坐标从顶点着色器中传递到片段着色器中,当然我们看到他使用了1.0 - aTexCoord.y ,是为了将图片倒一个方向
片段着色器:
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);
}
传入三个纹理,分别对应y,u,v然后yuv需要转换成rgb,yuv转rgb就是以上的方式。
对应的公式是:
V
U - 0.58060V
U但是在opengl使用的是线性代数的方式来处理。
好了我们直接看代码部分:
这次我们把顶点坐标和纹理坐标分开声明的
float vertexVertices[] = {
//顶点坐标
1.0f, 1.0f,
-1.0f, 1.0f,
1.0f, -1.0f,
-1.0f, -1.0f,
};
float textureVertices[] = {
//纹理坐标
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
注意:我把文件读取路径写的是sdcard/FFmpeg,以后我的很多操作都是写入的这个地方。
try {
byte[] buffer = new byte[yuvSize];
fis = new FileInputStream("sdcard/FFmpeg/oneframe.yuv");
fis.read(buffer);
byteY = new byte[yLen];
byteU = new byte[yLen / 4];
byteV = new byte[yLen / 4];
System.arraycopy(buffer, 0, byteY, 0, yLen);
System.arraycopy(buffer, yLen, byteU, 0, yLen / 4);
System.arraycopy(buffer, yLen * 5 / 4, byteV, 0, yLen / 4);
bufferY = ByteBuffer.wrap(byteY);
bufferU = ByteBuffer.wrap(byteU);
bufferV = ByteBuffer.wrap(byteV);
} catch (Exception e) {
Log.e("xhc", " message " + e.getMessage());
e.printStackTrace();
}
声明了三个本地缓存
private ByteBuffer bufferY; private ByteBuffer bufferU; private ByteBuffer bufferV;
分别保存的是y,u,v对应的数据
编译,连接,使能的代码部分就不一一拿出来说了,和之前的渲染三角形等一样,直接贴出:
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.yuv_vertex_shader);
String frgShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.yuv_frg_shader);
int vertextShader = ShaderHelper.compileVertextShader(vertexShaderSource);
int fragmentShader = ShaderHelper.compileFragmentShader(frgShaderSource);
program = ShaderHelper.linkProgram(vertextShader, fragmentShader);
ShaderHelper.validatePrograme(program);
glUseProgram(program);
textureYL = glGetUniformLocation(program, "yTexture");
textureUL = glGetUniformLocation(program, "uTexture");
textureVL = glGetUniformLocation(program, "vTexture");
aPositionL = glGetAttribLocation(program, "aPosition");
aTextureCoordinatesL = glGetAttribLocation(program, "aTexCoord");
vertexData.position(0);
int[] textures = TextureHelper.initYuvTexture();
if (textures == null) {
return;
}
textureYid = textures[0];
textureUid = textures[1];
textureVid = textures[2];
glVertexAttribPointer(aPositionL, 2, GL_FLOAT,false , 0, vertexData);
glEnableVertexAttribArray(aPositionL);
glVertexAttribPointer(aTextureCoordinatesL, 2, GL_FLOAT, false, 0, texData);
glEnableVertexAttribArray(aTextureCoordinatesL);
}
我们在这里拿到y,u,v纹理数据,顶点,和纹理坐标的location。稍后再绘制的时候会使用。
我们这里直接绘制纹理:
@Override
public void onDrawFrame(GL10 gl10) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
//激活纹理单元GL_TEXTURE0
glActiveTexture(GL_TEXTURE0);
//绑定对应的纹理对象textureYid
glBindTexture(GL_TEXTURE_2D, textureYid);
//详细看后面
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferY);
//调用glUniformli(textureYL,0)把被选定的纹理单元传递给片段着色器中。
glUniform1i(textureYL, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureUid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferU);
glUniform1i(textureUL, 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, textureVid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferV);
glUniform1i(textureVL, 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
glTexImage2D中对应的参数:
target
指定活动纹理单元的目标纹理。必须是GL_TEXTURE_2D,GL_TEXTURE_CUBE_MAP_POSITIVE_X,GL_TEXTURE_CUBE_MAP_NEGATIVE_X,GL_TEXTURE_CUBE_MAP_POSITIVE_Y,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,GL_TEXTURE_CUBE_MAP_POSITIVE_Z,或GL_TEXTURE_CUBE_MAP_NEGATIVE_Z。
level
指定详细程度编号。级别0是基本图像级别。级别n是第n个缩略图缩小图像。
internalformat
指定纹理的内部格式。必须是下列符号常量之一:GL_ALPHA(按照alpha值存储纹理单元),GL_LUMINANCE(按照亮度值存储纹理单元),GL_LUMINANCE_ALPHA(按照亮度值和alpha值存储纹理单元),GL_RGB(按照r,g,b成分存储纹理单元),GL_RGBA(按照r,g,b,alpha方式存储纹理单元)。
Width:尽量使用2的整数次方,不然会有可能有性能损耗,注意:y纹理的宽度,就是图片的宽度,但是u,v的宽度却除了2,那是因为yuv420p格式的数据是4个y共用一个uv,所以宽高都需要除2
Height:同上
border
指定边框的宽度。必须为0。
format
指定纹理数据的格式。必须匹配internalformat。下面的符号值被接受:GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE,和GL_LUMINANCE_ALPHA。
type
指定纹理数据的数据类型。下面的符号值被接受:GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT_5_6_5,GL_UNSIGNED_SHORT_4_4_4_4,和GL_UNSIGNED_SHORT_5_5_5_1。
data
指定一个指向内存中图像数据的指针。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 音视频之opengl渲染图片
- iOS 图片压缩、滤镜、剪切、渲染等解析
- iOS开发 - 图片的解压缩到渲染过程
- OpenGL ES 入门之旅(15)--分屏滤镜渲染图片
- OpenGL/OpenGL ES入门: 使用OpenGL ES 渲染图片
- Octane渲染入门-渲染设置图文版
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hacking Growth
Sean Ellis、Morgan Brown / Crown Business / 2017-4-25 / USD 29.00
The definitive playbook by the pioneers of Growth Hacking, one of the hottest business methodologies in Silicon Valley and beyond. It seems hard to believe today, but there was a time when Airbnb w......一起来看看 《Hacking Growth》 这本书的介绍吧!