fix: Fix physicalDevices
DeviceType computation on Android (#2072)
* fix: Fix device type calculation on Android * fix: Type safety for deviceTypes * fix: Update docs
This commit is contained in:
parent
5b1e5f3c9d
commit
8a5dfd6ac6
@ -11,17 +11,18 @@ import android.util.Size
|
||||
import com.facebook.react.bridge.Arguments
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.mrousavy.camera.extensions.bigger
|
||||
import com.mrousavy.camera.extensions.getPhotoSizes
|
||||
import com.mrousavy.camera.extensions.getVideoSizes
|
||||
import com.mrousavy.camera.extensions.toJSValue
|
||||
import com.mrousavy.camera.types.AutoFocusSystem
|
||||
import com.mrousavy.camera.types.DeviceType
|
||||
import com.mrousavy.camera.types.HardwareLevel
|
||||
import com.mrousavy.camera.types.LensFacing
|
||||
import com.mrousavy.camera.types.Orientation
|
||||
import com.mrousavy.camera.types.PixelFormat
|
||||
import com.mrousavy.camera.types.VideoStabilizationMode
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class CameraDeviceDetails(private val cameraManager: CameraManager, private val cameraId: String) {
|
||||
private val characteristics = cameraManager.getCameraCharacteristics(cameraId)
|
||||
@ -106,33 +107,29 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
||||
return array
|
||||
}
|
||||
|
||||
// 35mm is 135 film format, a standard in which focal lengths are usually measured
|
||||
private val size35mm = Size(36, 24)
|
||||
|
||||
private fun getDeviceTypes(): ReadableArray {
|
||||
// To get valid focal length standards we have to upscale to the 35mm measurement (film standard)
|
||||
val cropFactor = size35mm.bigger / sensorSize.bigger
|
||||
|
||||
val deviceTypes = Arguments.createArray()
|
||||
|
||||
focalLengths.forEach { focalLength ->
|
||||
// scale to the 35mm film standard
|
||||
val l = focalLength * cropFactor
|
||||
when {
|
||||
// https://en.wikipedia.org/wiki/Ultra_wide_angle_lens
|
||||
l < 24f -> deviceTypes.pushString("ultra-wide-angle-camera")
|
||||
// https://en.wikipedia.org/wiki/Wide-angle_lens
|
||||
l in 24f..43f -> deviceTypes.pushString("wide-angle-camera")
|
||||
// https://en.wikipedia.org/wiki/Telephoto_lens
|
||||
l > 43f -> deviceTypes.pushString("telephoto-camera")
|
||||
private fun getDeviceTypes(): List<DeviceType> {
|
||||
val deviceTypes = focalLengths.map { focalLength ->
|
||||
val fov = getFieldOfView(focalLength)
|
||||
return@map when {
|
||||
fov > 94 -> DeviceType.ULTRA_WIDE_ANGLE
|
||||
fov in 60f..94f -> DeviceType.WIDE_ANGLE
|
||||
fov < 60f -> DeviceType.TELEPHOTO
|
||||
else -> throw Error("Invalid focal length! (${focalLength}mm)")
|
||||
}
|
||||
}
|
||||
|
||||
return deviceTypes
|
||||
}
|
||||
|
||||
private fun getFieldOfView(): Double = 2 * atan(sensorSize.bigger / (focalLengths[0] * 2)) * (180 / PI)
|
||||
private fun getFieldOfView(focalLength: Float): Double {
|
||||
val sensorDiagonal = sqrt((sensorSize.width * sensorSize.width + sensorSize.height * sensorSize.height).toDouble())
|
||||
val fovRadians = 2.0 * atan2(sensorDiagonal, (2.0 * focalLength))
|
||||
return Math.toDegrees(fovRadians)
|
||||
}
|
||||
|
||||
private fun getMaxFieldOfView(): Double {
|
||||
val smallestFocalLength = focalLengths.minOrNull() ?: return 0.0
|
||||
return getFieldOfView(smallestFocalLength)
|
||||
}
|
||||
|
||||
private fun getVideoSizes(): List<Size> = characteristics.getVideoSizes(cameraId, videoFormat)
|
||||
private fun getPhotoSizes(): List<Size> = characteristics.getPhotoSizes(ImageFormat.JPEG)
|
||||
@ -177,7 +174,7 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
||||
map.putInt("minFps", fpsRange.lower)
|
||||
map.putInt("maxFps", fpsRange.upper)
|
||||
map.putDouble("maxZoom", maxZoom)
|
||||
map.putDouble("fieldOfView", getFieldOfView())
|
||||
map.putDouble("fieldOfView", getMaxFieldOfView())
|
||||
map.putBoolean("supportsVideoHDR", supportsVideoHdr)
|
||||
map.putBoolean("supportsPhotoHDR", supportsPhotoHdr)
|
||||
map.putBoolean("supportsDepthCapture", supportsDepthCapture)
|
||||
@ -188,9 +185,11 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
||||
}
|
||||
|
||||
fun toMap(): ReadableMap {
|
||||
val deviceTypes = getDeviceTypes()
|
||||
|
||||
val map = Arguments.createMap()
|
||||
map.putString("id", cameraId)
|
||||
map.putArray("physicalDevices", getDeviceTypes())
|
||||
map.putArray("physicalDevices", deviceTypes.toJSValue())
|
||||
map.putString("position", lensFacing.unionValue)
|
||||
map.putString("name", name)
|
||||
map.putBoolean("hasFlash", hasFlash)
|
||||
|
@ -0,0 +1,11 @@
|
||||
package com.mrousavy.camera.extensions
|
||||
|
||||
import com.facebook.react.bridge.Arguments
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.mrousavy.camera.types.JSUnionValue
|
||||
|
||||
fun List<JSUnionValue>.toJSValue(): ReadableArray {
|
||||
val arguments = Arguments.createArray()
|
||||
this.forEach { arguments.pushString(it.unionValue) }
|
||||
return arguments
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.mrousavy.camera.types
|
||||
|
||||
enum class DeviceType(override val unionValue: String) : JSUnionValue {
|
||||
ULTRA_WIDE_ANGLE("ultra-wide-angle-camera"),
|
||||
WIDE_ANGLE("wide-angle-camera"),
|
||||
TELEPHOTO("telephoto-camera")
|
||||
}
|
@ -13,9 +13,9 @@ export type CameraPosition = 'front' | 'back' | 'external'
|
||||
/**
|
||||
* Indentifiers for a physical camera (one that actually exists on the back/front of the device)
|
||||
*
|
||||
* * `"ultra-wide-angle-camera"`: A built-in camera with a shorter focal length than that of a wide-angle camera. (focal length between below 24mm)
|
||||
* * `"wide-angle-camera"`: A built-in wide-angle camera. (focal length between 24mm and 43mm)
|
||||
* * `"telephoto-camera"`: A built-in camera device with a longer focal length than a wide-angle camera. (focal length between above 85mm)
|
||||
* * `"ultra-wide-angle-camera"`: A built-in camera with a shorter focal length than that of a wide-angle camera. (FOV of 94° or higher)
|
||||
* * `"wide-angle-camera"`: A built-in wide-angle camera. (FOV between 60° and 94°)
|
||||
* * `"telephoto-camera"`: A built-in camera device with a longer focal length than a wide-angle camera. (FOV of 60° or lower)
|
||||
*
|
||||
* Some Camera devices consist of multiple physical devices. They can be interpreted as _logical devices_, for example:
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user