微信号:appjiagou

介绍:分享最有价值的APP技术干货文章,做一个有逼格的APP架构师,拒绝平庸,打造最有价值的APP社区!

Android TextureView的原理分析_haihengcao_新浪博客

2017-01-03 08:39 APP架构师



图1 TextureView及其依赖的java/c++类

本文将从TetureView的用途、使用模式及其在Framework依赖的类(图1所示那些)的三个方面进行说明。

1. 用途

TextureView可用于承载显示『数据流』的场合,之前看到『流』不太明确其意义,这里给两个具体的场景大家体会一下:camera模块从sensor采集了1080p@30fps的预览数据『流』,视频通话模块从网络包里解出实时视频数据『流』。

2. 使用模式

说了它的用途,我们看下TextureView工作的模式。刚了解到新浪博客是不支持贴代码的,这是要逼着人说人话。好在此处代码不长,看图说话!

图2 基于TextureView的Camera应用

使用TextureView的步骤:

(1)MainActvity要实现TextureView.SurfaceTextureListener接口

(2)创建TextureView,并将MainActvity设置为SurfaceTextureListener,供系统回调MainActvity实现的onSurfaceTextureXXX接口方法

(3)在onSurfaceTextureAvailable回调中拿到SurfaceTexture,并把它设置给camera,作为承载、预览数据『流』的载体

(4)在onSurfaceTextureDestroyed中关闭预览,释放camera资源,返回true

每个步骤的界面都很清晰。如果大家用过GLSurfaceView,用户代码里要显式的控制SurfaceTexture的声明、生成、下传,而TextureView则把SurfaceTexture干净的从用户视野中拿掉了,这就是被叫做『Texture』View的原因吧!

到这儿,TextureView的用途和使用模式都讲清楚了。看过了咱们的牛,接下来要认真的屠牛啦,Go!

3. Framework代码解析

3.1 TextureView与『上一级』关系

从图1可以看到TextureView与『上一级』(即用户代码中的MainActivity)只存在SurfaceTextureListener这一个关联点,表现为TextureView会在『适当』的时候调用『上一级』实现的SurfaceTextureListener接口方法。

3.2 TextureView内部结构

图1里TextureView与SurfaceTexture构成了组合关系,可见SurfaceTexture的确是由TextureView给『包办』了。在程序世界中,一个对象被『包办』无非是指:

(1)这个对象什么时候被创建?

(2)这个对象如何被创建?

(3)这个对象的产生带来了哪些变化,或者说程序自从有了它有哪些不同?

(4)这个对象什么时候被销毁?

之所以对SurfaceTexture这个对象要大动笔墨,因为它是整个显示框架的『连接者』。

3.3 SurfaceTexture与『上一级』关系

Java层的SurfaceTexture,有setOnFrameAvailableListener方法,其将『上一级』对象(即TextureView)设置为onFrameAvailableListener,这样SurfaceTexture在拿到新的『流』数据时会通知TextureView。

3.4 SurfaceTexture底层结构

SurfaceTexture.java会直接调用SurfaceTexture.cpp中的native方法,注意后者是一层JNI,而非c++类。在创建Java层SurfaceTexture对象时,向下调用SurfaceTexture_init方法,其调用BufferQueue::createBufferQueue静态方法,后者会做以下几件事:

(1)创建BufferQueueCore

(2)将BufferQueueCore作为参数创建BufferQueueProducer

(3)将BufferQueueCore作为参数创建BufferQueueConsumer

BufferQueueCore最重要的对象就是mAllocator,其为IGraphicBufferAlloc类型,其作用只有一个:分配GraphicBuffer内存。其类型是I开头的,我们似乎嗅到了什么。难道一个内存分配器都要通过IPC拿到?对,就是这样!

获取内存分配器的过程为:源进程(比如Camera APK)获取SurfaceComposer服务,通过该服务获取IGraphicBufferAlloc对象,后续内存分配要通过BufferQueueCore对象,都要通过BufferQueueCore的mAllocator对象,最终都要透过SurfaceComposer进程向Gralloc模块分配GraphicBuffer。

我们已经知道BufferQueueCore可以提供强大的GraphicBuffer分配支持。接下来聊聊BufferQueueProducer,从图1看出其为BnGraphicBufferProducer的子类,也是『I』字辈的,对也是用来IPC的家伙!这里分析下图2里onSurfaceTextureAvalilable中调用mCamera.setPreviewTexture(surface)这一瞬间发生的惊人内幕

(1)快进,直接调到了native层BpCamera->setPreviewTarget(BufferQueueProducer),注意BufferQueueProducer是本地对象,『Bn』辈的小生。

(2)跨进程发生:BufferQueueProducer对象到了内核,内核发现这货是个Binder,拦下,强行登记,只放走了一个『号码牌』(即handle)给目标进程(CameraService进程)。目标进程拿着号码牌,生成了一个BpBinder对象,此时这个BpBinder对象已经拥有了向内核找到源进程、以及源进程中BufferQueueProducer对象的能力。这个BpBinder没闲着,前脚被生成,后脚就被『踹进』了BpGraphicBufferProducer,就是『Bp』辈的后生。

(3)我要内存:CameraServcie可是内存消耗大户,1080p@30fps的YUV数据流,闹着玩呢!要分配内存,怎么干?很简单CameraServcie进程中直接用BpGraphicBufferProducer->dequeueBurffer或者requestBuffer即可。

(4)实际内存分配:BpGraphicBufferProducer因为有BpBinder,自然可以唤醒源进程(Camera APK进程)中的BnGraphicBufferProducer,调用对应的requestBuffer。实作的BnGraphicBufferProducer后生BufferQueueProducer拥有BufferQueueCore,自然可以向SurfaceCompser进程申请到GraphicBuffer,一路返还即可。

剩下的就是CameraServcie进程填充好了GraphicBuffer,然后BpGraphicBufferProducer->enqueue将其置入队列,Camera APK进程中的BufferQueueProducer自然直到这个事件,可以在SurfaceTexuture.cpp这层JNI向上通知frameAvailable。

3.5 聊聊Surface

最后,聊聊Surface这个native层类。Surface继承ANativeWindow,它的核心的就是传入它的IGraphicBufferProducer对象,后续所有对Surface的操作都会传递到IGraphicBufferProducer。在CameraService进程,在拿到BpGraphicBufferProducer后,会在该进程生成一个Surface,传入的正是前者。而Surface则作为ANativeWindow类型,畅通无阻的传入了HAL模块。貌似它的作用就是给Android平台提供统一的一个window接口层。


 
APP架构师 更多文章 Android属性动画源代码解析(超详细) Android DiskLruCache 源码解析 硬盘缓存的绝佳方案(上) Android 沉浸式状态栏攻略 让你的状态栏变色吧 Android干货框架集锦,搭建项目必不可少 国内Top500Android应用分析报告
猜您喜欢 自相矛盾:Null is Not Null引发的成本误区 weui.js v1.0.0 正式发布 定了,云技术社区新Logo,求点评 Filco Minila Air + Mac 如何设计选择菜单