音视频专题--opengl (3)

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


 

 

 
 


                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值