19.相机预览
相机预览可以使用OpenGL方便的实现相机美颜、滤镜、塑性以及一些特效。
相机的预览实现一般有2种方式:
- 一种是基于Android原生SurfaceTexture的纯GPU实现方式
- 一种是通过相机的预览回调接口获取帧的YUV数据,利用CPU算法处理完成之后,传入显存,再利用GPU实现YUV转RGBA进行渲染,即CPU + GPU的实现方式
基于Android原生SurfaceTexture的纯GPU实现方式,相机可以使用SurfaceTexture作为预览载体。
SurfaceTexture可以来自于GLSurfaceView、TextureView或SurfaceView这些独立拥有Surface的封装类,也可以自定义实现。
作为预览载体的SurfaceTexture绑定的纹理需要是OES纹理。
使用OES纹理后,我们不需要在片段着色器中自己做YUV to RGBA的转换,因为OES纹理可以直接接收YUV数据或者直接输出YUV数据。
YUV
YUV和RGBA是两种不同的颜色编码格式,主要区别于在数据组织和应用场景。
-
YUV主要用于视频压缩、传输(例如H264/HEVC),优势为亮度和色度分离适合压缩(人眼对亮度更敏感,色度可降采样)。 YUV为视频压缩设计,牺牲直接显示兼容性换取高压缩率。
-
RGBA主要用于图像显示、图形渲染(如屏幕绘制),每个像素的RGBA值连续存储,可直接兼容显示设备。
RGBA为显示优化,直接支持像素渲染和透明通道。
OES与YUV的关系
OES纹理(GL_TEXTURE_EXTERNAL_OES)是OpenGL ES的一种扩展纹理类型,主要用于直接操作外部设备(如摄像头、视频解码器)的纹理数据。它与YUV的关系如下:
- 视频解码后的YUV数据: 移动端视频解码器(如Android的MediaCodec)输出的YUV帧数据,通常通过OES纹理直接传递给GPU,避免CPU到GPU的数据拷贝。
使用OES纹理需要修改片段着色器,在着色器脚本的头部增加扩展纹理的声明:
#extension GL_OES_EGL_image_external : require
并且纹理采样器不再使用sample2D,需要换成samplerExternalOES作为纹理采样器。