Skip to content

Instantly share code, notes, and snippets.

@uchidev
Last active February 23, 2021 17:57
Show Gist options
  • Save uchidev/734540c84f7a6030b10dabed180b90c2 to your computer and use it in GitHub Desktop.
Save uchidev/734540c84f7a6030b10dabed180b90c2 to your computer and use it in GitHub Desktop.
camera config
// from https://github.com/android/camera-samples.git
private data class CameraInfo(
val name: String,
val cameraId: String,
val size: Size,
val fps: Int)
private fun lensOrientationString(value: Int) = when (value) {
CameraCharacteristics.LENS_FACING_BACK -> "Back"
CameraCharacteristics.LENS_FACING_FRONT -> "Front"
CameraCharacteristics.LENS_FACING_EXTERNAL -> "External"
else -> "Unknown"
}
val availableCameras: MutableList<CameraInfo> = mutableListOf()
// Iterate over the list of cameras and add those with high speed video recording capability to our output. This function only returns those cameras that declare constrained high speed video recording, but some cameras may be capable of doing unconstrained video recording with high enough FPS for some use cases and they will not necessarily declare constrained high speed video capability.
// カメラのリストを繰り返し処理し、高速ビデオ録画機能を持つカメラを出力に追加します。この関数は、制約付き高速ビデオ録画を宣言したカメラのみを返しますが、カメラの中には、ユースケースによっては制約なしで十分に高いFPSでのビデオ録画が可能なものもあり、必ずしも制約付き高速ビデオ録画機能を宣言しているとは限りません。
cameraManager.cameraIdList.forEach { id ->
val characteristics = cameraManager.getCameraCharacteristics(id)
val orientation = lensOrientationString(characteristics.get(CameraCharacteristics.LENS_FACING)!!)
// Query the available capabilities and output formats
// REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0
// REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1
// REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2
// REQUEST_AVAILABLE_CAPABILITIES_RAW = 3
// REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING = 4
// REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5
// REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6
// REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7
// REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8
// REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9
// REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10
// REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11
// REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12
// REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13
val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)!!
// https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap
val streamConfigMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
// Return cameras that declare to be backward compatible
if (capabilities.contains(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) {
// Recording should always be done in the most efficient format, which is the format native to the camera framework
val targetClass = MediaRecorder::class.java
// For each size, list the expected FPS
streamConfigMap.getOutputSizes(targetClass).forEach { size ->
// Get the number of seconds that each frame will take to process
val secondsPerFrame = streamConfigMap.getOutputMinFrameDuration(targetClass, size) / 1_000_000_000.0
// Compute the frames per second to let user select a configuration
val fps = if (secondsPerFrame > 0) (1.0 / secondsPerFrame).toInt() else 0
val fpsLabel = if (fps > 0) "$fps" else "N/A"
availableCameras.add(CameraInfo("$orientation ($id) $size $fpsLabel FPS", id, size, fps))
}
}
}
// https://medium.com/androiddevelopers/camera-enumeration-on-android-9a053b910cb5
fun filterCompatibleCameras(cameraIds: Array<String>, cameraManager: CameraManager): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
}
}
fun filterCameraIdsFacing(cameraIds: List<String>, cameraManager: CameraManager, facing: Int): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.LENS_FACING) == facing
}
}
fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? {
// Get all front, back and external cameras in 3 separate lists
val cameraIds = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager)
val backCameras = filterCameraIdsFacing(cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK)
val frontCameras = filterCameraIdsFacing(cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT)
val externalCameras = filterCameraIdsFacing(cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL)
// The recommended order of iteration is: all external, first back, first front
val allCameras = (externalCameras + listOf(backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull()
// Get the index of the currently selected camera in the list
val cameraIndex = allCameras.indexOf(currCameraId)
// The selected camera may not be on the list, for example it could be an
// external camera that has been removed by the user
return if (cameraIndex == -1) {
// Return the first camera from the list
allCameras.getOrNull(0)
} else {
// Return the next camera from the list, wrap around if necessary
allCameras.getOrNull((cameraIndex + 1) % allCameras.size)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment