Android SurfaceTexture说明

2023-10-23 08:40

本文主要是介绍Android SurfaceTexture说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

what

1. SurfaceTexture用来捕获视频流中的图像帧,视频流可以是相机预览或者是视频解码数据。

里边承接图像数据的也是GraphicBuffer, GLConsumer 作为其BufferQueue的消费方,取得数据后可以通过eglImage挂到opengles texture 里边对其做纹理采样。

how

1. 就用法来讲,主要就是有数据后BufferQueue Producer在queueBuffer时 回调应用的onFrameAvailable(),应用自己决定是否、何时调用updateTetxtureImage()去做纹理绑定、采样

2. BufferQueue:

native层,在SurfaceTexture native对象 创建前创建了生产者和消费者;

消费者作为其构造函数传入给SurfaceTexture;

生产者作为全局变量保存,同时也保存在SurfaceTexture java 对象的mProducer里边 ;

3.GraphicBuffer的获取

生产方:通过 SurfaceTexture_getProducer()获取到BufferQueueProducer ;

消费方:SurfaceTexture 在UpdateTexImage()时去acquireBuffer

相关技术点

SurfaceView

1. what

只拥有BufferQueue的生产端,消费端为SurfaceFlinger,渲染后必须上屏。

TextureView

1. what

由于其里边拥有SurfaceTexture, 可用于离屏渲染,拥有BufferQueue的生产端和消费端,

生产端可为camera、MediaCodec、任意render 模块, 可以跨进程(底层是GraphicBuffer嘛),消费端为SurfaceTexture GLConsumer, 可对图像做二次处理。

YUV

1. why

一般情况下SurfaceTexture承载的数据都是YUV类型(来自mediacodec、camera),有必要简单说下。

2. what

一种图像数据编码格式,常用的为YUV420,俗称I420,

各格式说明:

4:4:4 ,完全取样

4:2:2 ,2:1水平取样,垂直完全采样

4:2:0 ,2:1水平取样,垂直2:1采样

4:1:1 ,4:1水平取样,垂直完全采样

3. 格式 packed,planar、semi-planar

packed:不带后缀,如YUV420,数据以逐像素为单位排列,如

planar:带后缀P,如YUV420P,Y、U、V 分开存储,如

 

semi-planar:带后缀SP,如YUV420SP,UV交叉存储,与Y分开存储,如

这边可能要注意,排列可能为YYY.....UVUV, 或YYY...VUVU,即UV的第一个值到底是U还是V,

前者准确点叫YUV,后者叫YVU,又如 NV12、NV21 哈哈哈是不是有点迷糊了😜,

4. rgb与yuv的转换

一般可以用gpu,做个纹理采样去转,若gpu不支持硬件转换,需自己写shader;

有的gpu硬件支持直接转,如高通平台adreno,SurfaceTexture.updateTexImage()把YUV 图像数据挂上后,shader里边通过samplerExternal2D 采出来就是RGB数据。

5. android 系统 + 高通平台,如何获取不同YUV数据类型的GraphicBuffer大小,

接口:hardware/qcom/display/gralloc/gr_utils.cpp:: GetBufferSizeAndDimensions()

对于抓帧工具而言,将GraphicBuffer lock后,获取size,buffer里边分为Y、UV数据块,若是ubwc类型,头部还带meta数据,分块读取保存比较麻烦,由于这些分块数据在内存里边连续存储,所以可以直接整大块读取保存。

//notes: 该功能只有vendor才有能力开发,因为GraphicBuffer接口不对开发者开放,开放的AHardwareBuffer 相关的接口也起不了什么作用。

参考 kernel/msm-4.19/include/uapi/media/msm_media_info.h

EGLImage

1. what

 EGLImageKHR是EGL定义的一种专门用于共享2D图像数据的扩展格式,它可以在EGL的各种client api之间共享gpu侧数据(如OpenGL,OpenVG),也可称之为direct texture(Using direct textures on Android), 当我们需要对一块GraphicBuffer数据做纹理采样就可以使用EGLImage,所以其底层数据载体当然为GraphicBuffer。

对于Android系统,既然共享,又用了GraphicBuffer,那么就是不仅可以在不同线程间共享,还可以跨进程共享。

