I need to take as many frames as possible from the preview of the camera. I'm doing this to start the camera using CameraX:
private fun startCamera() {
// Create configuration object for the viewfinder use case
val metrics = DisplayMetrics().also { view_finder.display.getRealMetrics(it) }
// define the screen size
val screenSize = Size(metrics.widthPixels, metrics.heightPixels)
val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
val previewConfig = PreviewConfig.Builder()
.setLensFacing(CameraX.LensFacing.BACK) // defaults to Back camera
.setTargetAspectRatio(screenAspectRatio)
.setTargetResolution(screenSize)
.build()
// Build the viewfinder use case
val preview = Preview(previewConfig)
// Every time the viewfinder is updated, recompute layout
preview.setOnPreviewOutputUpdateListener {
// To update the SurfaceTexture, we have to remove it and re-add it
val parent = view_finder.parent as ViewGroup
parent.removeView(view_finder)
parent.addView(view_finder, 0)
view_finder.surfaceTexture = it.surfaceTexture
updateTransform()
}
val analyzerConfig = ImageAnalysisConfig.Builder().apply {
// Use a worker thread for image analysis to prevent glitches
val analyzerThread = HandlerThread("AnalysisThread").apply {
start()
}
setLensFacing(CameraX.LensFacing.BACK) // defaults to Back camera
setTargetAspectRatio(screenAspectRatio)
setMaxResolution(Size(600, 320))
setCallbackHandler(Handler(analyzerThread.looper))
setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
}.build()
val analyzerUseCase = ImageAnalysis(analyzerConfig).apply {
analyzer = context?.let { FrameCapturer(it) }
}
//====================== Image Analysis Config code End==========================
CameraX.bindToLifecycle(this, preview, analyzerUseCase)
}
My FrameCapturer class is:
class FrameCapturer(context: Context): ImageAnalysis.Analyzer {
private var mListener = context as FrameCapturerListener
override fun analyze(image: ImageProxy?, rotationDegrees: Int) {
val buffer = image?.planes?.get(0)?.buffer
// Extract image data from callback object
val data = buffer?.toByteArray()
// Convert the data into an array of pixel values
//val pixels = data?.map { it.toInt() and 0xFF }
mListener.updateFps()
}
private fun ByteBuffer.toByteArray(): ByteArray {
rewind() // Rewind the buffer to zero
val data = ByteArray(remaining())
get(data) // Copy the buffer into a byte array
return data // Return the byte array
}
interface FrameCapturerListener {
fun updateFps()
}
And my updateFps function is:
fun updateFps() {
fps += 1
if (!isCountDownStarted) {
var timer = object : CountDownTimer(1000, 1000) {
override fun onTick(millisUntilFinished: Long) {
}
override fun onFinish() {
Log.d("CameraFragment", fps.toString())
fps = 0
isCountDownStarted = false
}
}.start()
isCountDownStarted = true
}
}
I'm around 16-22 fps, even if I don't convert the image to an array of byte in the FrameCapturer class. So, it seems like the Analyzer take only 20 image per second. Is there a way to increase the fps? I need to take at least 40-60 image per second, because I need to do post-processing with machine learning for each frame, so they will probably drop to 20-30 after ML analysis.
EDIT: I discover that with the Pixel 2xl I got 60fps without any drop..with my device (Xiaomi Redmi Note 5 Pro) I got only 25 fps...Can I optimize the code in any way to increase FPS?