Android Camera预览实现方案总结

前言:

开发过camera apk的人可能都听过SurfaceView、SurfaceTexture、GLSurfaceView、TextureView等等这些东西,刚接触的时候可能很懵,到底为啥会有这么些View?到底有什么区别?哪些场景用哪些好一点?

博主也做了很长时间的Camera开发,惭愧!知道的也不多,不深入,仅仅记录下最新的理解,方便日后更新总结,也给初探者一点点帮助。

进入正题:

无论哪种预览方案,都离不开Surface这个对象,App将Surface传递给CameraServer,CameraServer拿到GraphicBuffer对应的buffer_handle,继续传给HAL,HAL再对buffer_handle进行映射,拿到buffer地址,往该地址上填充数据。数据填充完返回上层,要么是回到SurfaceTexture(onFrameAvailable),要么就是回到BLASTBufferQueue(onFrameAvailable)...

SurfaceView、SurfaceTexture、GLSurfaceView、TextureView、ImageReader这些东西的背后都是BufferQueue,BufferQueue就是一个生产者--消费者模型。生产者就是surface(对相机而言,本质的生产者就是camera),消费者就是所有onFrameAvailable实现的地方(以上各个组件有的不一样,有的实质上一样的)。

SurfaceView:

surfaceview是很常用的相机预览方案,我们直接通过getHolder.getSurface就可以获取surface,阅读SurfaceView源码可以看到,SurfaceView有个成员就是BLASTBufferQueue,BLASTBufferQueue就是背后的生产者消费者模型,底层填充完buffer数据之后也是直接回到BLASTBufferQueue里面的onFrameAvailable,继续调用到SurfaceFlinger。

所以SurfaceView这种预览方式而言,预览数据对app来说完全是个黑盒,完全无感,app开发者完全摸不到预览数据在哪,这也是为啥surfaceview很好用,但是理解不深的原因。

SurfaceView非常适合的场景就是扫码之类的应用,这些应用不需要对预览数据进行二次处理,仅仅显示源数据。

SurfaceTexture+GLSurfaceView:

这两个是需要放在一起的,单独讲并不好讲。

GLSurfaceView是SurfaceView的子类,比SurfaceView多的是内部创建了EGL环境,开发者不需要自己创建EGL环境了。

SurfaceTexture背后也是一个生产者消费者模型,但是更多的时候一些纹理和Image的操作,创建KHRImage,绑定Image这些。

SurfaceTexture、GLSurfaceView背后都有一个生产者消费者模型,他们是怎么分工的呢?

对于相机预览,我们先创建纹理,再用纹理创建SurfaceTexture,再用SurfaceTexture创建Surface,将Surface下发给Camera就行了,相机数据生产完成之后通过onFrameAvailable回到应用,应用收到每一帧的预览回调(注意不是预览数据)。所以可以看到SurfaceTexture能拿到预览回调了,比SurfaceView貌似高级一点了。到这里我们总结一下,SurfaceTexture就是预览数据的载体,SurfaceTexture就是这个阶段的消费者。

SurfaceTexture预览数据的载体了,但是预览怎么显示呢?那就是GLSurfaceView的事情了,GLSurfaceView背后也是生产者消费者模型,这时候生产者可以理解成SurfaceTexture了,因为数据从它这来;消费者就是BLASTBufferQueue里面的onFrameAvailable(最终是SurfaceFlinger)

具体opengl的绘制这些就不细讲了。

SurfaceTexture+GLSurfaceView适合那种对预览进行二次处理的场景,单也仅仅是opengl方式的处理,因为上面提到SurfaceTexture收到每一帧的预览回调(注意不是预览数据),我们起初绑定的也仅仅是个纹理id

TextureView:

再来看看TextureView,相对前面的两种,TextureView用的比较少了。通过名字也能看出它是含有纹理的,阅读源码看到TextureView里面有个成员就是SurfaceTexture,所以和SurfaceTexture+GLSurfaceView的预览方式有相同之处,就是都是通过SurfaceTexture从相机获取数据;不同的是TextureView继承自普通View,绘制流程是通过draw函数一路下去的,具体也没怎么看懂,先记着。

ImageReader+GLSurfaceView:

再来看看ImageReader,这是Camera Api2里面常用的一个类了,Camera Api2里面拍照的话是一定要用到这玩意的(其他方式可能也有,但是没见过),那么预览可不可以用ImageReader呢?当然是可以的。

ImageReader的背后同样也是生产者--消费者模型。

ImageReader非常灵活的是可以自己定义需要的数据格式(yuv,jpg,raw),那么预览的时候我就定义一个yuv格式的,然后将ImageReader.getSurface 获取surface传给相机。

ImageReader的onFrameAvailable回掉拿到的是实实在在的yuv数据,那好了,app想做什么算法都可以,可以先做CPU的算法在做GPU的算法。

yuv数据可以通过khr的一些接口绑定到纹理上,再用GLSurfaceView绘制显示。

总结:

以上就是一点简单的总结,当然预览方案不仅仅就这些。比如GLSurfaceView和SurfaceView相比就是多了EGL环境创建,那我们完全可以自己创建环境。那么SurfaceTexture+SurfaceView、ImageReader+SurfaceView的方案也是可行的。

总的来说,知道他们背后都是生产者--消费者模型这条主线就行了,生产者就是各种方式获取的surface,消费者就是onFrameAvailable实现的地方。

相关推荐
人生游戏牛马NPC1号1 小时前
学习 Flutter (三):玩安卓项目实战 - 上
android·学习·flutter
小馬佩德罗2 小时前
Android系统的问题分析笔记 - Android上的调试方式 debuggerd
android·调试
清霜之辰4 小时前
安卓基于 FirebaseAuth 实现 google 登录
android·google·auth·firebase
GitLqr4 小时前
数码洞察 | Apple VS DMA、三星新品、Android 16KB Page Size
android·ios·samsung
alexhilton4 小时前
SnapshotFlow还是collectAsState?对于Jetpack Compose来说哪个更香?
android·kotlin·android jetpack
Erwooow5 小时前
Android 16k jni修改
android
l软件定制开发工作室5 小时前
基于Android的景点旅游信息系统App
android
张可6 小时前
一个KMP/CMP项目的组织结构和集成方式
android·前端·kotlin
林林要一直努力6 小时前
AOSP Settings模块问题初窥
android·学习·bug·android studio
顾林海6 小时前
Android 性能优化:启动优化全解析
android·java·面试·性能优化·zygote