前言 : 上一节使用了创建Glsurfaceview 进行ioengl渲染,这一节 说明使用其他的渲染控件来进行opengl渲染
任务:通过传入surface,使用mediaplayer 把播放的视频流数据进行2d渲染。
1 SurfaceView TextureView GlSurfaceView如何拿到surface?
1 surfaceview:
2 TextureView
3 GlSurfaceView
其实它是继承surfaceview,所以方式一致,但是不同的是它内部自己进行addcallback,所以我们在外面要拿到surface,需要将glsurfaceview 内部的callback先进行注销;
2 创建opengl 环境
由于glsurfaceview 自己会创建环境,其他的场景就需要自己去收到创建opgles 环境。
EGLDisplay --系统显示 ID 或句柄,可以理解为一个前端的显示窗口
EGLConfig --Surface的EGL配置,可以理解为绘制目标framebuffer的配置属性
EGLContext--OpenGL ES 图形上下文,它代表了OpenGL状态机;如果没有它,OpenGL指令就没有执行的环境
创建EglSurface --系统窗口或 frame buffer 句柄 ,可以理解为一个后端的渲染目标窗口。
3 内部创建surface,提供给播放器
通过new SurfaceTexture实例,进行注册监听回调,然后通过SurfaceTexture来创建surface,提供给播放器,播放器用来加载。
为什么要新建一个surface,不是从渲染控件中拿到了surface?
这里的surface是提供给播放器进行显示的?但是我们需要的结果并不是要屏幕去直接渲染播放器的内容,而是去显示处理后的画面。所以给播放器的surface必然不能是渲染控件中的surface.
同时监听提供给播放器的surface的数据变化,有变化的时候需要去触发opengl去画。
4 画的过程
ondraw画的方式跟glsurfaceview.Renderer中onDrawFrame()方法内容几乎一致。
区别点:需要手动调用eglSwapBuffers()
内部的前端缓冲(front-buffer)和后端缓冲(back-surface)。
后端缓冲用于存储渲染结果,前端缓冲则用于底层窗口系统,底层窗口系统将缓冲中的颜色信息显示到设备上。
5 注意的问题
在开发的过程出现了 渲染黑屏,但是全程没有报错。
问题:projectionMatrix 未初始化
Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -1, 1, -1f, 1f);
通过一致变量(uniform修饰的变量)引用将一致变量值传入渲染管线。
location : uniform的位置。
count : 需要加载数据的数组元素的数量或者需要修改的矩阵的数量。
transpose : 指明矩阵是列优先(column major)矩阵(GL_FALSE)还是行优先(row major)矩阵(GL_TRUE)。
value : 指向由count个元素的数组的指针。
6 附上源码
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLExt;
import android.opengl.EGLSurface;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;
import android.view.Surface;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.EGL14;
public class SurfaceRenderer implements Runnable, SurfaceTexture.OnFrameAvailableListener {
protected Surface mSurface;
protected Surface mPlaySurface;
private EGLContext eglContext;
private EGLDisplay eglDisplay;
private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
private EGLSurface eglSurface;
private Context context;
private String TAG = "--SurfaceRenderer--";
public SurfaceRenderer(Context context, Surface surface) {
this.context = context;
this.mSurface = surface;
init();
}
public void setRenderSize(int screenWidth, int screenHeight) {
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -1, 1, -1f, 1f);
}
/**
* 生成的shader程序
*/
private int programId;
private int aPositionLocation;
private int uMatrixLocation;
private int uTextureSamplerLocation;
private int aTextureCoordLocation;
private int uSTMMatrixHandle;
private boolean updateSurface = false;
private SurfaceTexture surfaceTexture;
private GLSurfaceRenderer.OnRendererListener mListener;
private final float[] projectionMatrix = new float[16];
/**
* 纹理坐标
*/
private int textureId;
private float[] mSTMatrix = new float[16];
private boolean mIs3d = true;
private FloatBuffer vertexBuffer;
private FloatBuffer vertexBuffer2;
private FloatBuffer textureVertexBuffer;
private FloatBuffer textureVertexBuffer2;
private int screenWidth, screenHeight;
private Object lock = new Object();
// Core EGL
/**
* 是否需要进行绘制(draw)
*/
private boolean canWhile = true;
/**
* 顶点坐标
*/
private final float[] vertexData = {
1f, -1f, 0f, -1f, -1f, 0f, 1f, 1f, 0f, -1f, 1f, 0f
};
private final float[] vertexData2 = {
0f, -1f, 0f, -1f, -1f, 0f, 0f, 1f, 0f, -1f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, 1f, 1f, 0f, 0f,
-1f, 0f, 1f, -1f, 0f
};
/**
* 纹理坐标
*/
private final float[] textureVertexData = {
1f, 0f, 0f, 0f, 1f, 1f, 0f, 1f
};
private final float[] textureVertexData2 = {
1f, 0f, 0f, 0f, 1f, 1f, 0f, 1f, 0f, 1f, 0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f
};
public void setOnRendererListener(GLSurfaceRenderer.OnRendererListener listener) {
mListener = listener;
if (surfaceTexture != null) {
if (listener == null) {
surfaceTexture.setOnFrameAvailableListener(null);
}
}
}
public void setEnable3DMode(boolean is3d) {
this.mIs3d = is3d;
}
public void init() {
vertexBuffer = ByteBuffer
//4个字节
.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
textureVertexBuffer = ByteBuffer
//4个字节
.allocateDirect(textureVertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureVertexData);
textureVertexBuffer.position(0);
vertexBuffer2 = ByteBuffer
//4个字节
.allocateDirect(vertexData2.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData2);
vertexBuffer2.position(0);
textureVertexBuffer2 = ByteBuffer
//4个字节
.allocateDirect(textureVertexData2.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureVertexData2);
textureVertexBuffer2.position(0);
}
public void start() {
ExecutorServiceUtil.getInstance().execute(this);
}
private void initEGL() {
mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
throw new RuntimeException("Unable to get EGL14 display");
}
//获取显示设备
eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
//version中存放EGL 版本号,int[0]为主版本号,int[1]为子版本号
int[] version = new int[2];
if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
mEGLDisplay = null;
throw new RuntimeException("unable to initialize EGL14");
}
EGLConfig eglConfig = chooseEglConfig();
int[] surfaceAttribs = {
EGL14.EGL_NONE
};
int[] attrib3_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE
};
//创建EGL 的window surface 并且返回它的handles(eslSurface)
eglContext =
EGL14.eglCreateContext(mEGLDisplay, eglConfig, EGL14.EGL_NO_CONTEXT, attrib3_list, 0);
//需要检测Context是否存在
if (eglContext == EGL14.EGL_NO_CONTEXT) {
throw new RuntimeException("Failed to create EGL context");
}
eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, eglConfig, mSurface, surfaceAttribs, 0);
/**绑定context到当前渲染线程并且去绘制(通过opengl去绘制)和读取surface(通过eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示)*/
try {
if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
Log.d(TAG, "NOTE: makeCurrent w/o display");
}
checkDisplayEGLCurrent();
} catch (Exception e) {
e.printStackTrace();
}
}
private void checkDisplayEGLCurrent() {
if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, eglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
}
/***
* 选择一个你所期望的配置.
* @return 一个与你所指定最相近的一个EGL 帧缓存配置.
*/
private EGLConfig chooseEglConfig() {
int[] attribList = {
EGL14.EGL_BUFFER_SIZE, 32, EGL14.EGL_ALPHA_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_RED_SIZE, 8, EGL14.EGL_RENDERABLE_TYPE,
EGL14.EGL_OPENGL_ES2_BIT, EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT, EGL14.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, numConfigs,
0)) {
return null;
}
return configs[0];
}
/**
* 为当前渲染的API创建一个渲染上下文
*
* @return a handle to the context
*/
@Override
public void run() {
initEGL();
initGLComponents();
while (canWhile) {
synchronized (lock) {
onDraw();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
unInitEGL();
}
private void unInitEGL() {
Log.d(TAG, "unInitEGL");
EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
EGL14.EGL_NO_CONTEXT);
EGL14.eglDestroySurface(eglDisplay, eglSurface);
EGL14.eglDestroyContext(eglDisplay, eglContext);
EGL14.eglTerminate(eglDisplay);
}
public void initGLComponents() {
String vertexShader = ShaderUtil.readRawTextFile(context, R.raw.vetext_sharder);
String fragmentShader = ShaderUtil.readRawTextFile(context, R.raw.fragment_sharder);
programId = ShaderUtil.createProgram(vertexShader, fragmentShader);
aPositionLocation = GLES20.glGetAttribLocation(programId, "aPosition");
uMatrixLocation = GLES20.glGetUniformLocation(programId, "uMatrix");
uSTMMatrixHandle = GLES20.glGetUniformLocation(programId, "uSTMatrix");
uTextureSamplerLocation = GLES20.glGetUniformLocation(programId, "sTexture");
aTextureCoordLocation = GLES20.glGetAttribLocation(programId, "aTexCoord");
//生成纹理
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
textureId = textures[0];
//绑定
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
ShaderUtil.checkGlError("glBindTexture mTextureID");
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
surfaceTexture = new SurfaceTexture(textureId);
//监听是否有新的一帧数据到来
surfaceTexture.setOnFrameAvailableListener(this);
mPlaySurface = new Surface(surfaceTexture);
if (mListener != null) {
mListener.onRendererSurfaceCreated(mPlaySurface);
}
}
private void onDraw() {
int len = 0;
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
synchronized (this) {
if (updateSurface) {
//获取新数据
surfaceTexture.updateTexImage();
//让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和projectionMatrix完全一样的。
surfaceTexture.getTransformMatrix(mSTMatrix);
updateSurface = false;
}
}
//使用对应的program
ShaderUtil.checkGlError("draw start");
GLES20.glUseProgram(programId);
ShaderUtil.checkGlError("glUseProgram");
vertexBuffer2.position(0);
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
GLES20.glUniformMatrix4fv(uSTMMatrixHandle, 1, false, mSTMatrix, 0);
if (mIs3d) {
//设置顶点坐标系
vertexBuffer2.position(0);
GLES20.glEnableVertexAttribArray(aPositionLocation);
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer2);
//设置纹理坐标系
textureVertexBuffer2.position(0);
GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
GLES20.glVertexAttribPointer(aTextureCoordLocation, 2, GLES20.GL_FLOAT, false, 8,
textureVertexBuffer2);
len = vertexData2.length / 3;
} else {
//设置顶点坐标系
vertexBuffer.position(0);
GLES20.glEnableVertexAttribArray(aPositionLocation);
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer);
//设置纹理坐标系
textureVertexBuffer.position(0);
GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
GLES20.glVertexAttribPointer(aTextureCoordLocation, 2, GLES20.GL_FLOAT, false, 8,
textureVertexBuffer);
len = vertexData.length / 3;
}
//激活纹理单元,默认第0个纹理单元
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//将纹理对象ID绑定到当前活动的纹理单元0上的GL_TEXTURE_2D目标
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
GLES20.glUniform1i(uTextureSamplerLocation, 0);
GLES20.glViewport(0, 0, screenWidth, screenHeight);
//绘制4个点
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, len);
ShaderUtil.checkGlError("glDrawArrays");
EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);
if (mListener != null) {
mListener.onRendererDrawFrame();
}
}
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
Log.d(TAG, "onFrameAvailable --");
updateSurface = true;
synchronized (lock) {
lock.notify();
}
if (mListener != null) {
mListener.onRendererFrameAvailable();
}
}
public void release() {
Log.d(TAG, "release");
canWhile = false;
updateSurface = false;
synchronized (lock) {
lock.notify();
}
}
}