本文共 7729 字,大约阅读时间需要 25 分钟。
OpenGL中是不能直接渲染YUV数据的,可以用3个纹理来分别获取Y、U和V的值,然后根据公式:
r = y + 1.403 * v;
g = y - 0.344 * u - 0.714 * v; b = y + 1.770 * u;转为rgb颜色格式显示出来。这个转换过程是在GPU中完成的,计算效率比在CPU中计算高很多倍
在工程目录res目录下新建 raw文件夹 新建 顶点着色器/片元着色器
vertex_shader.glsl
aattribute vec4 av_Position;attribute vec2 af_Position;varying vec2 v_texPosition;void main() { v_texPosition = af_Position; gl_Position = av_Position;}
fragment_shader.glsl
precision mediump float;varying vec2 v_texPosition;uniform sampler2D sampler_y;uniform sampler2D sampler_u;uniform sampler2D sampler_v;void main() { float y,u,v; y = texture2D(sampler_y,v_texPosition).r; u = texture2D(sampler_u,v_texPosition).r- 0.5; v = texture2D(sampler_v,v_texPosition).r- 0.5; vec3 rgb; rgb.r = y + 1.403 * v; rgb.g = y - 0.344 * u - 0.714 * v; rgb.b = y + 1.770 * u; gl_FragColor = vec4(rgb,1);}
在java工程目录下新建opengl包
将 WlGLSurfaceView WlRender WlShaderUtil 粘贴过来
修改 WlRender 类
package com.ywl5320.myplayer.opengl;import android.content.Context;import android.opengl.GLES20;import android.opengl.GLSurfaceView;import com.ywl5320.myplayer.R;import com.ywl5320.myplayer.log.MyLog;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import static android.opengl.GLES30.GL_RGB32F;import static android.opengl.GLES30.GL_RGBA32F;public class WlRender implements GLSurfaceView.Renderer { private Context mContext; private int program_yuv; private int avPosition_yuv; private int afPosition_yuv; private int textureid; private int sampler_y; private int sampler_u; private int sampler_v; private int[] textureId_yuv; private int width_yuv; private int height_yuv; private ByteBuffer y; private ByteBuffer u; private ByteBuffer v; //声明顶点坐标数组 绘制坐标范围 private final float[] vertexData = { -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f }; //纹理坐标 private final float[] textureData = { 0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f }; private FloatBuffer vertexBuffer; private FloatBuffer textureBuffer; public WlRender(Context context) { MyLog.d("WlRender"); this.mContext = context; //为坐标分配本地内存地址 //.order排序 //.asFloatBuffer()类型 //.put(vertexData);放置 vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(vertexData); //移动指针到0 vertexBuffer.position(0); //纹理坐标 textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(textureData); textureBuffer.position(0); } //加载 @Override public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) { MyLog.d("onSurfaceCreated"); initRanderYUV(); } @Override public void onSurfaceChanged(GL10 gl10, int i, int i1) { MyLog.d("onSurfaceChanged"); //设置长宽高 GLES20.glViewport(0, 0, i, i1); } @Override public void onDrawFrame(GL10 gl10) { MyLog.d("onDrawFrame"); //清屏 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); //使用颜色清屏 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); renderYUV(); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } private void initRanderYUV() { //获取着色器语言 program String vertexSource = WlShaderUtil.readRawTxt(mContext, R.raw.vertex_shader); String fragmentSource = WlShaderUtil.readRawTxt(mContext, R.raw.fragment_shader); program_yuv = WlShaderUtil.createProgram(vertexSource, fragmentSource); //顶点坐标 avPosition_yuv = GLES20.glGetAttribLocation(program_yuv, "av_Position"); //纹理坐标 afPosition_yuv = GLES20.glGetAttribLocation(program_yuv, "af_Position"); sampler_y = GLES20.glGetUniformLocation(program_yuv, "sampler_y"); sampler_u = GLES20.glGetUniformLocation(program_yuv, "sampler_u"); sampler_v = GLES20.glGetUniformLocation(program_yuv, "sampler_v"); //创建纹理 textureId_yuv = new int[3]; //创建和绑定纹理 GLES20.glGenTextures(3, textureId_yuv, 0); for (int i = 0; i < 3; i++) { //绑定纹理 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[i]); //设置环绕过滤方法 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); } } public void setYUVRenderData(int width, int height, byte[] y, byte[] u, byte[] v) { MyLog.d("setYUVRenderData"); this.width_yuv = width; this.height_yuv = height; this.y = ByteBuffer.wrap(y); this.u = ByteBuffer.wrap(u); this.v = ByteBuffer.wrap(v); } private void renderYUV() { MyLog.d("width_yuv " + width_yuv + "height_yuv " + height_yuv + "y " + y + "u " + u + "v " + v); if (width_yuv > 0 && height_yuv > 0 && y != null && u != null && v != null) { MyLog.d("renderYUV"); //使用program GLES20.glUseProgram(program_yuv); MyLog.d("glUseProgram"); //使用顶点坐标 GLES20.glEnableVertexAttribArray(avPosition_yuv); GLES20.glVertexAttribPointer(avPosition_yuv, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer); MyLog.d("glVertexAttribPointer"); //绘制 //参数2从哪个顶点绘制 //参数3 绘制顶点个数 GLES20.glEnableVertexAttribArray(afPosition_yuv); GLES20.glVertexAttribPointer(afPosition_yuv, 2, GLES20.GL_FLOAT, false, 8, textureBuffer); //纹理赋值 //激活纹理 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); //绑定 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[0]); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GL_RGBA32F, width_yuv, height_yuv, 0, GL_RGBA32F, GLES20.GL_UNSIGNED_BYTE, y); GLES20.glActiveTexture(GLES20.GL_TEXTURE1); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[1]); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GL_RGBA32F, width_yuv / 2, height_yuv / 2, 0, GL_RGBA32F, GLES20.GL_UNSIGNED_BYTE, u); GLES20.glActiveTexture(GLES20.GL_TEXTURE2); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[2]); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width_yuv / 2, height_yuv / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, v); GLES20.glUniform1i(sampler_y, 0); GLES20.glUniform1i(sampler_u, 1); GLES20.glUniform1i(sampler_v, 2); y.clear(); u.clear(); v.clear(); y = null; u = null; v = null; MyLog.d("END"); } }}
* 注意这个类目前绘制有问题但是能保证程序运行 后面明白了怎么做就改掉
转载地址:http://udzo.baihongyu.com/