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.Arguments
|
||||||
import com.facebook.react.bridge.ReadableArray
|
import com.facebook.react.bridge.ReadableArray
|
||||||
import com.facebook.react.bridge.ReadableMap
|
import com.facebook.react.bridge.ReadableMap
|
||||||
import com.mrousavy.camera.extensions.bigger
|
|
||||||
import com.mrousavy.camera.extensions.getPhotoSizes
|
import com.mrousavy.camera.extensions.getPhotoSizes
|
||||||
import com.mrousavy.camera.extensions.getVideoSizes
|
import com.mrousavy.camera.extensions.getVideoSizes
|
||||||
|
import com.mrousavy.camera.extensions.toJSValue
|
||||||
import com.mrousavy.camera.types.AutoFocusSystem
|
import com.mrousavy.camera.types.AutoFocusSystem
|
||||||
|
import com.mrousavy.camera.types.DeviceType
|
||||||
import com.mrousavy.camera.types.HardwareLevel
|
import com.mrousavy.camera.types.HardwareLevel
|
||||||
import com.mrousavy.camera.types.LensFacing
|
import com.mrousavy.camera.types.LensFacing
|
||||||
import com.mrousavy.camera.types.Orientation
|
import com.mrousavy.camera.types.Orientation
|
||||||
import com.mrousavy.camera.types.PixelFormat
|
import com.mrousavy.camera.types.PixelFormat
|
||||||
import com.mrousavy.camera.types.VideoStabilizationMode
|
import com.mrousavy.camera.types.VideoStabilizationMode
|
||||||
import kotlin.math.PI
|
import kotlin.math.atan2
|
||||||
import kotlin.math.atan
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
class CameraDeviceDetails(private val cameraManager: CameraManager, private val cameraId: String) {
|
class CameraDeviceDetails(private val cameraManager: CameraManager, private val cameraId: String) {
|
||||||
private val characteristics = cameraManager.getCameraCharacteristics(cameraId)
|
private val characteristics = cameraManager.getCameraCharacteristics(cameraId)
|
||||||
@ -106,33 +107,29 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
|||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
// 35mm is 135 film format, a standard in which focal lengths are usually measured
|
private fun getDeviceTypes(): List<DeviceType> {
|
||||||
private val size35mm = Size(36, 24)
|
val deviceTypes = focalLengths.map { focalLength ->
|
||||||
|
val fov = getFieldOfView(focalLength)
|
||||||
private fun getDeviceTypes(): ReadableArray {
|
return@map when {
|
||||||
// To get valid focal length standards we have to upscale to the 35mm measurement (film standard)
|
fov > 94 -> DeviceType.ULTRA_WIDE_ANGLE
|
||||||
val cropFactor = size35mm.bigger / sensorSize.bigger
|
fov in 60f..94f -> DeviceType.WIDE_ANGLE
|
||||||
|
fov < 60f -> DeviceType.TELEPHOTO
|
||||||
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")
|
|
||||||
else -> throw Error("Invalid focal length! (${focalLength}mm)")
|
else -> throw Error("Invalid focal length! (${focalLength}mm)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return deviceTypes
|
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 getVideoSizes(): List<Size> = characteristics.getVideoSizes(cameraId, videoFormat)
|
||||||
private fun getPhotoSizes(): List<Size> = characteristics.getPhotoSizes(ImageFormat.JPEG)
|
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("minFps", fpsRange.lower)
|
||||||
map.putInt("maxFps", fpsRange.upper)
|
map.putInt("maxFps", fpsRange.upper)
|
||||||
map.putDouble("maxZoom", maxZoom)
|
map.putDouble("maxZoom", maxZoom)
|
||||||
map.putDouble("fieldOfView", getFieldOfView())
|
map.putDouble("fieldOfView", getMaxFieldOfView())
|
||||||
map.putBoolean("supportsVideoHDR", supportsVideoHdr)
|
map.putBoolean("supportsVideoHDR", supportsVideoHdr)
|
||||||
map.putBoolean("supportsPhotoHDR", supportsPhotoHdr)
|
map.putBoolean("supportsPhotoHDR", supportsPhotoHdr)
|
||||||
map.putBoolean("supportsDepthCapture", supportsDepthCapture)
|
map.putBoolean("supportsDepthCapture", supportsDepthCapture)
|
||||||
@ -188,9 +185,11 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun toMap(): ReadableMap {
|
fun toMap(): ReadableMap {
|
||||||
|
val deviceTypes = getDeviceTypes()
|
||||||
|
|
||||||
val map = Arguments.createMap()
|
val map = Arguments.createMap()
|
||||||
map.putString("id", cameraId)
|
map.putString("id", cameraId)
|
||||||
map.putArray("physicalDevices", getDeviceTypes())
|
map.putArray("physicalDevices", deviceTypes.toJSValue())
|
||||||
map.putString("position", lensFacing.unionValue)
|
map.putString("position", lensFacing.unionValue)
|
||||||
map.putString("name", name)
|
map.putString("name", name)
|
||||||
map.putBoolean("hasFlash", hasFlash)
|
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)
|
* 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)
|
* * `"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. (focal length between 24mm and 43mm)
|
* * `"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. (focal length between above 85mm)
|
* * `"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:
|
* 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