• 音视频专题--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  附上源码

    1. import android.content.Context;
    2. import android.graphics.SurfaceTexture;
    3. import android.opengl.EGLConfig;
    4. import android.opengl.EGLContext;
    5. import android.opengl.EGLDisplay;
    6. import android.opengl.EGLExt;
    7. import android.opengl.EGLSurface;
    8. import android.opengl.GLES11Ext;
    9. import android.opengl.GLES20;
    10. import android.opengl.Matrix;
    11. import android.util.Log;
    12. import android.view.Surface;
    13. import java.nio.ByteBuffer;
    14. import java.nio.ByteOrder;
    15. import java.nio.FloatBuffer;
    16. import android.opengl.EGL14;
    17. public class SurfaceRenderer implements Runnable, SurfaceTexture.OnFrameAvailableListener {
    18. protected Surface mSurface;
    19. protected Surface mPlaySurface;
    20. private EGLContext eglContext;
    21. private EGLDisplay eglDisplay;
    22. private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
    23. private EGLSurface eglSurface;
    24. private Context context;
    25. private String TAG = "--SurfaceRenderer--";
    26. public SurfaceRenderer(Context context, Surface surface) {
    27. this.context = context;
    28. this.mSurface = surface;
    29. init();
    30. }
    31. public void setRenderSize(int screenWidth, int screenHeight) {
    32. this.screenWidth = screenWidth;
    33. this.screenHeight = screenHeight;
    34. Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -1, 1, -1f, 1f);
    35. }
    36. /**
    37. * 生成的shader程序
    38. */
    39. private int programId;
    40. private int aPositionLocation;
    41. private int uMatrixLocation;
    42. private int uTextureSamplerLocation;
    43. private int aTextureCoordLocation;
    44. private int uSTMMatrixHandle;
    45. private boolean updateSurface = false;
    46. private SurfaceTexture surfaceTexture;
    47. private GLSurfaceRenderer.OnRendererListener mListener;
    48. private final float[] projectionMatrix = new float[16];
    49. /**
    50. * 纹理坐标
    51. */
    52. private int textureId;
    53. private float[] mSTMatrix = new float[16];
    54. private boolean mIs3d = true;
    55. private FloatBuffer vertexBuffer;
    56. private FloatBuffer vertexBuffer2;
    57. private FloatBuffer textureVertexBuffer;
    58. private FloatBuffer textureVertexBuffer2;
    59. private int screenWidth, screenHeight;
    60. private Object lock = new Object();
    61. // Core EGL
    62. /**
    63. * 是否需要进行绘制(draw)
    64. */
    65. private boolean canWhile = true;
    66. /**
    67. * 顶点坐标
    68. */
    69. private final float[] vertexData = {
    70. 1f, -1f, 0f, -1f, -1f, 0f, 1f, 1f, 0f, -1f, 1f, 0f
    71. };
    72. private final float[] vertexData2 = {
    73. 0f, -1f, 0f, -1f, -1f, 0f, 0f, 1f, 0f, -1f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, 1f, 1f, 0f, 0f,
    74. -1f, 0f, 1f, -1f, 0f
    75. };
    76. /**
    77. * 纹理坐标
    78. */
    79. private final float[] textureVertexData = {
    80. 1f, 0f, 0f, 0f, 1f, 1f, 0f, 1f
    81. };
    82. private final float[] textureVertexData2 = {
    83. 1f, 0f, 0f, 0f, 1f, 1f, 0f, 1f, 0f, 1f, 0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f
    84. };
    85. public void setOnRendererListener(GLSurfaceRenderer.OnRendererListener listener) {
    86. mListener = listener;
    87. if (surfaceTexture != null) {
    88. if (listener == null) {
    89. surfaceTexture.setOnFrameAvailableListener(null);
    90. }
    91. }
    92. }
    93. public void setEnable3DMode(boolean is3d) {
    94. this.mIs3d = is3d;
    95. }
    96. public void init() {
    97. vertexBuffer = ByteBuffer
    98. //4个字节
    99. .allocateDirect(vertexData.length * 4)
    100. .order(ByteOrder.nativeOrder())
    101. .asFloatBuffer()
    102. .put(vertexData);
    103. vertexBuffer.position(0);
    104. textureVertexBuffer = ByteBuffer
    105. //4个字节
    106. .allocateDirect(textureVertexData.length * 4)
    107. .order(ByteOrder.nativeOrder())
    108. .asFloatBuffer()
    109. .put(textureVertexData);
    110. textureVertexBuffer.position(0);
    111. vertexBuffer2 = ByteBuffer
    112. //4个字节
    113. .allocateDirect(vertexData2.length * 4)
    114. .order(ByteOrder.nativeOrder())
    115. .asFloatBuffer()
    116. .put(vertexData2);
    117. vertexBuffer2.position(0);
    118. textureVertexBuffer2 = ByteBuffer
    119. //4个字节
    120. .allocateDirect(textureVertexData2.length * 4)
    121. .order(ByteOrder.nativeOrder())
    122. .asFloatBuffer()
    123. .put(textureVertexData2);
    124. textureVertexBuffer2.position(0);
    125. }
    126. public void start() {
    127. ExecutorServiceUtil.getInstance().execute(this);
    128. }
    129. private void initEGL() {
    130. mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    131. if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
    132. throw new RuntimeException("Unable to get EGL14 display");
    133. }
    134. //获取显示设备
    135. eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    136. //version中存放EGL 版本号,int[0]为主版本号,int[1]为子版本号
    137. int[] version = new int[2];
    138. if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
    139. mEGLDisplay = null;
    140. throw new RuntimeException("unable to initialize EGL14");
    141. }
    142. EGLConfig eglConfig = chooseEglConfig();
    143. int[] surfaceAttribs = {
    144. EGL14.EGL_NONE
    145. };
    146. int[] attrib3_list = {
    147. EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE
    148. };
    149. //创建EGL 的window surface 并且返回它的handles(eslSurface)
    150. eglContext =
    151. EGL14.eglCreateContext(mEGLDisplay, eglConfig, EGL14.EGL_NO_CONTEXT, attrib3_list, 0);
    152. //需要检测Context是否存在
    153. if (eglContext == EGL14.EGL_NO_CONTEXT) {
    154. throw new RuntimeException("Failed to create EGL context");
    155. }
    156. eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, eglConfig, mSurface, surfaceAttribs, 0);
    157. /**绑定context到当前渲染线程并且去绘制(通过opengl去绘制)和读取surface(通过eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示)*/
    158. try {
    159. if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
    160. Log.d(TAG, "NOTE: makeCurrent w/o display");
    161. }
    162. checkDisplayEGLCurrent();
    163. } catch (Exception e) {
    164. e.printStackTrace();
    165. }
    166. }
    167. private void checkDisplayEGLCurrent() {
    168. if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, eglContext)) {
    169. throw new RuntimeException("eglMakeCurrent failed");
    170. }
    171. }
    172. /***
    173. * 选择一个你所期望的配置.
    174. * @return 一个与你所指定最相近的一个EGL 帧缓存配置.
    175. */
    176. private EGLConfig chooseEglConfig() {
    177. int[] attribList = {
    178. EGL14.EGL_BUFFER_SIZE, 32, EGL14.EGL_ALPHA_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8,
    179. EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_RED_SIZE, 8, EGL14.EGL_RENDERABLE_TYPE,
    180. EGL14.EGL_OPENGL_ES2_BIT, EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT, EGL14.EGL_NONE
    181. };
    182. EGLConfig[] configs = new EGLConfig[1];
    183. int[] numConfigs = new int[1];
    184. if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, numConfigs,
    185. 0)) {
    186. return null;
    187. }
    188. return configs[0];
    189. }
    190. /**
    191. * 为当前渲染的API创建一个渲染上下文
    192. *
    193. * @return a handle to the context
    194. */
    195. @Override
    196. public void run() {
    197. initEGL();
    198. initGLComponents();
    199. while (canWhile) {
    200. synchronized (lock) {
    201. onDraw();
    202. try {
    203. lock.wait();
    204. } catch (InterruptedException e) {
    205. e.printStackTrace();
    206. }
    207. }
    208. }
    209. unInitEGL();
    210. }
    211. private void unInitEGL() {
    212. Log.d(TAG, "unInitEGL");
    213. EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
    214. EGL14.EGL_NO_CONTEXT);
    215. EGL14.eglDestroySurface(eglDisplay, eglSurface);
    216. EGL14.eglDestroyContext(eglDisplay, eglContext);
    217. EGL14.eglTerminate(eglDisplay);
    218. }
    219. public void initGLComponents() {
    220. String vertexShader = ShaderUtil.readRawTextFile(context, R.raw.vetext_sharder);
    221. String fragmentShader = ShaderUtil.readRawTextFile(context, R.raw.fragment_sharder);
    222. programId = ShaderUtil.createProgram(vertexShader, fragmentShader);
    223. aPositionLocation = GLES20.glGetAttribLocation(programId, "aPosition");
    224. uMatrixLocation = GLES20.glGetUniformLocation(programId, "uMatrix");
    225. uSTMMatrixHandle = GLES20.glGetUniformLocation(programId, "uSTMatrix");
    226. uTextureSamplerLocation = GLES20.glGetUniformLocation(programId, "sTexture");
    227. aTextureCoordLocation = GLES20.glGetAttribLocation(programId, "aTexCoord");
    228. //生成纹理
    229. int[] textures = new int[1];
    230. GLES20.glGenTextures(1, textures, 0);
    231. textureId = textures[0];
    232. //绑定
    233. GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
    234. ShaderUtil.checkGlError("glBindTexture mTextureID");
    235. GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
    236. GLES20.GL_NEAREST);
    237. GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
    238. GLES20.GL_LINEAR);
    239. surfaceTexture = new SurfaceTexture(textureId);
    240. //监听是否有新的一帧数据到来
    241. surfaceTexture.setOnFrameAvailableListener(this);
    242. mPlaySurface = new Surface(surfaceTexture);
    243. if (mListener != null) {
    244. mListener.onRendererSurfaceCreated(mPlaySurface);
    245. }
    246. }
    247. private void onDraw() {
    248. int len = 0;
    249. GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
    250. GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    251. synchronized (this) {
    252. if (updateSurface) {
    253. //获取新数据
    254. surfaceTexture.updateTexImage();
    255. //让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和projectionMatrix完全一样的。
    256. surfaceTexture.getTransformMatrix(mSTMatrix);
    257. updateSurface = false;
    258. }
    259. }
    260. //使用对应的program
    261. ShaderUtil.checkGlError("draw start");
    262. GLES20.glUseProgram(programId);
    263. ShaderUtil.checkGlError("glUseProgram");
    264. vertexBuffer2.position(0);
    265. GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
    266. GLES20.glUniformMatrix4fv(uSTMMatrixHandle, 1, false, mSTMatrix, 0);
    267. if (mIs3d) {
    268. //设置顶点坐标系
    269. vertexBuffer2.position(0);
    270. GLES20.glEnableVertexAttribArray(aPositionLocation);
    271. GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer2);
    272. //设置纹理坐标系
    273. textureVertexBuffer2.position(0);
    274. GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
    275. GLES20.glVertexAttribPointer(aTextureCoordLocation, 2, GLES20.GL_FLOAT, false, 8,
    276. textureVertexBuffer2);
    277. len = vertexData2.length / 3;
    278. } else {
    279. //设置顶点坐标系
    280. vertexBuffer.position(0);
    281. GLES20.glEnableVertexAttribArray(aPositionLocation);
    282. GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer);
    283. //设置纹理坐标系
    284. textureVertexBuffer.position(0);
    285. GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
    286. GLES20.glVertexAttribPointer(aTextureCoordLocation, 2, GLES20.GL_FLOAT, false, 8,
    287. textureVertexBuffer);
    288. len = vertexData.length / 3;
    289. }
    290. //激活纹理单元,默认第0个纹理单元
    291. GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    292. //将纹理对象ID绑定到当前活动的纹理单元0上的GL_TEXTURE_2D目标
    293. GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
    294. GLES20.glUniform1i(uTextureSamplerLocation, 0);
    295. GLES20.glViewport(0, 0, screenWidth, screenHeight);
    296. //绘制4个点
    297. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, len);
    298. ShaderUtil.checkGlError("glDrawArrays");
    299. EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);
    300. if (mListener != null) {
    301. mListener.onRendererDrawFrame();
    302. }
    303. }
    304. @Override
    305. public void onFrameAvailable(SurfaceTexture surfaceTexture) {
    306. Log.d(TAG, "onFrameAvailable --");
    307. updateSurface = true;
    308. synchronized (lock) {
    309. lock.notify();
    310. }
    311. if (mListener != null) {
    312. mListener.onRendererFrameAvailable();
    313. }
    314. }
    315. public void release() {
    316. Log.d(TAG, "release");
    317. canWhile = false;
    318. updateSurface = false;
    319. synchronized (lock) {
    320. lock.notify();
    321. }
    322. }
    323. }


     

     
    

     
    
     
    

    
                    
  • 相关阅读:
    C# OpenCvSharp Mat操作-操作符重载
    postgresql使用group by进行数据去重-2022新项目
    MYSQL索引——B+树讲解
    【开卷数据结构 】平衡二叉树
    数字IC前端设计流程及详细解释
    如何使用DALL-E 3
    计算机毕业论文java毕业设计选题源代码javaweb学生信息管理/学生考试系统[包运行成功]
    818专业课【考经】—《信号系统》之章节概要:第六章 连续时间系统的变换域分析
    25考研数据结构复习·3.1栈·顺序栈·链栈
    RIP协议;OSPF协议;BGP协议
  • 原文地址:https://blog.csdn.net/so1993/article/details/125486132