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");
}
}
}
* 注意这个类目前绘制有问题但是能保证程序运行 后面明白了怎么做就改掉