因为工作需要需要用到相机API,就去瞅了瞅。Camera基本上已经都被弃用,写完满屏幕的灰色横线。就琢磨着用Camera2来实现该有的功能。
这是官方的camera2 demo 基本上该有的功能,都在demo中实现
https://github.com/googlearchive/android-Camera2Basic
首先开发过自定义相机的都知道,如果不特殊处理,会出现拉伸的情况,这是因为SurfaceView的宽高比,和相机输出的图像宽高比不同,所以会出现图像拉伸的情况。
根据官方给出的处理方案,就是自定义一个SurfaceVIew根据相机输出的图像宽高比,来制定自身的宽高,代码如下:
private var aspectRatio = 0f
fun setAspectRatio(width: Int, height: Int) {
require(width > 0 && height > 0) {
"Size cannot be negative" }
aspectRatio = width.toFloat() / height.toFloat()
holder.setFixedSize(width, height)
requestLayout()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
if (aspectRatio == 0f) {
setMeasuredDimension(width, height)
} else {
val newWidth: Int
val newHeight: Int
val actualRatio = if (width > height) aspectRatio else 1f / aspectRatio
if (width < height * actualRatio) {
newHeight = height
newWidth = (height * actualRatio).roundToInt()
} else {
newWidth = width
newHeight = (width / actualRatio).roundToInt()
}
setMeasuredDimension(newWidth, newHeight)
}
}
在surface监听中,拿到相机的previewSize,调用setAspectRatio方法即可
代码如下
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceDestroyed(holder: SurfaceHolder) = Unit
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) = Unit
override fun surfaceCreated(holder: SurfaceHolder) {
val previewSize = getPreviewOutputSize(
surfaceView.display, characteristics, SurfaceHolder::class.java
)
surfaceView.setAspectRatio(previewSize.width, previewSize.height)
view.post {
initializeCamera() }
}
})
因为Camera2中没有像Camera中一样有一个setPreviewCallback方法,可以对每一帧进行处理。但是Camera2中有ImageReader对象,可以进行我们需要的处理
在上述代码中 initializeCamera中如下代码
camera = openCamera(cameraManager, FONT_CAMERA, cameraHandler)
val size = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
)!!
.getOutputSizes(ImageFormat.YUV_420_888).maxBy {
it.height * it.width }!!
currentSize = size
imageReader = ImageReader.newInstance(
size.width, size.height, ImageFormat.YUV_420_888, IMAGE_BUFFER_SIZE
) imageReader.setOnImageAvailableListener(mOnImageAvailableListener, null)
val targets = listOf(surfaeView.holder.surface, imageReader.surface)
session = createCaptureSession(camera, targets, cameraHandler)
val captureRequest = camera.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW
).apply {
addTarget(viewFinder.holder.surface)
addTarget(imageReader.surface)
}
session.setRepeatingRequest(captureRequest.build(), null, cameraHandler)
其中具体openCamera或characteristics如何获取等基本方法信息,很简单就不放出来了。
然后关键是Imagereader设置的mOnImageAvailableListener
咱们可以自定义一个监听 代码如下
private val mOnImageAvailableListener: OnImageAvailableListener =
object : OnImageAvailableListener {
override fun onImageAvailable(reader: ImageReader) {
val image = reader.acquireLatestImage() ?: return
//子线程中进行处理
imageReaderHandler.post {
//todo 此处可以对每一帧的image进行处理
//不要忘记关闭close
image.close()
}
}
}
其实不怎么难,一开始不太愿意看官方的demo。但是看了其实一目了然。Camera2跟Camera还是差了很多的。难吧,其实也还好。但是也不容易。仔细看看demo就能理解了。
希望有帮助吧