CameraX简单使用

Posted by alonealice on 2020-05-20

CameraX实际上还是用的Camera2的代码,但是它对调用API进行了很好的封装,使用起来对比直接Camera2更加的方便。同时使用需要绑定lifecircle,能够自动管理生命周期。

添加依赖

1
2
3
4
implementation "androidx.camera:camera-core:1.0.0-rc01"
implementation "androidx.camera:camera-camera2:1.0.0-rc01"
implementation 'androidx.camera:camera-view:1.0.0-alpha20'
implementation "androidx.camera:camera-lifecycle:1.0.0-rc01"

申请权限

1
<uses-permission android:name="android.permission.CAMERA" />
1
2
3
4
int checkCallPhonePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 222);
}

预览

1
2
3
4
<androidx.camera.view.PreviewView
android:id="@+id/tv_camera"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

cameraX显示布局需要PreviewView,直接在xml中添加。

启动相机,需要先获取到ProcessCameraProvider:

1
2
3
4
5
6
previewView.post(new Runnable() {
@Override
public void run() {
setupCamera();
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void setupCamera() {
ListenableFuture<ProcessCameraProvider> instance = ProcessCameraProvider.getInstance(this);
instance.addListener(new Runnable() {
@Override
public void run() {
try {
cameraProvider = instance.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (cameraProvider != null) {
startCamera();
}
}
}, ContextCompat.getMainExecutor(this));
}

添加预览的参数preview:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private void startCamera() {
//预览
Preview preview = new Preview.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setTargetRotation(Surface.ROTATION_90)
.build();
//拍照
ImageCapture imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setTargetRotation(Surface.ROTATION_90)
.build();
//图像数据
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().setTargetAspectRatio(AspectRatio.RATIO_16_9).setTargetRotation(Surface.ROTATION_90).build();
imageAnalysis.setAnalyzer(cameraExecutor, new ImageAnalysis.Analyzer() {
@Override
public void analyze(@NonNull ImageProxy image) {
Log.e("画面", image.getWidth() + "**" + image.getHeight());
}
});

//选择后置摄像头
CameraSelector selector = new C ameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
//绑定参数
cameraProvider.unbindAll();
cameraProvider.bindToLifecycle(this, selector, preview, imageCapture, imageAnalysis);

//绑定previewView 并开始预览
preview.setSurfaceProvider(previewView.getSurfaceProvider());
}

bindToLifecycle方法中的preview、imageCapture和imageAnalysis并不是每次都需要,如果只是预览的话就只传preview即可。

图像分析

ImageAnalysis 可以帮助我们做一些图像质量的分析,需要我们去实现 ImageAnalysis.Analyzer 接口的 analyze 方法。

拍照

拍照需要在预览的基础上,调用ImageCapture拍照,同时需要创建OutputFileOptions用以存储文件信息。在onImageSaved方法回调时,照片会自动存储到对应的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void takePicture(View v) {
imageCapture.setFlashMode(ImageCapture.FLASH_MODE_AUTO);
File file = new File(getCacheDir()+"/"+System.currentTimeMillis()+".png");
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
imageCapture.takePicture(outputFileOptions, cameraExecutor, new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
if (outputFileResults.getSavedUri() != null) {
//保存成功
}
}
@Override
public void onError(@NonNull ImageCaptureException exception) {

}
});
}
录像

录像是需要创建VideoCapture,同时在bind方法中不能和imageAnalysis一起使用。

1
2
3
4
5
6
7
8
9
10
11
videoCapture = new VideoCapture.Builder()
.setTargetRotation(Surface.ROTATION_0)
//设置宽高比
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setAudioBitRate(44100)
.setAudioRecordSource(MediaRecorder.AudioSource.MIC)
//视频帧率 越高视频体积越大
.setVideoFrameRate(25)
//bit率 越大视频体积越大
.setBitRate(3 * 1024 * 1024)
.build();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if (start) {
videoCapture.stopRecording();
start = false;
} else {
File file = new File(Environment.getExternalStorageDirectory() + "/" + System.currentTimeMillis() + ".mp4");
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
VideoCapture.OutputFileOptions outputFileOptions = new VideoCapture.OutputFileOptions.Builder(file).build();
videoCapture.startRecording(outputFileOptions, cameraExecutor, new VideoCapture.OnVideoSavedCallback() {
@Override
public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
Log.e("画面", "视频保存成功");
}

@Override
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {

}
});
start = true;
}

CameraView

如果觉得上面的代码还是比较多,官方提供了一个极简拍摄的组件CameraView。

在xml中添加依赖:

1
2
3
4
5
<androidx.camera.view.CameraView
android:id="@+id/view_finder"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

同时通过绑定开始预览,并调用对应的takePicture和startRecording,完成拍照和摄影,这两个方法的参数与上面相同。

1
2
3
4
cameraView = findViewById(R.id.view_finder);
cameraView.bindToLifecycle(this);
cameraView.takePicture(...);
cameraView.startRecording(...);

CameraX官方还未出正式版本,这部分的代码各个版本改动较大,建议直接参考官方demo:https://github.com/android/camera-samples/tree/main/CameraXBasic