Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: Add minFocusDistance prop to CameraDevice #2392

Merged
merged 13 commits into from
Jan 15, 2024
4 changes: 2 additions & 2 deletions docs/docs/guides/ERRORS.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ See [the `CameraError.ts` file](https://github.com/mrousavy/react-native-vision-

### Runtime Errors

The `CameraRuntimeError` represents any kind of error that occured while mounting the Camera view, or an error that occured during the runtime.
The [`CameraRuntimeError`](/docs/api/classes/CameraRuntimeError) represents any kind of error that occured while mounting the Camera view, or an error that occured during the runtime.

The `<Camera />` UI Component provides an `onError` function that will be invoked every time an unexpected runtime error occured.

Expand All @@ -71,7 +71,7 @@ function App() {

### Capture Errors

The `CameraCaptureError` represents any kind of error that occured only while taking a photo or recording a video.
The [`CameraCaptureError`](/docs/api/classes/CameraCaptureError) represents any kind of error that occured only while taking a photo or recording a video.

```tsx
function App() {
Expand Down
8 changes: 6 additions & 2 deletions docs/docs/guides/PERFORMANCE.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Note: By default (when not passing the options object), a simpler device is alre

### No Video HDR

Video HDR uses 10-bit formats and/or additional processing steps that come with additional computation overhead. Disable Video HDR (don't pass `videoHdr` to the `<Camera>`) for higher efficiency.
Video HDR uses 10-bit formats and/or additional processing steps that come with additional computation overhead. Disable [`videoHdr`](/docs/api/interfaces/CameraProps#videohdr) for higher efficiency.

### Buffer Compression

Expand All @@ -83,7 +83,11 @@ By default, the `native` [`PixelFormat`](/docs/api#pixelformat) is used, which i

### Disable unneeded pipelines

Only enable [`photo`](/docs/api/interfaces/CameraProps#photo) and [`video`](/docs/api/interfaces/CameraProps#video) if needed.
Only enable [`photo`](/docs/api/interfaces/CameraProps#photo), [`video`](/docs/api/interfaces/CameraProps#video), [`codeScanner`](/docs/api/interfaces/CameraProps#codescanner) or [`frameProcessor`](/docs/api/interfaces/CameraProps#frameprocessor) if needed.

### Using `isActive`

The [`isActive`](/docs/api/interfaces/CameraProps#isactive) prop controls whether the Camera should actively stream frames. Instead of fully unmounting the `<Camera>` component and remounting it again, keep it mounted and just switch `isActive` on or off. This makes the Camera resume much faster as it internally keeps the session warmed up.

### Fast Photos

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class CameraDeviceDetails(val cameraManager: CameraManager, val cameraId: String
?: floatArrayOf(35f)
val sensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)!!
val sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!
val minFocusDistance = getMinFocusDistanceCm()
val name = (
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
characteristics.get(CameraCharacteristics.INFO_VERSION)
Expand Down Expand Up @@ -97,6 +98,13 @@ class CameraDeviceDetails(val cameraManager: CameraManager, val cameraId: String
return false
}

private fun getMinFocusDistanceCm(): Double {
val distance = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)
if (distance == null || distance == 0f) return 0.0
// distance is in "diopters", meaning 1/meter. Convert to meters, then centi-meters
return 1.0 / distance * 100.0
}

private fun createStabilizationModes(): ReadableArray {
val array = Arguments.createArray()
digitalStabilizationModes.forEach { videoStabilizationMode ->
Expand Down Expand Up @@ -198,6 +206,7 @@ class CameraDeviceDetails(val cameraManager: CameraManager, val cameraId: String
map.putString("name", name)
map.putBoolean("hasFlash", hasFlash)
map.putBoolean("hasTorch", hasFlash)
map.putDouble("minFocusDistance", minFocusDistance)
map.putBoolean("isMultiCam", isMultiCam)
map.putBoolean("supportsRawCapture", supportsRawCapture)
map.putBoolean("supportsLowLightBoost", supportsLowLightBoost)
Expand Down
2 changes: 1 addition & 1 deletion package/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -729,4 +729,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 27f53791141a3303d814e09b55770336416ff4eb

COCOAPODS: 1.14.3
COCOAPODS: 1.11.3
25 changes: 25 additions & 0 deletions package/ios/Extensions/AVCaptureDevice+minFocusDistance.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// AVCaptureDevice+minFocusDistance.swift
// VisionCamera
//
// Created by Marc Rousavy on 15.01.24.
// Copyright © 2024 mrousavy. All rights reserved.
//

import AVFoundation
import Foundation

extension AVCaptureDevice {
/**
* The minimum distance this device can focus to, in centi-meters.
*/
var minFocusDistance: Double {
guard #available(iOS 15.0, *), minimumFocusDistance > 0 else {
// focus distance is unknown/unavailable
return 0
}

// convert from millimeters to centimeters
return Double(minimumFocusDistance) / 10
}
}
1 change: 1 addition & 0 deletions package/ios/Extensions/AVCaptureDevice+toDictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extension AVCaptureDevice {
"name": localizedName,
"hasFlash": hasFlash,
"hasTorch": hasTorch,
"minFocusDistance": minFocusDistance,
"minZoom": minAvailableVideoZoomFactor,
"maxZoom": maxAvailableVideoZoomFactor,
"neutralZoom": neutralZoomFactor,
Expand Down
4 changes: 4 additions & 0 deletions package/ios/VisionCamera.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
B88751A725E0102000DB86D6 /* CameraView+Zoom.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887518225E0102000DB86D6 /* CameraView+Zoom.swift */; };
B88751A825E0102000DB86D6 /* CameraError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887518325E0102000DB86D6 /* CameraError.swift */; };
B88751A925E0102000DB86D6 /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887518425E0102000DB86D6 /* CameraView.swift */; };
B88977BE2B556DBA0095C92C /* AVCaptureDevice+minFocusDistance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88977BD2B556DBA0095C92C /* AVCaptureDevice+minFocusDistance.swift */; };
B8994E6C263F03E100069589 /* JSINSObjectConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = B8994E6B263F03E100069589 /* JSINSObjectConversion.mm */; };
B8A1AEC42AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A1AEC32AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift */; };
B8A1AEC62AD7F08E00169C0D /* CameraView+Focus.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A1AEC52AD7F08E00169C0D /* CameraView+Focus.swift */; };
Expand Down Expand Up @@ -161,6 +162,7 @@
B887518325E0102000DB86D6 /* CameraError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraError.swift; sourceTree = "<group>"; };
B887518425E0102000DB86D6 /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
B88873E5263D46C7008B1D0E /* FrameProcessorPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameProcessorPlugin.h; sourceTree = "<group>"; };
B88977BD2B556DBA0095C92C /* AVCaptureDevice+minFocusDistance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice+minFocusDistance.swift"; sourceTree = "<group>"; };
B8994E6B263F03E100069589 /* JSINSObjectConversion.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = JSINSObjectConversion.mm; sourceTree = "<group>"; };
B89A79692B3EF60F005E0357 /* UIImageOrientation+descriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImageOrientation+descriptor.h"; sourceTree = "<group>"; };
B8A1AEC32AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureVideoDataOutput+pixelFormat.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -284,6 +286,7 @@
B8A1AEC32AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift */,
B8207AAC2B0E5DD70002990F /* AVCaptureSession+synchronizeBuffer.swift */,
B8207AAE2B0E67460002990F /* AVCaptureVideoDataOutput+recommendedVideoSettings.swift */,
B88977BD2B556DBA0095C92C /* AVCaptureDevice+minFocusDistance.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -488,6 +491,7 @@
B881D35E2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift in Sources */,
B87B11BF2A8E63B700732EBF /* PixelFormat.swift in Sources */,
B88751A625E0102000DB86D6 /* CameraViewManager.swift in Sources */,
B88977BE2B556DBA0095C92C /* AVCaptureDevice+minFocusDistance.swift in Sources */,
B80175EC2ABDEBD000E7DE90 /* ResizeMode.swift in Sources */,
B887519F25E0102000DB86D6 /* AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift in Sources */,
B88685ED2AD6A5E600E93869 /* CameraSession+CodeScanner.swift in Sources */,
Expand Down
4 changes: 4 additions & 0 deletions package/src/CameraDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ export interface CameraDevice {
* Specifies whether this camera supports continuously enabling the flash to act like a torch (flash with video capture)
*/
hasTorch: boolean
/**
* The minimum distance this device can properly focus to (in centimeters/cm) or `0` if unknown.
*/
minFocusDistance: number
/**
* A property indicating whether the device is a virtual multi-camera consisting of multiple combined physical cameras.
*
Expand Down