适用场景 : 需要经常更新纹理数据的场合,比如逐帧更新;

                   对camera、mediacode的输出做采样处理;

                   跨进程、跨线程共享纹理;

数据类型: 由于做为扩展给gpu厂家去自行支持, EGLImage里边可以存的数据其格式可以是opengles标准不支持的, 具体看厂家自己去实现,理论上可以存各种数据, 但一般在高通平台主要也就RGB和YUV,再加上是否带UBWC压缩。

2. why

性能优化,能跨进程、跨线程在gpu 侧直接共享纹理数据,减少拷贝次数;

在跨进程、跨线程共享texture上统一定义了标准接口与用法。

3. how

底层通过GraphicBuffer 实现(基于EGL_ANDROID_image_native_buffer 扩展),

所以原理上其实EGLImage只是一种接口封装,对GraphicBuffer的封装,将其封装成texture,

eglCreateImageKHR()
glBindTexture()
glEGLImageTargetTexture2DOES()
//glDrawXXX()
eglDestroyImageKHR()

4. 关于EGL_ANDROID_image_native_buffer 扩展

说明:

This extension enables using an Android window buffer (struct

ANativeWindowBuffer) as an EGLImage source.

该扩展使得可以将ANativeWindowBuffer 作为EGLImage的输入源

限制 :

If <target> is EGL_NATIVE_BUFFER_ANDROID, <dpy> must be a valid display,

<ctx> must be EGL_NO_CONTEXT, <buffer> must be a pointer to a valid

ANativeWindowBuffer object (cast into the type EGLClientBuffer), and

attributes other than EGL_IMAGE_PRESERVED_KHR are ignored."

即  对于EGLImageKHR eglCreateImageKHR( EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)

  dpy必须合法,上下文必须为EGL_NO_CONTEXT,

  buffer输入源必须为ANativeWindowBuffer,GraphicBuffer通过getNativeBuffer()类型转换而来。

引用自: frameworks/native/opengl/specs/EGL_ANDROID_image_native_buffer.txt

5. bind texture

可以通过glEGLImageTargetTexture2DOES() 与GL_TEXTURE_2D、GL_TEXTURE_EXTERNAL_OES绑定,

6. eglImage和eglImageKHR

带KHR表示khronos 加的扩展,整体用法在Android上应该都差不多,一般都用带KHR后缀的,

具体细节倒没理得那么清😂。

7. EGLImage和EGLSurface

相同点: 底层都是GraphicBuffer,都是可以作为RenderTarget或texture使用;

不同点:创建的接口不同,eglCreateWindowSurface()、eglCreatePixmapSurface()、eglCreatePbufferSurface()、eglCreatePbufferFromClientBuffer(),eglCreateImageKHR()

             用法不同,EGLImage上下文无关,可以跨进程、线程共享、

              EGLSurface 上下文绑定。

8. GraphicBuffer 与eglImage 关系

等我看看freedreno代码先。。。

9. 进程间共享图像数据方式

GPU侧:GraphicBuffer + EGLImage + oes texture;

CPU侧:共享内存;

10. 共进程,不同opengl es线程共享纹理方式

(1)share context后,共享texture;

(2)EGLImage;

GL_TEXTURE_EXTERNAL_OES

1. what

俗称oes texture, 专门为EGLImage而加的texute类型,对于装有YUV数据的EGLImage,EGLImage一般通过挂到GL_TEXTURE_EXTERNAL_OES去做处理;

shader里边的sampler类型: samplerExternalOES;

如果是采样YUV数据类型的纹理,会自动转成RGB(GPU厂商需要实现这个功能),

Sampling an external texture will return an RGBA vector in the same colorspace as the source image. If the source image is stored in YUV (or some other basis) then the YUV values will be transformed to RGB values.

2. why

为何不直接挂到GL_TEXTURE_2D处理呢? 为什么要加上这个扩展?

这块理的不是特别清楚,相关资料都没讲得那么清,以下是一些整理+自己理解

/**

* mTexTarget is the GL texture target with which the GL texture object is

* associated. It is set in the constructor and never changed. It is

* almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android

* Browser. In that case it is set to GL_TEXTURE_2D to allow

* glCopyTexSubImage to read from the texture. This is a hack to work

* around a GL driver limitation on the number of FBO attachments, which the

* browser's tile cache exceeds.

*/

