Android SurfaceTexture说明

news2025/7/24 5:10:20

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/394856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习笔记三:容器,镜像相关操作,并部署nginx

这里写目录标题镜像相关命令从dockerhub查找镜像容器相关操作以交互式方式启动并进入容器以守护进程方式启动容器查看正在运行的容器通过docker部署nginx服务在docker里安装nginx创建静态页面访问docker里的nginx服务流量走向&#xff1a;镜像相关命令 从dockerhub查找镜像 d…

mTip 输入法状态跟踪提示 ,可以更改热键等

ImTip ( 输入法状态跟踪提示 )最新版本是 v4.4 :免费开源&#xff0c;仅 715 KB。单文件绿色软件&#xff0c;无任何外部依赖&#xff0c;兼容 XP&#xff0c;Vista&#xff0c;Win7&#xff0c;Win8&#xff0c;Win10&#xff0c;Win11 …… 等所有流行桌面操作系统。源代码: …

Java设计模式笔记——六个创建型模式

系列文章目录 Java设计模式笔记——七大设计原则 文章目录系列文章目录一、简单工厂模式1.概念2.案例分析3.使用简单工厂模式进行改进4.总结二、工厂方法模式1.概念2.案例分析3.使用工厂方法模式进行改进4.总结三、抽象工厂模式1.概念2.案例分析3.使用抽象工厂模式改进4.总结四…

跨端技术或许是提升软件运维效率的利器

凡是代码&#xff0c;难免有 bug。 开发者们的日常&#xff0c;除了用一行行代码搭产品外&#xff0c;便是找出代码里的虫&#xff0c;俗称 debug。 ​随着移动互联网的快速发展&#xff0c;App 已经成为日常生活中不可或缺的一部分。但是在开发者/运维人员的眼里简直就是痛苦…

Win YAPI + Jenkins 实现接口自动化测试

自动化测试 传统的接口自动化测试成本高&#xff0c;大量的项目没有使用自动化测试保证接口的质量&#xff0c;仅仅依靠手动测试&#xff0c;是非常不可靠和容易出错的。 为了解决这个问题&#xff0c;使用YAPI接口自动化测试功能&#xff0c;只需要配置每个接口的入参和对 RE…

网络类型以及数据链路层协议

网络类型以及数据链路层协议网络类型是根据我们数据链路层所运行的协议及规则来划分网络类型的分类P2P --- 点到点 --- point to pointMA --- 多点接入网络BMA --- 广播型多点接入网络NBMA --- 非广播型多点接入网络数据链路层协议MA网络以太网协议特点&#xff1a;需要使用MAC…

Java代码弱点与修复之——Explicit null dereferenced(显式空间接引用)

弱点描述 Explicit null dereferenced, 显示空间接引用。是 Coverity 静态代码分析工具检测到的一种中风险缺陷。这种缺陷通常发生在尝试使用空指针引用调用对象上的方法或访问属性时。 Explicit null dereferenced的缺陷可能会导致程序崩溃或产生不可预测的结果。 在Java语…

0102 MySQL05

1.约束 1.约束&#xff08;constraint&#xff09;&#xff1a;在创建表时&#xff0c;可以给表中的字段加上一些约束&#xff0c;保证表中数据的完整性&#xff0c;有效性 常见的约束&#xff1f; 非空约束&#xff1a;not null 唯一性约束&#xff1a;unique 主键约束&am…

在VM16.X虚拟机上安装Android-X86 9.0

前提&#xff1a;电脑已安装好VM虚拟机&#xff0c; 第一步&#xff1a;下载好安卓9.0系统 https://www.fosshub.com/Android-x86.html 第二步&#xff1a;开始安装 1、新建虚拟机&#xff08;按图片上的点一下步&#xff09; 点浏览&#xff0c;确定虚拟机位置 处理器配置建…

深度剖析C语言预处理

致前行的人&#xff1a; 人生像攀登一座山&#xff0c;而找寻出路&#xff0c;却是一种学习的过程&#xff0c;我们应当在这过程中&#xff0c;学习稳定冷静&#xff0c;学习如何从慌乱中找到生机。 目录 1.程序翻译过程&#xff1a; 2.字符串宏常量 3.用宏定义充当注释符号 4…

