gpt4 book ai didi

一文学会TextureID渲染到Surface

转载 作者:我是一只小鸟 更新时间:2023-07-12 22:31:36 26 4
gpt4 key购买 nike

最近遇到一个需求,要求将一个GL_TEXTURE_2D类型的纹理ID写入到ImageReader生成的Surface中。 其实这个需求与我之前写过的一篇文章 一文学会MediaCodeC与OpenGL录制mp4视频 需求比较接近,只需要对该案例源码进行一些改造即可.

在正式介绍实现之前,需先明确:

  • 什么是 android.view.Surface
  • 如何向 Surface 中写入数据?

1、Surface

什么是 android.view.Surface ?

  • 用高大上方式(让人听不懂的方式)表述如下:
    android.view.Surface  是 Android 系统中一个重要的图形渲染类,它用于与硬件显示层进行通信,将图形数据渲染到屏幕上,可以用于实现多种功能,如视频播放、相机预览、屏幕录制等。
    Surface  对象代表了一个画布,可以在其上绘制图形,这些图形将通过硬件显示层呈现在屏幕上。可以在  SurfaceView TextureView WindowManager  等控件中使用  Surface  进行图形渲染。此外, Surface  还可以用于视频播放、相机预览、屏幕录制等功能。
  • 查阅官方描述、源码实现,总结为一句通俗易懂的话:
    Surface是一个Java层类,其持有一个Native (C层) 管理的图像缓冲区句柄。由图像缓冲区的消费者创建(如MediaRecorder),通过Surface将句柄传递给图像的生产者 (如MediaPlayer) 进行渲染。

1.1 官方描述

关于 android.view.Surface 官方描述如下:

android.view.Surface官方描述

翻译过来就是:

Surface 持有一个由屏幕合成器管理(Native层管理)的 原始缓冲区的句柄 。通常是由 图像缓冲区的消费者 (如 SurfaceTexture、MediaRecorder、Allocation等)创建或生成,并被 传递给生产者 (如 OpenGL、MediaPlayer、CameraDevice等)进行绘制。 因为, Surface 只是持有Native层缓冲区的句柄,若Native层的指针被释放后,则该 Surface 不再有效.

1.2 官方源码

查看 Surface 源码,可以看到 Surface 通过持有Native层的句柄 mNativeObject 来管理原始数据缓冲区.

android.view.Surface源代码

1.3 官方文档

查看 Surface 官方文档,查看其所有的公有方法:

android.view.Surface公有方法

看到上述公有方法后,发现除了通过 lockCanvas() 方法可以获取一个 Canvas 对象,然后使用 drawBitmap() 等API写入图形数据外,并无其他有用的方法,帮助我们实现 TextureID 纹理ID的写入.

2、向Surface写入数据

要向  Surface  持有的  mNativeObject  句柄中写入图像数据,我现在已知有两种方式:

  • 第一种方式是上文提到的通过 Canvas 写入;
  • 第二种方式是通过 OpenGL 写入,也就是本文的要介绍的重点;

2.1 通过Canvas写入

上文介绍到,在查看 Surface 的公有方法后,发现通过 lockCanvas() 方法可以获取一个 Canvas 对象,然后使用 drawBitmap() 等API写入图形数据,操作步骤如下:

  • 通过  SurfaceHolder  获取  Surface  对象;
  • 通过  Surface  对象的  lockCanvas()  方法获取  Canvas  对象;
  • 在  Canvas  上进行绘制操作,例如调用  drawBitmap()  方法绘制位图;
  • 通过  Canvas  对象的  unlockCanvasAndPost()  方法将绘制结果提交到  Surface  中,从而实现在屏幕上渲染数据。

以下为简单的代码举例:

                        
                          SurfaceHolder holder = surfaceView.getHolder();
Surface surface = holder.getSurface();
Canvas canvas = surface.lockCanvas(null);
// 在 canvas 上进行绘制操作
canvas.drawBitmap(bitmap, 0, 0, null);
surface.unlockCanvasAndPost(canvas);

                        
                      

2.2 通过OpenGL写入

通过OpenGL向Surface中写入数据,其根本原理是:

将Surface绑定到一个EGLSurface上,然后通过OpenGL向EGLSurface渲染数据,最终将结果渲染到关联的Surface上。 具体实现是使用 EGL 提供的 eglCreateWindowSurface() 函数,将 EGLSurface 与 Surface 对象关联起来。然后就可以通过 OpenGL ES 将渲染结果绘制到 EGLSurface 中,最终渲染到Surface上.

其代码实现举例如下所示:

                        
                          // 获取 EGLDisplay 对象
EGLDisplay mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
// 初始化 EGL 环境
int[] version = new int[2];
EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)
// 配置 attribList
int[] attribList = {
        EGL14.EGL_RED_SIZE, 8,
        EGL14.EGL_GREEN_SIZE, 8,
        EGL14.EGL_BLUE_SIZE, 8,
        EGL14.EGL_ALPHA_SIZE, 8,
        //
        EGL14.EGL_RENDERABLE_TYPE,
        EGL14.EGL_OPENGL_ES2_BIT,
        0x3142,
        1,
        EGL14.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
EGL14.eglChooseConfig(mEglDisplay, attribList, 0, configs, 0, configs.length, numConfigs, 0);
// 获取 EGLContext 上下文
EGLContext shareEglContext = inEglContext;
// 配置 EGLContext 属性
final int[] attrib_list = {
        EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL14.EGL_NONE
};
// 获取 EGLDisplay 对象
EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
// 创建一个 EGLSurface 对象(绑定surface)
EGLSurface eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, configs[0], surface, surfaceAttribs, 0);
// 将 EGLSurface 和 EGLContext 绑定到 EGLDisplay 上
EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

// 渲染图形 ...

// 交换前后缓冲(将egl渲染结果交换到surface上)
EGL14.eglSwapBuffers(eglDisplay, eglSurface);

                        
                      

3、源码下载

将一个GL_TEXTURE_2D类型的纹理ID写入到ImageReader生成的Surface中, 源码案例工程下载地址如下: https://download.csdn.net/download/aiwusheng/87959680 。

案例代码实现流程流程如下:

  • OpenGLES3 中加载GL_TEXTURE_2D纹理,生成纹理ID;
  • 通过 EGL 构建 EGLDisplay 并绑定ImageReader提供的Surface
  • 在 EGL 线程中渲染GL_TEXTURE_2D对应的纹理图形;
  • 在 EGL 线程中完成渲染后,通过eglSwapBuffers交换缓冲数据;
  • 在 ImageReader 中 onImageAvailable 中读取Surface数据,并将数据保存为一张Bitmap;
  • 将的Bitmap显示到 ImageView 上(用于验证纹理ID是否正常写入到Surface)

案例源码效果图如下图所示:

案例源码效果图

= THE END =

最后此篇关于一文学会TextureID渲染到Surface的文章就讲到这里了,如果你想了解更多关于一文学会TextureID渲染到Surface的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com