来自:frameworks/base/libs/hwui/surfacetexture/SurfaceTexture.h

即,除非需要从fbo拷贝数据到该texture挂的eglimage,才会将该eglImage挂到GL_TEXTURE_2D上,

而咱们一般都是对这块eglimage做采样嘛,所以要挂到GL_TEXTURE_EXTERNAL_OES上。

(感觉有点牵强,可以先接着往下看)

(1)外部纹理,即gpu侧图像数据来自其他上下文,对其采样时,目前的GL_TEXTURE2D不能挂,需要用eglimage挂到GL_TEXTURE_EXTERNAL_OES,

(2)硬件对YUV转RGB的支持

对于装YUV数据格式的EGLImage,一般GPU也不支持硬件YUV转RGB,若直接挂到GL_TEXTURE_2D做采样,需要自己在shader做RGB转换;

TEXTURE_EXTERNAL_OES 作为扩展,当GPU支持硬件YUV转RGB时,就会通过支持该扩展来表明。

3. how

怎么把gpu这个功能用上呢?

使用TEXTURE_EXTERNAL_OES,把EGLImage挂上去。

eglCreateImageKHR()
glBindTexture(TEXTURE_EXTERNAL_OES, textureId)
//eglImage 装YUV格式数据
glEGLImageTargetTexture2DOES(TEXTURE_EXTERNAL_OES, eglImage)
//glDrawXXX()
eglDestroyImageKHR()

通过samplerExternalOES类型的采样器,从YUV数据类型的TEXTURE_EXTERNAL_OES里边采样出来的数据,就是RGB,gpu做了转换,无需shader去转,eg:

            //声明使用该扩展"#extension GL_OES_EGL_image_external : require\n" +"precision mediump float;\n" +//指定sampler类型"uniform samplerExternalOES tex_sampler_0;\n" +"varying vec2 v_texcoord;\n" +"void main() {\n" +"  gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" +"}\n";

跨线程使用

1. 准确的说是跨拥有不同opengles context的线程

attachToGLContext()
detachToGLContext()//通过这2个接口跨线context

代码分析

1. 主要代码流程

SurfaceTexture.java 
-->
base/core/jni/android/graphics/SurfaceTexture.cpp
-->
base/libs/hwui/surfacetexture/SurfaceTexture.cpp
--> 
EGLConsumer.cpp 
--> 
opengl es

SurfaceTexture.java:

主要是做类的作用、用法说明,对每个接口做了详细的说明,没什么逻辑,都是直接转调native 接口,

base/core/jni/android/graphics/SurfaceTexture.cpp:

实现SurfaceTexture.jave 的jni接口,里边没什么具体逻辑, 主要是承接 SurfaceTexture.jave 和base/libs/hwui/surfacetexture/SurfaceTexture.cpp

base/libs/hwui/surfacetexture/SurfaceTexture.cpp:

对SurfaceTexture.java的实现,主要是GraphicBuffer 的处理

EGLConsumer.cpp :

opengl es接口的封装,主要做了 基于acquireBuffer()出来的GraphicBuffer创建eglImageKHR, 将其挂到指定的oes texture 上

2. 时序图

注册SurfaceTexture.OnFrameAvailableListener:

 生产者生产完一块GraphicBuffer 数据后回调onFrameAvailable() 流程:

UpdateTextureImage(),消费者消费该GrapicBuffer,将其挂到opengles texture做纹理采样流程:

参考

https://blog.csdn.net/xkuzhang/article/details/115423061

https://paaatrick.com/2020-01-26-yuv-pixel-formats/

https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_image_base.txt

https://registry.khronos.org/OpenGL/extensions/OES/OES_EGL_image_external.txt

http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt

这篇关于Android SurfaceTexture说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/266754

相关文章

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

log4j2相关配置说明以及${sys:catalina.home}应用

${sys:catalina.home} 等价于 System.getProperty("catalina.home") 就是Tomcat的根目录:  C:\apache-tomcat-7.0.77 <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" /> 2017-08-10

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使