第一章,使用SurfaceTexture作为Camera输出
在Android系统中,使用GPU对摄像头画面进行高效可控的渲染,几乎是必须的。说到GPU就不得不提OpenGL,一组GPU暴露给应用层使用的接口。
- Tip:OpenGL是一组基于状态的系统,在这里没有对象,只有一系列的状态。包括申请的Texture、FBO和PBO都是以状态的形式存在的。当我们向系统申请一个Texture,系统不会直接给你返回一个Texture对象,而是一个编号,FBO和PBO也是一样的。
CameraPreviewPresenter.png
UML类图
正式开始之前我们先看一下这个模块的脑图和类图,以便对结构有个大概的了解。
- CamerPreviewPresenter:序章介绍过了,一个全局控制器
- Parameter:很重要的一个data类,包含了Camera、Encoder和Muxer初始化的一系列参数,再这里只用到Camera部分,也就是fps、previewWidth和previewHeight。
- CameraWrapper:一个Camera的包装,对外暴露了SurfaceTexture.OnFrameAvailableListener接口,以及EGL,SurfaceTexture环境
- CamerTextureWraper:EGL和SurfaceTexture的封装,其中textureId是OpenGL的纹理id,前面提到OpenGL是一个基于状态的系统,对SurfaceTexture的一系列处理都得通过textureId
首先,CameraPreviewPresenter需要实现SurfaceTexture.OnFrameAvailableListener接口,并且持有一个Parameter和一个CameraWrapper。cameraWrapper 会在init中初始化,parameter则是在CameraPreviewPresenter的调用处传进来。
class CameraPreviewPresenter(var parameter: Parameter,
private var cameraWrapper: CameraWrapper? = null)
: SurfaceTexture.OnFrameAvailableListener{
init {
cameraWrapper = CameraWrapper.open(parameter, this)
}
}
接下来在CameraWrapper里面,我们同样看到了Parameter,这个类会贯穿整个结构层级。onFrameAvailableListener也是由外部调用者赋值进来的,也就是CameraPreviewPresenter。
由于Camera的初始化是一个耗时任务,所以需要在线程中初始化,这里使用了一个HandlerThread。熟悉HandlerThread的人应该知道,HandlerThread会和一个Handler关联起来,通过Handler给Thread发送消息,从而实现子线程中的消息消费,具体的效果就是可以让线程以规定的顺序间歇性的处理我们的任务,而无须关心线程的等待问题。
class CameraWrapper(private var parameter: Parameter,
private var onFrameAvailableListener: SurfaceTexture.OnFrameAvailableListener,
var textureWrapper: TextureWrapper = CameraTextureWrapper()) {
private var mHandlerThread = HandlerThread("Renderer_Thread")
private var mHandler: Handler? = null
private var mCamera: Camera? = null
private var mCameras = 0
private var mCameraIndex = Camera.CameraInfo.CAMERA_FACING_BACK
}
- 在CameraWrapper初始化时获取摄像头数量,并初始化开启HandlerThread线程,之后向HandlerThread发送准备消息,在子线程中准备Camera的初始化。
init {
mCameras = CameraHelper.getNumberOfCameras()
initThread()
mHandler?.removeMessages(PREPARE)
mHandler?.sendEmptyMessage(PREPARE)
}
- Handler比较简单,只包含了一个Camera初始化的状态。代码就比较长了,在prepare()中,主要任务就是根据Parameter中的cameraIndex参数来打开前置或者后置摄像头,然后确定Camera的PreviewSize(预览分辨率)、ColorFormat(颜色格式)、FocusMode(对焦模式)、Fps(预览帧率)以及一些情景模式等。
private fun initThread() {
mHandlerThread.start()
mHandler = object : Handler(mHandlerThread.looper) {
override fun handleMessage(msg: Message) {
when (msg.what) {
PREPARE -> {
prepare()
}
}
}
}
}
private fun prepare() {
if (0 == mCameras) {
debug_e("Unavailable camera")
return
}
//如果没有前置摄像头,则强制使用后置摄像头
if (parameter.cameraIndex == Camera.CameraInfo.CAMERA_FACING_FRONT && mCameras < 2)
parameter.cameraIndex = Camera.CameraInfo.CAMERA_FACING_BACK
mCameraIndex = parameter.cameraIndex
val time = System.currentTimeMillis()
mCamera = openCamera(mCameraIndex)
debug_e("open time: ${System.currentTimeMillis() - time}")
if (null == mCamera) return
val cameraParam = mCamera!!.parameters
CameraHelper.setPreviewSize(cameraParam, parameter)
CameraHelper.setColorFormat(cameraParam, parameter)
CameraHelper.setFocusMode(cameraParam, parameter)
CameraHelper.setFps(cameraParam, parameter)
CameraHelper.setAutoExposureLock(cameraParam, false)
CameraHelper.setSceneMode(cameraParam, Camera.Parameters.SCENE_MODE_AUTO)
CameraHelper.setFlashMode(cameraParam, Camera.Parameters.FLASH_MODE_OFF)
CameraHelper.setAntibanding(cameraParam, Camera.