近期,Google 的 Jetpack 组件又出了新的库:CameraX 。android
顾名思义:CameraX 就是用来进行 Camera 开发的官方库了,并且后续会有 Google 进行维护和升级。这对于广大 Camera 开发工程师和即将成为 Camera 的程序员来讲,真是个好消息~~~git
原文地址:glumes.com/post/androi…程序员
官方有给出一个示例的工程,我 fork 了以后,加入使用 OpenGL 黑白滤镜渲染的操做,具体地址以下:github
官方并无提到 CameraX 库具体如何进行 OpenGL 线程渲染的, 继续往下看,你会找到答案的~~~微信
关于 CameraX 更多的介绍,建议看看 Google I/O 大会上的视频记录,比看文档能了解更多内容~~~app
在视频中提到,目前有不少应用都开始接入了 CameraX,好比 Camera360、Tik Tok 等。post
关于 Camera 的开发,以前也有写过相关的文章🤔性能
对于一个简单能用的 Camera 应用(Demo 级别)来讲,关注两个方面就行了:预览和拍摄。
而预览和拍摄的图像都受到分辨率、方向的影响。Camera 最必备的功能就是能针对预览和拍摄提供两套分辨率,所以就得区分场景去设置。
对于拍摄还好说一点,要得到最好的图像质量,就选择同比例中分辨率最大的吧。
而预览的图像最终要呈现到 Android 的 Surface 上,所以选择分辨率的时候要考虑 Surface 的宽高比例,不要出现比例不匹配致使图像拉伸的现象。
另外,若是要作美颜、滤镜类的应用,就要把 Camera 预览的图像放到 OpenGL 渲染的线程上去,而后由 OpenGL 去作图像相关的操做,也就没 Camera 什么事了。等到拍摄图片时,能够由 OpenGL 去获取图像内容,也能够由 Camera 得到图像内容,而后通过 OpenGL 作离屏处理~~~
至于 Camera 开发的其余功能,好比对焦、曝光、白平衡、HDR 等操做,不必定全部的 Camera 都可以支持,并且也能够在上面的基础上当作 Camera 的一个 feature 去拓展开发,并不算难事,这也是一个 Camera 开发工程师进阶所要掌握的内容~~
CameraX 目前的版本是 1.0.0-alpha01
,在使用时要添加以下的依赖:
// CameraX
def camerax_version = "1.0.0-alpha01"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
复制代码
CameraX 向后兼容到 Android 5.0(API Level 21),而且它是基于 Camera 2.0 的 API 进行封装的,解决了市面上绝大部分手机的兼容性问题~~~
相比 Camera 2.0 复杂的调用流程,CameraX 就简化不少,只关心咱们须要的内容就行了,不像前者得本身维护 CameraSession 会话等状态,而且 CameraX 和 Jetpack 主打的 Lifecycle 绑定在一块儿了,何时该打开相机,何时该释放相机,都交给 Lifecycle 生命周期去管理吧
上手 CameraX 主要关注三个方面:
不论是 预览 仍是 图像分析、图像拍摄,CameraX 都是经过一个建造者模式来构建参数 Config 类,再由 Config 类建立预览、分析器、拍摄的类,并在绑定生命周期时将它们传过去。
// // Apply declared configs to CameraX using the same lifecycle owner
CameraX.bindToLifecycle(
lifecycleOwner: this, preview, imageCapture, imageAnalyzer)
复制代码
既能够绑定 Activity 的 Lifecycle,也能够绑定 Fragment 的。
当须要解除绑定时:
// Unbinds all use cases from the lifecycle and removes them from CameraX.
CameraX.unbindAll()
复制代码
关于预览的参数配置,若是你有看过以前的文章:Android 相机开发中的尺寸和方向问题 想必就会很了解了。
提供咱们的目标参数,由 CameraX 去判断当前 Camera 是否支持,并选择最符合的。
fun buildPreviewUseCase(): Preview {
val previewConfig = PreviewConfig.Builder()
// 宽高比
.setTargetAspectRatio(aspectRatio)
// 旋转
.setTargetRotation(rotation)
// 分辨率
.setTargetResolution(resolution)
// 先后摄像头
.setLensFacing(lensFacing)
.build()
// 建立 Preview 对象
val preview = Preview(previewConfig)
// 设置监听
preview.setOnPreviewOutputUpdateListener { previewOutput ->
// PreviewOutput 会返回一个 SurfaceTexture
cameraTextureView.surfaceTexture = previewOutput.surfaceTexture
}
return preview
}
复制代码
经过建造者模式建立 Preview
对象,而且必定要给 Preview 对象设置 OnPreviewOutputUpdateListener
接口回调。
相机预览的图像流是经过 SurfaceTexture 来返回的,而在项目例子中,是经过把 TextureView 的 SurfaceTexture 替换成 CameraX 返回的 SurfaceTexture,这样实现了 TextureView 控件显示 Camera 预览内容。
另外,还须要考虑到设备的选择方向,当设备横屏变为竖屏了,TextureView 也要相应的作旋转。
preview.setOnPreviewOutputUpdateListener { previewOutput ->
cameraTextureView.surfaceTexture = previewOutput.surfaceTexture
// Compute the center of preview (TextureView)
val centerX = cameraTextureView.width.toFloat() / 2
val centerY = cameraTextureView.height.toFloat() / 2
// Correct preview output to account for display rotation
val rotationDegrees = when (cameraTextureView.display.rotation) {
Surface.ROTATION_0 -> 0
Surface.ROTATION_90 -> 90
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
else -> return@setOnPreviewOutputUpdateListener
}
val matrix = Matrix()
matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
// Finally, apply transformations to TextureView
cameraTextureView.setTransform(matrix)
}
复制代码
TextureView 旋转的设置一样在 OnPreviewOutputUpdateListener
接口中去完成。
在 bindToLifecycle
方法中,imageAnalyzer
参数并非必需的。
ImageAnalysis
能够帮助咱们作一些图像质量的分析,须要咱们去实现 ImageAnalysis.Analyzer
接口的 analyze
方法。
fun buildImageAnalysisUseCase(): ImageAnalysis {
// 分析器配置 Config 的建造者
val analysisConfig = ImageAnalysisConfig.Builder()
// 宽高比例
.setTargetAspectRatio(aspectRatio)
// 旋转
.setTargetRotation(rotation)
// 分辨率
.setTargetResolution(resolution)
// 图像渲染模式
.setImageReaderMode(readerMode)
// 图像队列深度
.setImageQueueDepth(queueDepth)
// 设置回调的线程
.setCallbackHandler(handler)
.build()
// 建立分析器 ImageAnalysis 对象
val analysis = ImageAnalysis(analysisConfig)
// setAnalyzer 传入实现了 analyze 接口的类
analysis.setAnalyzer { image, rotationDegrees ->
// 能够获得的一些图像信息,参见 ImageProxy 类相关方法
val rect = image.cropRect
val format = image.format
val width = image.width
val height = image.height
val planes = image.planes
}
return analysis
}
复制代码
在图像分析器的相关配置中,有个 ImageReaderMode
和 ImageQueueDepth
的设置。
ImageQueueDepth 会指定相机管线中图像的个数,提升 ImageQueueDepth 的数量会对相机的性能和内存的使用形成影响
其中,ImageReaderMode 有两种模式:
在图像分析的 analyze
方法中,能经过 ImageProxy 类拿到一些图像信息,并基于这些信息作分析。
拍摄一样有一个 Config 参数构建者类,并且设定的参数和预览相差不大,也是图像宽高比例、旋转方向、分辨率,除此以外还有闪光灯等配置项。
fun buildImageCaptureUseCase(): ImageCapture {
val captureConfig = ImageCaptureConfig.Builder()
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.setFlashMode(flashMode)
// 拍摄模式
.setCaptureMode(captureMode)
.build()
// 建立 ImageCapture 对象
val capture = ImageCapture(captureConfig)
cameraCaptureImageButton.setOnClickListener {
// Create temporary file
val fileName = System.currentTimeMillis().toString()
val fileFormat = ".jpg"
val imageFile = createTempFile(fileName, fileFormat)
// Store captured image in the temporary file
capture.takePicture(imageFile, object : ImageCapture.OnImageSavedListener {
override fun onImageSaved(file: File) {
// You may display the image for example using its path file.absolutePath
}
override fun onError(useCaseError: ImageCapture.UseCaseError, message: String, cause: Throwable?) {
// Display error message
}
})
}
return capture
}
复制代码
在图像拍摄的相关配置中,也有个 CaptureMode
的设置。
它有两种选项:
以上是关于 CameraX 的简单应用方面的内容,更关心的是如何用 CameraX 去作 OpenGL 渲染实现美颜。滤镜等效果。
还记得在图像预览 Preview 的 setOnPreviewOutputUpdateListener 方法中,会返回一个 SurfaceTexture
,相机的图像流就是经过它返回的。
那么要实现 OpenGL 线程的渲染,首先就要基于 EGL 去建立 OpenGL 绘制环境,而后利用 SurfaceTexture 的 attachToGLContext
方法,将 SurfaceTexture 添加到 OpenGL 线程去。
attachToGLContext 的参数是一个纹理 ID ,这个纹理就必须是 OES 类型的纹理。
而后再把这纹理 ID 绘制到 OpenGL 对应的 Surface 上,这能够当作是两个不一样的线程在容许,一个 Camera 预览线程,一个 OpenGL 绘制线程。
若是你不是很理解的话,建议仍是看看上面提供的代码地址:
也能够关注个人微信公众号 【纸上浅谈】,里面有一些关于 OpenGL 学习和实践的文章~~~
若是你看了 Google I/O 大会的视频,那确定了解 CameraX 的拓展属性。
在视频中提到 Google 也正在和华为、三星、LG、摩托摩拉等厂商进行合做,为了得到厂商系统相机的一些能力,好比 HDR 等。
不过考虑到目前的形势,可能和华为的合做难以继续下去了吧...
但仍是期待 CameraX 能给带来更多的新特性吧~~~
文章推荐
以为文章不错,欢迎关注和转发微信公众号:【纸上浅谈】,得到最新文章推送~~~