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实现的地方。

相关推荐
试行15 分钟前
Android实现自定义下拉列表绑定数据
android·java
Dingdangr5 小时前
Android中的Intent的作用
android
技术无疆5 小时前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
GEEKVIP5 小时前
Android 恢复挑战和解决方案:如何从 Android 设备恢复删除的文件
android·笔记·安全·macos·智能手机·电脑·笔记本电脑
Jouzzy12 小时前
【Android安全】Ubuntu 16.04安装GDB和GEF
android·ubuntu·gdb
极客先躯13 小时前
java和kotlin 可以同时运行吗
android·java·开发语言·kotlin·同时运行
Good_tea_h15 小时前
Android中的单例模式
android·单例模式
计算机源码社20 小时前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
丶白泽20 小时前
重修设计模式-结构型-门面模式
android
晨春计1 天前
【git】
android·linux·git