81 lines
3.3 KiB
Kotlin
Raw Normal View History

2021-02-19 20:41:49 +01:00
package com.mrousavy.camera.utils
2021-02-19 16:28:14 +01:00
import android.hardware.camera2.CameraCharacteristics
import android.util.Size
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReadableArray
import com.mrousavy.camera.parsers.bigger
2021-02-19 16:28:14 +01:00
import kotlin.math.PI
import kotlin.math.atan
// 35mm is 135 film format, a standard in which focal lengths are usually measured
val Size35mm = Size(36, 24)
/**
* Convert a given array of focal lengths to the corresponding TypeScript union type name.
*
* Possible values for single cameras:
* * `"wide-angle-camera"`
* * `"ultra-wide-angle-camera"`
* * `"telephoto-camera"`
*
* Sources for the focal length categories:
* * [Telephoto Lens (wikipedia)](https://en.wikipedia.org/wiki/Telephoto_lens)
* * [Normal Lens (wikipedia)](https://en.wikipedia.org/wiki/Normal_lens)
* * [Wide-Angle Lens (wikipedia)](https://en.wikipedia.org/wiki/Wide-angle_lens)
* * [Ultra-Wide-Angle Lens (wikipedia)](https://en.wikipedia.org/wiki/Ultra_wide_angle_lens)
*/
fun CameraCharacteristics.getDeviceTypes(): ReadableArray {
// TODO: Check if getDeviceType() works correctly, even for logical multi-cameras
val focalLengths = this.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)!!
val sensorSize = this.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)!!
2021-02-19 16:28:14 +01:00
// To get valid focal length standards we have to upscale to the 35mm measurement (film standard)
val cropFactor = Size35mm.bigger / sensorSize.bigger
2021-02-19 16:28:14 +01:00
val deviceTypes = Arguments.createArray()
2021-02-19 16:28:14 +01:00
val containsTelephoto = focalLengths.any { l -> (l * cropFactor) > 35 } // TODO: Telephoto lenses are > 85mm, but we don't have anything between that range..
// val containsNormalLens = focalLengths.any { l -> (l * cropFactor) > 35 && (l * cropFactor) <= 55 }
val containsWideAngle = focalLengths.any { l -> (l * cropFactor) >= 24 && (l * cropFactor) <= 35 }
val containsUltraWideAngle = focalLengths.any { l -> (l * cropFactor) < 24 }
2021-02-19 16:28:14 +01:00
if (containsTelephoto)
deviceTypes.pushString("telephoto-camera")
if (containsWideAngle)
deviceTypes.pushString("wide-angle-camera")
if (containsUltraWideAngle)
deviceTypes.pushString("ultra-wide-angle-camera")
2021-02-19 16:28:14 +01:00
return deviceTypes
2021-02-19 16:28:14 +01:00
}
fun CameraCharacteristics.getFieldOfView(): Double {
val focalLengths = this.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)!!
val sensorSize = this.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)!!
2021-02-19 16:28:14 +01:00
return 2 * atan(sensorSize.bigger / (focalLengths[0] * 2)) * (180 / PI)
2021-02-19 16:28:14 +01:00
}
fun CameraCharacteristics.supportsFps(fps: Int): Boolean {
return this.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)!!
.any { it.upper >= fps && it.lower <= fps }
2021-02-19 16:28:14 +01:00
}
/**
* Get the value at which the Zoom is at neutral state (wide-angle camera zoom 0) (in percent, between 0.0-1.0)
*
* * On single-camera physical devices this value will always be 0
* * On devices with multiple cameras, e.g. triple-camera, this value will be a value between 0.0 and 1.0, where the field-of-view and zoom looks "neutral"
*/
val CameraCharacteristics.neutralZoomPercent: Float
get() {
val zoomRange = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
this.get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE)
else null
return if (zoomRange != null)
((1.0f - zoomRange.lower) / (zoomRange.upper - zoomRange.lower))
else
0.0f
}