前言 : 上一节使用了创建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();
- }
- }
- }
-