在项目raw下创建 fragment_mediacodec.glsl 用来渲染视频
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 v_texPosition;
uniform samplerExternalOES sTexture;
void main() {
gl_FragColor=texture2D(sTexture, v_texPosition);
}
WlRender中的代码
package com.ywl5320.myplayer.opengl;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.view.Surface;
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;
public class WlRender implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
public static final int RENDER_YUV = 1;
public static final int RENDER_MEDIACODEC = 2;
private Context mContext;
private int renderType = RENDER_YUV;
public void setRenderType(int renderType) {
this.renderType = renderType;
}
/*********************************** yuv ***********************************************/
//yuv
private int program_yuv;
private int avPosition_yuv;
private int afPosition_yuv;
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;
/*********************************** mediacodec-start ***********************************************/
//创建program
private int program_mediacodec;
private int avPosition_mediacodec;
private int afPosition_mediacodec;
//纹理id
private int samplerOES_mediacodec;
private int textureId_mediacodec;
private SurfaceTexture surfaceTexture;
private Surface surface;
private OnSurfaceCreateListener onSurfaceCreateListener;
private OnRenderListner onRenderListner;
public void setOnSurfaceCreateListener(OnSurfaceCreateListener onSurfaceCreateListener) {
this.onSurfaceCreateListener = onSurfaceCreateListener;
}
public void setOnRenderListner(OnRenderListner onRenderListner) {
this.onRenderListner = onRenderListner;
}
/*********************************** mediacodec-end ***********************************************/
//声明顶点坐标数组 绘制坐标范围
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) {
initRanderYUV();
initRanderMediaCodec();
}
@Override
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
//设置长宽高
GLES20.glViewport(0, 0, i, i1);
}
@Override
public void onDrawFrame(GL10 gl10) {
//清屏
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//使用颜色清屏
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
if (renderType == RENDER_YUV) {
renderYUV();
} else if (renderType == RENDER_MEDIACODEC) {
renderMediacodec();
}
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_yuv);
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) {
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() {
if (width_yuv > 0 && height_yuv > 0 && y != null && u != null && v != null) {
//使用program
GLES20.glUseProgram(program_yuv);
//使用顶点坐标
GLES20.glEnableVertexAttribArray(avPosition_yuv);
GLES20.glVertexAttribPointer(avPosition_yuv, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
//绘制
//参数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,
GLES20.GL_LUMINANCE,
width_yuv, height_yuv,
0,
GLES20.GL_LUMINANCE,
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,
GLES20.GL_LUMINANCE,
width_yuv / 2, height_yuv / 2,
0,
GLES20.GL_LUMINANCE,
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;
}
}
private void initRanderMediaCodec() {
//获取着色器语言 program
String vertexSource = WlShaderUtil.readRawTxt(mContext, R.raw.vertex_shader);
String fragmentSource = WlShaderUtil.readRawTxt(mContext, R.raw.fragment_mediacodec);
program_mediacodec = WlShaderUtil.createProgram(vertexSource, fragmentSource);
//顶点坐标
avPosition_mediacodec = GLES20.glGetAttribLocation(program_mediacodec, "av_Position");
//纹理坐标
afPosition_mediacodec = GLES20.glGetAttribLocation(program_mediacodec, "af_Position");
//纹理id
samplerOES_mediacodec = GLES20.glGetUniformLocation(program_mediacodec, "sTexture");
//创建纹理
int[] textureids = new int[1];
//创建和绑定纹理
GLES20.glGenTextures(1, textureids, 0);
textureId_mediacodec = textureids[0];
//设置环绕
//GLES11Ext.GL_TEXTURE_EXTERNAL_OES 绘制视频 必须用这个
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
//过滤方法
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//构造器值为纹理
surfaceTexture = new SurfaceTexture(textureId_mediacodec);
surface = new Surface(surfaceTexture);
surfaceTexture.setOnFrameAvailableListener(this);
//回调
if (onSurfaceCreateListener != null) {
onSurfaceCreateListener.onSurfaceCreate(surface);
}
}
//当mediacodec向surface发送数据时的回调
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
//刷新
if (onRenderListner != null) {
onRenderListner.onRender();
}
}
private void renderMediacodec() {
//更新 surfaceTexture
surfaceTexture.updateTexImage();
GLES20.glUseProgram(program_mediacodec);
//使用顶点坐标
GLES20.glEnableVertexAttribArray(avPosition_mediacodec);
GLES20.glVertexAttribPointer(avPosition_mediacodec, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
//绘制
//参数2从哪个顶点绘制
//参数3 绘制顶点个数
GLES20.glEnableVertexAttribArray(afPosition_mediacodec);
GLES20.glVertexAttribPointer(afPosition_mediacodec, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);
//激活纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//绑定
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId_mediacodec);
//使用
GLES20.glUniform1i(samplerOES_mediacodec, 0);
}
public interface OnSurfaceCreateListener {
void onSurfaceCreate(Surface surface);
}
public interface OnRenderListner {
void onRender();
}
}
WlGLSurfaceView
package com.ywl5320.myplayer.opengl;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.Surface;
import com.ywl5320.myplayer.log.MyLog;
public class WlGLSurfaceView extends GLSurfaceView {
private WlRender wlRender;
public WlGLSurfaceView(Context context) {
this(context, null);
}
public WlGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
MyLog.d("WlGLSurfaceView");
//初始化
//设置OpenGL版本
setEGLContextClientVersion(2);
wlRender = new WlRender(context);
//设置Renderer
setRenderer(wlRender);
//渲染模式
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
wlRender.setOnRenderListner(new WlRender.OnRenderListner() {
@Override
public void onRender() {
requestRender();
}
});
}
public void setYUVData(int width, int height, byte[] y, byte[] u, byte[] v) {
if (wlRender != null) {
wlRender.setYUVRenderData(width, height, y, u, v);
MyLog.d("手动渲染");
//手动渲染
requestRender();
}
}
public WlRender getWlRender() {
return wlRender;
}
}
WlPlayer
public void setWlGLSurfaceView(WlGLSurfaceView wlGLSurfaceView) {
this.wlGLSurfaceView = wlGLSurfaceView;
wlGLSurfaceView.getWlRender().setOnSurfaceCreateListener(new WlRender.OnSurfaceCreateListener() {
@Override
public void onSurfaceCreate(Surface s) {
if (surface == null) {
surface = s;
MyLog.d("onSurfaceCreate");
}
}
});
}
//回收Mediacodec
private void releaseMediacodec() {
if (mediaCodec != null) {
mediaCodec.flush();
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
mediaFormat = null;
info = null;
}
}