前言
近期博主准备编写一个基于Android Camera2的图像采集并编码为h.264的应用,准备分为三个阶段来完成,第一阶段实现Camera2的摄像机预览,第二阶段完成基于MediaCodec H.264编码,第三阶段完成基于MediaCodec H.264解码,针对不同阶段将输出对应的实现博文,因为笔者是第一次接触这块因此如果编写过程中有什么错误的话,欢迎大家指正,对于技术方面感兴趣的也欢迎私信或者留言,一起讨论共同进步。
Camera2 API简介
Android Camera2 API 是从 Android 5.0(Lollipop)开始引入的,用以取代旧的 Camera API。Camera2 提供了更强大和灵活的相机控制能力,允许开发者实现更多的相机功能,如手动对焦、手动曝光、原生 RAW 图像捕获等。
在开始使用Camera2之前,我们先来了解下Camera2使用过程中需要用到的相关类:
-
CameraManager:相机管理器,安卓系统针对不同的功能模块会创建不同的Manager,所以相机也不例外,一般主要用来open相机或者查询相机列表以及对应相机的参数等。
-
CameraDevice:代表一个物理相机设备,可以打开、配置和关闭相机设备等。
-
CameraCaptureSession:相机捕获会话,用于发送捕获请求和接收捕获结果,可以预览、拍照、录像等。
-
CameraCharacteristics:提供了相机设备的静态信息,如支持的参数、分辨率、对焦模式等。
整个执行流程大致上如下:
flowchart TB
获取CameraManager对象 --> 通过CameraManager打开指定ID的相机 --> 打开后拿到到CameraDevice对象 --> 通过CameraDevice创建CameraCaptureSession对象 --> 通过CameraCaptureSession开启预览
现在已经简单的知晓了相关类的用途和流程,那么我们接下来开始实现Camera2的预览功能。
编码实现
为了方便后续对这块的复用,因此这里我们创建一个名为CameraWrapper的类,用以对Camera相关功能的封装,首先添加如下代码:
class CameraWrapper(private var context:Context) {
private val TAG = "CameraWrapper"
private var cameraManager: CameraManager
private var cameraDevice: CameraDevice? = null
private var characteristics: CameraCharacteristics? = null
private var session: CameraCaptureSession? = null
//当前设备的相机列表
private var cameraIds:Array<String>
//默认启用的cameraId
private var cameraId:String = "0"//默认前置
private var previewView:SurfaceView? = null
private var encoderSurface: Surface? = null
private var cameraThread:HandlerThread = HandlerThread("CameraThread")
private var cameraHandler: Handler
private var previewSize:Size? = Size(1280,720)
init {
cameraThread.start()
cameraHandler = Handler(cameraThread.looper)
cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
cameraIds = getCameraIds()
//看下id和前后置的对应关系
for(id in cameraIds){
Log.d(TAG,"id : "+id+"---"+getCameraOrientationString(id))
}
useCamera(cameraId)
}
这里我们定义了所有需要用到的成员变量,这里我挑几个说明下,其他的就不过多说明了,看名字应该都能理解。
通过previewView应该不难看出我们使用的预览View为SurfaceView。
encoderSurface这个预留给后续摄像机编码H.264时使用,本篇文章暂未用到。
cameraThread和cameraHandler这里可以不用过多关注,创建的意义主要是传参给Camera,使用是在Camera内。
previewSize可以理解为预览的画面分辨率,默认设置的是720P。
该类类创建时,获取到了设备支持的摄像机列表并打印了前后置的对应关系,这里主要是调试观察的。getCameraIds()和 useCamera(cameraId)我们还没实现,但是先不急,让我们先加两个权限相关的函数。
//添加权限请求和检查接口,方便使用
companion object{
fun requestCameraPermissions(activity: Activity){
ActivityCompat.requestPermissions(
activity,
arrayOf(
Manifest.permission.CAMERA,
),
998
)
}
fun checkCameraPermission(context: Context):Boolean{
return ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
}
}
这两个函数作用就不解释了,核心作用就是为了方便使用CameraWrapper时对相关权限进行检查和请求。
fun useCamera(id:String){
cameraId = id
try {
characteristics = cameraManager.getCameraCharacteristics(cameraId