【笔记】若依不分离的$.modal.open()打开多个子窗口,关闭子窗口刷新父窗口问题

前言 如题所述&#xff0c;当前遇到的问题是&#xff1a;我在若依不分离版的一个普通HTML页面A使用 $.modal.open()打开一个子窗口B&#xff0c;且在这个子窗口里再次使用 这个函数打开一个子窗口C&#xff0c;这时的情况就是 A 界面有子窗口 B&#xff0c; B 窗口又有一个子…

《系统架构设计》-06-面向领域思想和策略设计

文章目录1 面向领域思想1.1 架构设计与领域驱动1.1.1 领域驱动设计1.1.2 使用领域驱动设计的条件1.2 领域驱动设计核心概念1.2.1 策略维度1.2.2 技术维度2. 面向领域的策略设计2.1 通用语言2.2 领域与上下文2.2.1 架构轮回2.2.2 系统拆分子域界限上下文系统拆分策略2.2.3 上下文…

Mysql—主从复制

主从复制 创建mysql 基于docker创建2个mysql容器 1、拉取mysql镜像&#xff0c;这里拉取最新的8.0.20 docker pull mysql:latest2、使用镜像运行两个mysql容器&#xff1a;mysql 和 mysql-2 docker run -itd --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORDroot mysql …

Ubuntu系统升级16.04升级18.04

一、需求说明 作为Linux发行版中的后起之秀&#xff0c;Ubuntu 在短短几年时间里便迅速成长为从Linux初学者到实验室用计算机/服务器都适合使用的发行版&#xff0c;目前官网最新版本是22.04。Ubuntu16.04是2016年4月发行的版本&#xff0c;于2019年4月停止更新维护。很多软件支…

C++学习笔记之提高

目录C提高一.模板1.1.函数模板1.1.1语法1.1.2.普通函数与函数模板的区别1.1.3.普通函数与函数模板的调用规则1.1.4.模板的局限性1.2.类模板1.2.1.类模板与函数模板的区别1.2.2.类模板中的成员函数的创建时机1.2.3.类模板做函数的参数1.2.4.类模板与继承1.2.5.类模板成员函数类外…

cesium——飞行定位

Cesium的飞行定位&#xff0c;主要通过Viewer、Camera这两个类实现的。其中viewer.flyTo()、camera.flyTo()、camera.flyToBoundingSphere()这三个方法会有一个飞行动画的效果&#xff0c;所以会有飞行持续时间参数duration&#xff0c;默认是3秒。一、viewerflyTotarget&#…

电子台账:定义产品的行业代码和产品代码

1 简介水平过滤模板和垂直过滤模板定义好后&#xff0c;就可以进行数据抓取了。首次数据抓取后&#xff0c;用产品名称对产品代码表进行填充&#xff0c;程序会提示补充完善产品代码表&#xff0c;需要人工对产品代码表中的信息进行完善。产品代码表补充完整后&#xff0c;以后…

【微信小程序】如何使用阿里巴巴的icon自定义图标以及简单的下拉框组件实现全过程

前言 小编我将用CSDN记录软件开发之路上所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注一下&#xff01;也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff0c;才能走的更远&#xff01;让我们在成长的道路上互相学习&#xff0c;让我们共…

CUDA By Example笔记--线程协作

1--使用线程实现GPU上的矢量求和 完整代码&#xff1a; # include <iostream> # define N (33 * 1024)__global__ void add(int* a, int* b, int* c){int tid threadIdx.x blockIdx.x * blockDim.x;while (tid < N){c[tid] a[tid] b[tid];tid blockDim.x * grid…

pyqt 小项目

此项目是别人用Q开发的&#xff0c;我模仿用Pyqt编写。仿写过程种发下c 和python在调用时还是有些不一样。遇到行不通时就要多尝试别的方法。不如在C里可以直接在cpp文件里传入QBrush和QPen对象&#xff0c;而在python里就不行&#xff0c;估计使用信号与槽可以&#xff08;本人…