android camera2 简单介绍

从 Android 5.0 开始,Google 引入了一套全新的相机框架 Camera2 api,它相比较 Camera1 有以下优势:

1、可以获取更多的帧(预览/拍照)信息以及手动控制每一帧的参数
2、对Camera的控制更加完全(比如支持调整focus distance, 剪裁预览/拍照图片)
3、支持更多图片格式(yuv/raw)以及高速连拍
4、…

现在是 2022 年了,可以说 99% 以上的安卓手机都在 5.0 系统,因此完全不用担心兼容问题。本文只是记录在自定义 camera2 实现连拍过程的坑,具体有关 camera2 的介绍可以参考 Google 的文档。

https://developer.android.com/training/camera2

camera2 实现连拍并保存

理论上 camera2 连拍可以达到 30fps,笔者需要的速度是 20s 拍 100 张并保存,实测无压力。主要是使用 CountDownTimer 定时 build CaptureRequest,然后在 CaptureResult 中使用 RxJava 线程调度,即在 IO 线程保存照片,在 UI 线程更新。

遇到的一些问题

预览正常,保存的照片旋转了 90 度

解决办法有两个,第一个就在在 CaptureRequest 中构建 bitmap,然后强行使这个 bitmap 旋转到原来的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) {
Matrix m = new Matrix();
m.setRotate(orientationDegree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
try {
return Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
} catch (OutOfMemoryError ex) {
ex.fillInStackTrace();
}
return bm;
}

Bitmap bitmapImage = BitmapFactory.decodeByteArray(data, 0, data.length, null);
// 这个 90 度太唐突了,但是能解决问题
Bitmap newBitmap = adjustPhotoRotation(bitmapImage, 90);

第二个是 requestBuilder 设置 JPEG_ORIENTATION,这种才是解决根本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public int getDisplayRotation(Activity activity) {
if (activity == null) {
return 0;
}

int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
switch (rotation) {
case Surface.ROTATION_0:
return 90;
case Surface.ROTATION_90:
return 0;
case Surface.ROTATION_180:
return 270;
case Surface.ROTATION_270:
return 180;
}
return 0;
}

// 构建 requestBuilder 的时候设置
mCaptureReqBuilder.set(CaptureRequest.JPEG_ORIENTATION, getDisplayRotation(activity));

CaptureRequest$Builder NPE

完整报错信息是:

1
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.hardware.camera2.CaptureRequest$Builder android.hardware.camera2.CameraDevice.createCaptureRequest(int)' on a null object reference

这是因为,相机驱动相关初始化后要延迟 1s 左右才能 buildCaptureRequest,post 一个延时 1s 的 runnable 即可

部分机型上界面拉伸,保存正常

试了很多,暂无解,待填