feat: Create persistent CaptureSession to avoid any blackscreen issues or errors (#2494)

* feat: Create custom `CaptureSession` wrapper

* Create `PersistentCameraCaptureSession`

* Update VideoStabilizationMode.kt

* Create RepeatingRequest.kt

* Update CaptureSession.kt

* Delete CaptureSession.kt

* Update PersistentCameraCaptureSession.kt

* Update PersistentCameraCaptureSession.kt

* fix: Add `isRepeating`

* Update CameraSession.kt

* Make `SurfaceOutput` not `Closable` anymore

* Update PersistentCameraCaptureSession.kt

* Stub out the rest

* Format

* Set `isRunning` properly

* Close previous outputs

* onError callback

* Format

* Started/Stopped

* Update CameraPage.tsx

* Add `isValid`

* Log `isActive`

* Add `tryAbortCaptures`

* Configure()

* Try?

* Add `didDestroyFromOutside`

* Disable FP for testing

* fix: Call `super.onAttachedToWindow` first

* Hm

* Update CameraSession.kt

* Update PersistentCameraCaptureSession.kt

* Try catch `didDestroyFromOutside`

* Update PersistentCameraCaptureSession.kt

* Session can only be active with a preview

* Update PersistentCameraCaptureSession.kt

* Throw `no-outputs` if needed

* Update logs

* fix: Check for CAMERA permission

* fix: Close session when opening a new device

* perf: Make everything `by lazy` in CameraDeviceDetails

* Update CameraDeviceDetails.kt

* Update PersistentCameraCaptureSession.kt

* Update PersistentCameraCaptureSession.kt

* Move

* Update Podfile.lock

* Implement `capture()`

* Format

* fix: Fix orientation not being applied

* fix: Fix `isMirrored`

* fix: Fix getting size

* fix: Close `Surface` in `VideoPipeline`

* Format

* fix: Fix `VideoPipeline` not properly destroying itself

* Use FP again

* Update CameraConfiguration.kt

* Rename

* Clean up

* Format

* Update CameraConfiguration.kt

* fix: Don't stop repeating request when capturing
This commit is contained in:
Marc Rousavy
2024-02-06 14:19:25 +01:00
committed by GitHub
parent cd5fdd4924
commit 5acc64e031
20 changed files with 746 additions and 496 deletions

View File

@@ -0,0 +1,9 @@
package com.mrousavy.camera.extensions
import android.hardware.camera2.CameraCaptureSession
fun CameraCaptureSession.tryAbortCaptures() {
try {
abortCaptures()
} catch (_: Throwable) {}
}

View File

@@ -1,104 +0,0 @@
package com.mrousavy.camera.extensions
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CaptureRequest
import android.view.Surface
import com.mrousavy.camera.types.Flash
import com.mrousavy.camera.types.Orientation
import com.mrousavy.camera.types.QualityPrioritization
private fun supportsSnapshotCapture(cameraCharacteristics: CameraCharacteristics): Boolean {
// As per CameraDevice.TEMPLATE_VIDEO_SNAPSHOT in documentation:
val hardwareLevel = cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)!!
if (hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) return false
val capabilities = cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)!!
val hasDepth = capabilities.contains(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT)
val isBackwardsCompatible = !capabilities.contains(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)
if (hasDepth && !isBackwardsCompatible) return false
return true
}
fun CameraDevice.createPhotoCaptureRequest(
cameraManager: CameraManager,
surface: Surface,
zoom: Float,
qualityPrioritization: QualityPrioritization,
flashMode: Flash,
enableRedEyeReduction: Boolean,
enableAutoStabilization: Boolean,
enableHdr: Boolean,
orientation: Orientation
): CaptureRequest {
val cameraCharacteristics = cameraManager.getCameraCharacteristics(this.id)
val template = if (qualityPrioritization == QualityPrioritization.SPEED && supportsSnapshotCapture(cameraCharacteristics)) {
CameraDevice.TEMPLATE_VIDEO_SNAPSHOT
} else {
CameraDevice.TEMPLATE_STILL_CAPTURE
}
val captureRequest = this.createCaptureRequest(template)
captureRequest.addTarget(surface)
// TODO: Maybe we can even expose that prop directly?
val jpegQuality = when (qualityPrioritization) {
QualityPrioritization.SPEED -> 85
QualityPrioritization.BALANCED -> 92
QualityPrioritization.QUALITY -> 100
}
captureRequest.set(CaptureRequest.JPEG_QUALITY, jpegQuality.toByte())
captureRequest.set(CaptureRequest.JPEG_ORIENTATION, orientation.toDegrees())
// TODO: Use the same options as from the preview request. This is duplicate code!
when (flashMode) {
// Set the Flash Mode
Flash.OFF -> {
captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
}
Flash.ON -> {
captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH)
}
Flash.AUTO -> {
if (enableRedEyeReduction) {
captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE)
} else {
captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
}
}
}
if (enableAutoStabilization) {
// Enable optical or digital image stabilization
val digitalStabilization = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)
val hasDigitalStabilization = digitalStabilization?.contains(CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_ON) ?: false
val opticalStabilization = cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)
val hasOpticalStabilization = opticalStabilization?.contains(CameraCharacteristics.LENS_OPTICAL_STABILIZATION_MODE_ON) ?: false
if (hasOpticalStabilization) {
captureRequest.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF)
captureRequest.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON)
} else if (hasDigitalStabilization) {
captureRequest.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON)
} else {
// no stabilization is supported. ignore it
}
}
// TODO: Check if that zoom value is even supported.
captureRequest.setZoom(zoom, cameraCharacteristics)
// Set HDR
// TODO: Check if that value is even supported
if (enableHdr) {
captureRequest.set(CaptureRequest.CONTROL_SCENE_MODE, CaptureRequest.CONTROL_SCENE_MODE_HDR)
}
return captureRequest.build()
}

View File

@@ -0,0 +1,13 @@
package com.mrousavy.camera.extensions
import android.hardware.camera2.CameraDevice
val CameraDevice.isValid: Boolean
get() {
try {
this.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
return true
} catch (e: Throwable) {
return false
}
}