内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 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渲染入门-渲染设置图文版
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Laravel框架关键技术解析
陈昊、陈远征、陶业荣 / 电子工业出版社 / 2016-7 / 79.00元
《Laravel框架关键技术解析》以Laravel 5.1版本为基础,从框架技术角度介绍Laravel构建的原理,从源代码层次介绍Laravel功能的应用。通过本书的学习,读者能够了解Laravel框架实现的方方面面,完成基于该框架的定制化应用程序开发。 《Laravel框架关键技术解析》第1章到第4章主要介绍了与Laravel框架学习相关的基础部分,读者可以深入了解该框架的设计思想,学习环......一起来看看 《Laravel框架关键技术解析》 这本书的介绍吧!