因為作業需要需要用到相機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就能理解了,
希望有幫助吧
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/76465.html
標籤:其他
上一篇:Flutter 工程目錄結構
