Camera app 分析(四)预览与滤镜

Camera 预览有多种方式,如:
第一种方案 :SurfaceView + SurfaceHolder;
第二种方案 :GlSurfaceView + SurfaceTexture;
第三种方案 :TextureView + SurfaceTexture;

这3种显示的方法对比可以参考以下对比:
http://blog.csdn.net/jinzhuojun/article/details/44062175

由于我们需要做实时滤镜,如果用第一种方案来做的话,就需要通过设置 Camera.setPreviewCallback() 来获取每一帧的数据,获取到的数据由于是原始的 YUV 格式数据,显示到我们的 View 上还需要转成 RGB 格式,这就需要在 CPU 中对图像格式进行转换,所以效率并不高,并且采用Camera.setPreviewCallback()还有一个小问题,就是必须要先用Camera.setPreviewDisplay()对Camera设置一个预览的SurfaceView。对于那些不想显示原始的预览效果的应用来说,可以把SurfaceView的尺寸设为 1×1,让用户不可见。

第二种方案 Camera 通过 SurfaceTexture 把数据渲染到纹理上,再通过 OpenGL 来对纹理进行处理并贴到 GlSurfaceView 上,做实时渲染其实是在 OpenGL 的 shader 中对纹理的数据进行颜色矩阵的变化,这里用的是 GPU ,不占用 CPU ,所以效率会很高。

第三种方案其实和第二种方案差不多,也是通过 SurfaceTexture 把数据渲染到纹理上,不同的是不需要 OpenGL 即可以把纹理在 TextureView 里显示;但是要做实时滤镜的话还是要用到 OpenGL ,和GLSurfaceView不同,TextureView并没有自动为我们创建GL 上下文,render surface和GL thread。因此,如果我们需要在 TextureView 中用OpenGL进行绘制,必须手动地做这些事。

综合比较还是第二种和第三种方案好,第二种方案的话用起来没有第三种方案复杂,因为 GlSurfaceView 已经为我们创建了 OpenGL 所需的环境;第三种方案的优点是可以把 TextureView 当做是普通 View 一样进行变化;

这三种方案的实现可以参考以下:
http://tangzm.com/blog/?p=18
http://tangzm.com/blog/?p=20

以上变化我们是不用到图像格式的转化的,但是还是要了解下,因为现在流行的直播软件是必须要进行转化后才能显示的,下面来介绍下 YUV 格式;

YUV 格式的详细介绍:
https://baike.baidu.com/item/YUV/3430784?fr=aladdin

其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色;

就是说加入只有 Y (即明亮度),那么图像是黑白的,加入了 U 和 V,图片才有颜色;

Camera 中默认用的是 YCbCr_420_SP的格式(NV21),即 YUV420SP 格式的数据;
详细介绍参考:http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html

Y,U,V三个分量的数量比是4:1:1.也就是说每四个像素共用一对UV。举个例子,如果是一个30*40的帧,那么有1200个Y分量,分别有300个U和300个V分量。总共有1200*1.5这么多个值。

YUV 转 RGB 的算法,其实是一种线性的比例,转换公式如下:

R=Y+1.4075*(V-128)G=Y-0.3455*(U-128) – 0.7169*(V-128)B=Y+1.779*(U-128)