1. Vantagens do CameraX
CameraX é uma biblioteca de suporte Jetpack projetada para ajudá-lo a simplificar o desenvolvimento de aplicativos de câmera. Ele fornece uma superfície de API consistente e fácil de usar, adequada para a maioria dos dispositivos Android, e é compatível com versões anteriores do Android 5.0 (API de nível 21).
Embora use a funcionalidade da câmera2, ele usa uma abordagem mais simples e baseada em casos de uso que tem consciência do ciclo de vida. Ele também resolve problemas de compatibilidade do dispositivo, então você não precisa adicionar código específico do dispositivo à base de código. Esses recursos reduzem a quantidade de código que precisa ser escrito ao adicionar funções de câmera ao aplicativo.
2. Adicionar dependências
//主要工具类
implementation 'androidx.camera:camera-core:1.0.0-alpha10'
//主要的外部接口
implementation 'androidx.camera:camera-camera2:1.0.0-alpha10'
//管理相机的生命周期
implementation 'androidx.camera:camera-lifecycle:1.0.0-alpha10'
//预览图层
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
//可选插件,通过该插件,您可以在支持的设备上添加效果。这些效果包括人像、HDR、夜间模式和美颜。
implementation 'androidx.camera:camera-extensions:1.0.0-alpha10'
A interface de cada versão pode ser ligeiramente diferente, mas as funções são basicamente as mesmas. Além disso, você precisa se inscrever para obter permissões de câmera:
<uses-permission android:name="android.permission.CAMERA" />
Se quiser tirar fotos e salvar, você também precisa de permissões de armazenamento:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
3. Ligue a câmera
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private PreviewView previewView;
private ImageCapture imageCapture;
private ProcessCameraProvider cameraProvider;
cameraProviderFuture = ProcessCameraProvider.getInstance(activity);
cameraProviderFuture.addListener(() -> {
try {
cameraProvider = cameraProviderFuture.get();
//相机ID CameraSelector.LENS_FACING_FRONT前置;CameraSelector.LENS_FACING_BACK 后置
bindPreview(cameraProvider, cameraId);
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "error:" + e);
}
}, ContextCompat.getMainExecutor(activity));
private void bindPreview(@NonNull ProcessCameraProvider cameraProvider, int lensFacing) {
Preview preview = new Preview.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9) //设置宽高比
.setTargetRotation(Surface.ROTATION_0) // 设置旋转角度
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(lensFacing)
.build();
/**
图像分析可以分为两种模式:阻塞模式和非阻塞模式。通过使用 STRATEGY_BLOCK_PRODUCER 调用
setBackpressureStrategy() 以启用阻塞模式。
在此模式下,执行程序会按顺序从相机接收帧;这意味着,如果 analyze() 方法所用的时间超过单帧在当前帧
速率下的延迟时间,帧便可能不再是最新的帧,因为新帧已被阻止进入流水线,直到该方法返回为止。
通过使用 STRATEGY_KEEP_ONLY_LATEST 调用 setBackpressureStrategy() 以启用非阻塞模式。在此模式
下,执行程序会从相机接收调用 analyze() 方法时的最后一个可用帧。如果此方法所用的时间超过单帧在当前
帧速率下的延迟时间, 可能会跳过某些帧,以便在下一次 analyze() 接收数据时,它会获取相机流水线中的
最后一个可用帧。从 analyze() 返回前,请通过调用 image.close() 关闭图片引用,以避免阻塞其他图像的
生成(导致预览停顿)并避免可能出现的图像丢失。 此方法必须完成分析或创建副本,而不是将图像引用传递
到分析方法以外。*/
//设置宽高比
// 设置旋转角度
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9) //设置宽高比
.setTargetRotation(Surface.ROTATION_0) // 设置旋转角度
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(executors, imageProxy -> {
//预览过程中,如果需要录制视频,则在这里获取。
//将图片转换成yuv(格式YUV_420_888)数据,再进行编码。
//如果处理数据太慢,导致造成阻塞,可以设置监听器,把数据发送到其他线程进行处理
ImageProxy.PlaneProxy[] planes = imageProxy.getPlanes();
byte[] mYuvBytes = new byte[imageProxy.getWidth() * imageProxy.getHeight() * 3 / 2];
// YUV_420_888
ByteBuffer yBuffer = planes[0].getBuffer();
int yLen = imageProxy.getWidth() * imageProxy.getHeight();
yBuffer.get(mYuvBytes, 0, yLen);
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
int pixelStride = planes[1].getPixelStride(); // pixelStride = 2
for (int i = 0; i <= uBuffer.remaining(); i += pixelStride) {
mYuvBytes[yLen++] = uBuffer.get(i);
mYuvBytes[yLen++] = vBuffer.get(i);
}
imageProxy.close();
});
//拍摄图像的配置
imageCapture =
new ImageCapture.Builder()
//CAPTURE_MODE_MAXIMIZE_QUALITY 拍摄高质量图片,图像质量优先于延迟,可能需要更长的时间
//CAPTURE_MODE_MINIMIZE_LATENCY
.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
.setTargetAspectRatio(AspectRatio.RATIO_16_9) //设置宽高比
.setTargetRotation(Surface.ROTATION_0) // 设置旋转角度
.build();
cameraProvider.unbindAll();
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) activity, cameraSelector, imageCapture, preview, imageAnalysis);
//这里previewView是预览图层,需要在布局中实现,然后在这里使用
preview.setSurfaceProvider(previewView.createSurfaceProvider(camera.getCameraInfo()));
}
Uso de PreviewView
<androidx.camera.view.PreviewView
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
4. Tire fotos
Existem duas maneiras de tirar fotos de retorno de chamada:
1. Chame de volta a imagem, se você precisar salvar, você pode transferir para Bitmap e salvar
2. Configure diretamente o caminho de salvamento e, em seguida, receba o retorno de chamada do sucesso e do fracasso do foto.
public void takePicture() {
imageCapture.takePicture(executors, new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(@NonNull ImageProxy imageProxy) {
ImageProxy.PlaneProxy[] planes = imageProxy.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
buffer.position(0);
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
imageProxy.close();
super.onCaptureSuccess(imageProxy);
}
});
/*ImageCapture.Metadata metadata = new ImageCapture.Metadata();
if (mCurrentCameraId == CameraSelector.LENS_FACING_FRONT) {
metadata.setReversedHorizontal(true);
} else {
metadata.setReversedHorizontal(false);
}
File file = new File(Environment.getExternalStorageState(), new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS",
Locale.US).format(System.currentTimeMillis()) + ".jpg");
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.
Builder(file).setMetadata(metadata).build();
imageCapture.takePicture(outputFileOptions, executors, new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
Log.e(TAG, "outputFileResults:" + outputFileResults.getSavedUri());
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Log.e(TAG, "exception:" + exception.toString());
}
});*/
}
Os alunos que precisarem da extensão do fornecedor podem conferir no site oficial.
PS: A descrição oficial do CameraX
https://developer.android.google.cn/training/camerax