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

相关推荐
雨白2 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹3 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空5 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭5 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日6 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安6 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑6 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟11 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡12 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0012 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体