什么是CameraX?
CameraX是一个基于camera2的加强库,具有生命周期感知能力,有很多的自感知能力,比如我们不需要处理拍照旋转,它向后兼容至21.
有没有必要升级到CameraX?
现在,你只需要两行代码就能实现与预安装的相机相同的体验和功能(what)
有生命周期感知能力
更简单的使用方式
自动解决设备的兼容性问题,减少代码量,比如自动确定可使用的最佳分辨率。包括其他宽高比、屏幕方向、旋转角度、预览大小,这些都交给CameraX
反正有意思的东西我就必须要学。。
我的计划大概是分为
- 基础预览、拍照
- 使用自带的录制视频功能
- 获取预览的流自处理,如编码为其他格式推流
- 使用CameraX Extensions提供的插件,测试人像,夜间、美颜模式等功能
- 其他,如生命周期感知能力,自动分辨率等。
预览与拍照(测试机Android 11)
CameraX是一个jatpack支持库,使用它我们需要导入依赖。
// CameraX core library using the camera2 implementation
def camerax_version = "1.0.0"
// The following line is optional, as the core library is included indirectly by camera-camera2
implementation("androidx.camera:camera-core:${camerax_version}")
implementation("androidx.camera:camera-camera2:${camerax_version}")
// If you want to additionally use the CameraX Lifecycle library
implementation("androidx.camera:camera-lifecycle:${camerax_version}")
// If you want to additionally use the CameraX View class
implementation("androidx.camera:camera-view:1.0.0-alpha25")
// If you want to additionally use the CameraX Extensions library
implementation("androidx.camera:camera-extensions:1.0.0-alpha25")
记得处理CAMERA权限。
<Button
android:id="@+id/takeP"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拍照" />
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:layout_width="match_parent"
android:id="@+id/imageView"
android:layout_height="0dp"
android:layout_weight="1" />
我们准备了三个按钮,拍照、预览、显示拍照后图片,大概这样:
获取ProcessCameraProvider,它的作用是将相机的生命周期绑定到应用程序,它是一个单例类。
private fun initCamera() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
//请求 CameraProvider 后,请验证它能否在视图创建后成功初始化。以下代码展示了如何执行此操作:
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
}
获取camera
fun bindPreview(cameraProvider: ProcessCameraProvider) {
var preview: Preview = Preview.Builder()
.setTargetResolution(Size(1280, 720)) //设置分辨率
.build()
// 拍照
imageCapture = ImageCapture.Builder()
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY) //优先考虑图片质量,速度略低
// .setTargetRotation(Surface.ROTATION_90)
.build()
var cameraSelector: CameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK) //后置
.build()
//提供previewView预览控件
preview.setSurfaceProvider(previewView.surfaceProvider)
var camera = cameraProvider.bindToLifecycle(
this as LifecycleOwner,
cameraSelector,
imageCapture,
preview
)
}
现在运行,你将看到可以正常显示预览界面,如果没有显示,请检查是否处理危险权限CAMERA。
添加拍照的点击事件
private fun takePicture() {
val file = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!.path, "1.jpg")
Log.d(TAG, "initView: 拍照")
val options = ImageCapture.OutputFileOptions.Builder(file).build()
imageCapture?.takePicture(options, mainExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onError(error: ImageCaptureException) {
// insert your code here.
Log.d(TAG, "onError: " + error.message)
}
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
// insert your code here.
Log.d(TAG, "onImageSaved: ")
val savedUri = outputFileResults.savedUri ?: Uri.fromFile(file)
imageView.setImageURI(null)
imageView.setImageURI(savedUri)
}
})
}
这里我使用了外部存储目录,保存在storage/emulated/0/android/data/packageName/下,如果你要保存在公共区域,可修改如下代码,或者你将直接处理图片数据,ImageCapture.OutputFileOptions.Builder的构造函数的参数,注意修改。
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "NEW_IMAGE");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions.Builder(
getContentResolver(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues).build();
现在点击按钮,拍照的图片将显示在ImageView上,我们没有处理旋转角度,预览角度,CameraX帮我们自动处理了这些。
下一篇我们使用CameraX自带的VideoCapture实现自带的录制视频功能。