chore: Clean up Android codebase a bit (#1748)
<!-- ❤️ Thank you for your contribution! ❤️ Make sure you have read the Contributing Guidelines: https://github.com/mrousavy/react-native-vision-camera/blob/main/CONTRIBUTING.md --> ## What <!-- Enter a short description on what this pull-request does. Examples: This PR adds support for the HEVC format. This PR fixes a "unsupported device" error on iPhone 8 and below. This PR fixes a typo in a CameraError. This PR adds support for Quadruple Cameras. --> ## Changes <!-- Create a short list of logic-changes. Examples: * This PR changes the default value of X to Y. * This PR changes the configure() function to cache results. --> ## Tested on <!-- Create a short list of devices and operating-systems you have tested this change on. (And verified that everything works as expected). Examples: * iPhone 11 Pro, iOS 14.3 * Huawai P20, Android 10 --> ## Related issues <!-- Link related issues here. Examples: * Fixes #29 * Closes #30 * Resolves #5 -->
This commit is contained in:
parent
272504f39d
commit
f3fd3f15e3
20
.github/workflows/build-android.yml
vendored
20
.github/workflows/build-android.yml
vendored
@ -6,19 +6,19 @@ on:
|
|||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-android.yml'
|
- '.github/workflows/build-android.yml'
|
||||||
- 'cpp/**'
|
- 'package/cpp/**'
|
||||||
- 'android/**'
|
- 'package/android/**'
|
||||||
- 'example/android/**'
|
- 'package/example/android/**'
|
||||||
- 'yarn.lock'
|
- 'package/yarn.lock'
|
||||||
- 'example/yarn.lock'
|
- 'package/example/yarn.lock'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-android.yml'
|
- '.github/workflows/build-android.yml'
|
||||||
- 'cpp/**'
|
- 'package/cpp/**'
|
||||||
- 'android/**'
|
- 'package/android/**'
|
||||||
- 'example/android/**'
|
- 'package/example/android/**'
|
||||||
- 'yarn.lock'
|
- 'package/yarn.lock'
|
||||||
- 'example/yarn.lock'
|
- 'package/example/yarn.lock'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
16
.github/workflows/build-ios.yml
vendored
16
.github/workflows/build-ios.yml
vendored
@ -6,17 +6,17 @@ on:
|
|||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-ios.yml'
|
- '.github/workflows/build-ios.yml'
|
||||||
- 'cpp/**'
|
- 'package/cpp/**'
|
||||||
- 'ios/**'
|
- 'package/ios/**'
|
||||||
- '*.podspec'
|
- 'package/*.podspec'
|
||||||
- 'example/ios/**'
|
- 'package/example/ios/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-ios.yml'
|
- '.github/workflows/build-ios.yml'
|
||||||
- 'cpp/**'
|
- 'package/cpp/**'
|
||||||
- 'ios/**'
|
- 'package/ios/**'
|
||||||
- '*.podspec'
|
- 'package/*.podspec'
|
||||||
- 'example/ios/**'
|
- 'package/example/ios/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
8
.github/workflows/validate-android.yml
vendored
8
.github/workflows/validate-android.yml
vendored
@ -6,13 +6,13 @@ on:
|
|||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/validate-android.yml'
|
- '.github/workflows/validate-android.yml'
|
||||||
- 'android/**'
|
- 'package/android/**'
|
||||||
- '.editorconfig'
|
- 'package/.editorconfig'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/validate-android.yml'
|
- '.github/workflows/validate-android.yml'
|
||||||
- 'android/**'
|
- 'package/android/**'
|
||||||
- '.editorconfig'
|
- 'package/.editorconfig'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
4
.github/workflows/validate-ios.yml
vendored
4
.github/workflows/validate-ios.yml
vendored
@ -6,11 +6,11 @@ on:
|
|||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/validate-ios.yml'
|
- '.github/workflows/validate-ios.yml'
|
||||||
- 'ios/**'
|
- 'package/ios/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/validate-ios.yml'
|
- '.github/workflows/validate-ios.yml'
|
||||||
- 'ios/**'
|
- 'package/ios/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
SwiftLint:
|
SwiftLint:
|
||||||
|
@ -4,7 +4,6 @@ import android.Manifest
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.hardware.camera2.CameraManager
|
import android.hardware.camera2.CameraManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
@ -31,13 +30,8 @@ import kotlinx.coroutines.launch
|
|||||||
//
|
//
|
||||||
// TODOs for the CameraView which are currently too hard to implement either because of CameraX' limitations, or my brain capacity.
|
// TODOs for the CameraView which are currently too hard to implement either because of CameraX' limitations, or my brain capacity.
|
||||||
//
|
//
|
||||||
// CameraView
|
|
||||||
// TODO: High-speed video recordings (export in CameraViewModule::getAvailableVideoDevices(), and set in CameraView::configurePreview()) (120FPS+)
|
// TODO: High-speed video recordings (export in CameraViewModule::getAvailableVideoDevices(), and set in CameraView::configurePreview()) (120FPS+)
|
||||||
|
|
||||||
// CameraView+RecordVideo
|
|
||||||
// TODO: Better startRecording()/stopRecording() (promise + callback, wait for TurboModules/JSI)
|
// TODO: Better startRecording()/stopRecording() (promise + callback, wait for TurboModules/JSI)
|
||||||
|
|
||||||
// CameraView+TakePhoto
|
|
||||||
// TODO: takePhoto() depth data
|
// TODO: takePhoto() depth data
|
||||||
// TODO: takePhoto() raw capture
|
// TODO: takePhoto() raw capture
|
||||||
// TODO: takePhoto() return with jsi::Value Image reference for faster capture
|
// TODO: takePhoto() return with jsi::Value Image reference for faster capture
|
||||||
@ -103,11 +97,6 @@ class CameraView(context: Context) : FrameLayout(context) {
|
|||||||
cameraSession = CameraSession(context, cameraManager, { invokeOnInitialized() }, { error -> invokeOnError(error) })
|
cameraSession = CameraSession(context, cameraManager, { invokeOnInitialized() }, { error -> invokeOnError(error) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration?) {
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
// TODO: updateOrientation()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
override fun onAttachedToWindow() {
|
||||||
super.onAttachedToWindow()
|
super.onAttachedToWindow()
|
||||||
if (!isMounted) {
|
if (!isMounted) {
|
||||||
@ -144,7 +133,6 @@ class CameraView(context: Context) : FrameLayout(context) {
|
|||||||
val shouldReconfigureFormat = shouldReconfigureSession || changedProps.containsAny(propsThatRequireFormatReconfiguration)
|
val shouldReconfigureFormat = shouldReconfigureSession || changedProps.containsAny(propsThatRequireFormatReconfiguration)
|
||||||
val shouldReconfigureZoom = shouldReconfigureSession || changedProps.contains("zoom")
|
val shouldReconfigureZoom = shouldReconfigureSession || changedProps.contains("zoom")
|
||||||
val shouldReconfigureTorch = shouldReconfigureSession || changedProps.contains("torch")
|
val shouldReconfigureTorch = shouldReconfigureSession || changedProps.contains("torch")
|
||||||
val shouldUpdateOrientation = /* TODO: When should we reconfigure this? */ shouldReconfigureSession || changedProps.contains("orientation")
|
|
||||||
val shouldCheckActive = shouldReconfigureFormat || changedProps.contains("isActive")
|
val shouldCheckActive = shouldReconfigureFormat || changedProps.contains("isActive")
|
||||||
val shouldReconfigureZoomGesture = changedProps.contains("enableZoomGesture")
|
val shouldReconfigureZoomGesture = changedProps.contains("enableZoomGesture")
|
||||||
|
|
||||||
@ -167,9 +155,6 @@ class CameraView(context: Context) : FrameLayout(context) {
|
|||||||
if (shouldReconfigureTorch) {
|
if (shouldReconfigureTorch) {
|
||||||
updateTorch()
|
updateTorch()
|
||||||
}
|
}
|
||||||
if (shouldUpdateOrientation) {
|
|
||||||
// TODO: updateOrientation()
|
|
||||||
}
|
|
||||||
if (shouldReconfigureZoomGesture) {
|
if (shouldReconfigureZoomGesture) {
|
||||||
updateZoomGesture()
|
updateZoomGesture()
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import com.mrousavy.camera.parsers.VideoStabilizationMode
|
|||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
class CameraViewManager : ViewGroupManager<CameraView>() {
|
class CameraViewManager : ViewGroupManager<CameraView>() {
|
||||||
|
|
||||||
public override fun createViewInstance(context: ThemedReactContext): CameraView {
|
public override fun createViewInstance(context: ThemedReactContext): CameraView {
|
||||||
return CameraView(context)
|
return CameraView(context)
|
||||||
}
|
}
|
||||||
|
@ -37,15 +37,8 @@ class CameraPermissionError : CameraError("permission", "camera-permission-denie
|
|||||||
class InvalidTypeScriptUnionError(unionName: String, unionValue: String) : CameraError("parameter", "invalid-parameter", "The given value for $unionName could not be parsed! (Received: $unionValue)")
|
class InvalidTypeScriptUnionError(unionName: String, unionValue: String) : CameraError("parameter", "invalid-parameter", "The given value for $unionName could not be parsed! (Received: $unionValue)")
|
||||||
|
|
||||||
class NoCameraDeviceError : CameraError("device", "no-device", "No device was set! Use `getAvailableCameraDevices()` to select a suitable Camera device.")
|
class NoCameraDeviceError : CameraError("device", "no-device", "No device was set! Use `getAvailableCameraDevices()` to select a suitable Camera device.")
|
||||||
class NoFlashAvailableError : CameraError("device", "flash-unavailable", "The Camera Device does not have a flash unit! Make sure you select a device where `hasFlash`/`hasTorch` is true!")
|
|
||||||
class PixelFormatNotSupportedError(format: String) : CameraError("device", "pixel-format-not-supported", "The pixelFormat $format is not supported on the given Camera Device!")
|
class PixelFormatNotSupportedError(format: String) : CameraError("device", "pixel-format-not-supported", "The pixelFormat $format is not supported on the given Camera Device!")
|
||||||
|
|
||||||
class HdrNotContainedInFormatError : CameraError(
|
|
||||||
"format", "invalid-hdr",
|
|
||||||
"The currently selected format does not support HDR capture! " +
|
|
||||||
"Make sure you select a format which includes `supportsPhotoHDR`!"
|
|
||||||
)
|
|
||||||
|
|
||||||
class CameraNotReadyError : CameraError("session", "camera-not-ready", "The Camera is not ready yet! Wait for the onInitialized() callback!")
|
class CameraNotReadyError : CameraError("session", "camera-not-ready", "The Camera is not ready yet! Wait for the onInitialized() callback!")
|
||||||
class CameraCannotBeOpenedError(cameraId: String, error: CameraDeviceError) : CameraError("session", "camera-cannot-be-opened", "The given Camera device (id: $cameraId) could not be opened! Error: $error")
|
class CameraCannotBeOpenedError(cameraId: String, error: CameraDeviceError) : CameraError("session", "camera-cannot-be-opened", "The given Camera device (id: $cameraId) could not be opened! Error: $error")
|
||||||
class CameraSessionCannotBeConfiguredError(cameraId: String, outputs: CameraOutputs) : CameraError("session", "cannot-create-session", "Failed to create a Camera Session for Camera $cameraId! Outputs: $outputs")
|
class CameraSessionCannotBeConfiguredError(cameraId: String, outputs: CameraOutputs) : CameraError("session", "cannot-create-session", "Failed to create a Camera Session for Camera $cameraId! Outputs: $outputs")
|
||||||
|
@ -91,7 +91,6 @@ 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
|
// 35mm is 135 film format, a standard in which focal lengths are usually measured
|
||||||
private val size35mm = Size(36, 24)
|
private val size35mm = Size(36, 24)
|
||||||
|
|
||||||
@ -153,7 +152,6 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
|||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get available pixel formats for the given Size
|
|
||||||
private fun createPixelFormats(size: Size): ReadableArray {
|
private fun createPixelFormats(size: Size): ReadableArray {
|
||||||
val formats = cameraConfig.outputFormats
|
val formats = cameraConfig.outputFormats
|
||||||
val array = Arguments.createArray()
|
val array = Arguments.createArray()
|
||||||
@ -186,7 +184,6 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to React Native JS object (map)
|
|
||||||
fun toMap(): ReadableMap {
|
fun toMap(): ReadableMap {
|
||||||
val map = Arguments.createMap()
|
val map = Arguments.createMap()
|
||||||
map.putString("id", cameraId)
|
map.putString("id", cameraId)
|
||||||
@ -205,39 +202,7 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
|
|||||||
map.putDouble("neutralZoom", 1.0) // Zoom is always relative to 1.0 on Android
|
map.putDouble("neutralZoom", 1.0) // Zoom is always relative to 1.0 on Android
|
||||||
map.putString("hardwareLevel", hardwareLevel.unionValue)
|
map.putString("hardwareLevel", hardwareLevel.unionValue)
|
||||||
map.putString("sensorOrientation", Orientation.fromRotationDegrees(sensorOrientation).unionValue)
|
map.putString("sensorOrientation", Orientation.fromRotationDegrees(sensorOrientation).unionValue)
|
||||||
|
|
||||||
val array = Arguments.createArray()
|
|
||||||
cameraConfig.outputFormats.forEach { f ->
|
|
||||||
val str = when (f) {
|
|
||||||
ImageFormat.YUV_420_888 -> "YUV_420_888"
|
|
||||||
ImageFormat.YUV_422_888 -> "YUV_422_888"
|
|
||||||
ImageFormat.YUV_444_888 -> "YUV_444_888"
|
|
||||||
ImageFormat.JPEG -> "JPEG"
|
|
||||||
ImageFormat.DEPTH16 -> "DEPTH16"
|
|
||||||
ImageFormat.DEPTH_JPEG -> "DEPTH_JPEG"
|
|
||||||
ImageFormat.FLEX_RGBA_8888 -> "FLEX_RGBA_8888"
|
|
||||||
ImageFormat.FLEX_RGB_888 -> "FLEX_RGB_888"
|
|
||||||
ImageFormat.YUY2 -> "YUY2"
|
|
||||||
ImageFormat.Y8 -> "Y8"
|
|
||||||
ImageFormat.YV12 -> "YV12"
|
|
||||||
ImageFormat.HEIC -> "HEIC"
|
|
||||||
ImageFormat.PRIVATE -> "PRIVATE"
|
|
||||||
ImageFormat.RAW_PRIVATE -> "RAW_PRIVATE"
|
|
||||||
ImageFormat.RAW_SENSOR -> "RAW_SENSOR"
|
|
||||||
ImageFormat.RAW10 -> "RAW10"
|
|
||||||
ImageFormat.RAW12 -> "RAW12"
|
|
||||||
ImageFormat.NV16 -> "NV16"
|
|
||||||
ImageFormat.NV21 -> "NV21"
|
|
||||||
ImageFormat.UNKNOWN -> "UNKNOWN"
|
|
||||||
ImageFormat.YCBCR_P010 -> "YCBCR_P010"
|
|
||||||
else -> "unknown ($f)"
|
|
||||||
}
|
|
||||||
array.pushString(str)
|
|
||||||
}
|
|
||||||
map.putArray("pixelFormats", array)
|
|
||||||
|
|
||||||
map.putArray("formats", getFormats())
|
map.putArray("formats", getFormats())
|
||||||
|
|
||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,10 @@ import com.mrousavy.camera.PhotoNotEnabledError
|
|||||||
import com.mrousavy.camera.RecorderError
|
import com.mrousavy.camera.RecorderError
|
||||||
import com.mrousavy.camera.RecordingInProgressError
|
import com.mrousavy.camera.RecordingInProgressError
|
||||||
import com.mrousavy.camera.VideoNotEnabledError
|
import com.mrousavy.camera.VideoNotEnabledError
|
||||||
import com.mrousavy.camera.extensions.SessionType
|
|
||||||
import com.mrousavy.camera.extensions.capture
|
import com.mrousavy.camera.extensions.capture
|
||||||
import com.mrousavy.camera.extensions.createCaptureSession
|
import com.mrousavy.camera.extensions.createCaptureSession
|
||||||
import com.mrousavy.camera.extensions.createPhotoCaptureRequest
|
import com.mrousavy.camera.extensions.createPhotoCaptureRequest
|
||||||
import com.mrousavy.camera.extensions.openCamera
|
import com.mrousavy.camera.extensions.openCamera
|
||||||
import com.mrousavy.camera.extensions.tryClose
|
|
||||||
import com.mrousavy.camera.extensions.zoomed
|
import com.mrousavy.camera.extensions.zoomed
|
||||||
import com.mrousavy.camera.frameprocessor.FrameProcessor
|
import com.mrousavy.camera.frameprocessor.FrameProcessor
|
||||||
import com.mrousavy.camera.parsers.Flash
|
import com.mrousavy.camera.parsers.Flash
|
||||||
@ -116,7 +114,7 @@ class CameraSession(private val context: Context,
|
|||||||
cameraManager.unregisterAvailabilityCallback(this)
|
cameraManager.unregisterAvailabilityCallback(this)
|
||||||
photoOutputSynchronizer.clear()
|
photoOutputSynchronizer.clear()
|
||||||
captureSession?.close()
|
captureSession?.close()
|
||||||
cameraDevice?.tryClose()
|
cameraDevice?.close()
|
||||||
outputs?.close()
|
outputs?.close()
|
||||||
isRunning = false
|
isRunning = false
|
||||||
}
|
}
|
||||||
@ -206,7 +204,6 @@ class CameraSession(private val context: Context,
|
|||||||
|
|
||||||
private fun updateVideoOutputs() {
|
private fun updateVideoOutputs() {
|
||||||
val videoPipeline = outputs?.videoOutput?.videoPipeline ?: return
|
val videoPipeline = outputs?.videoOutput?.videoPipeline ?: return
|
||||||
val previewOutput = outputs?.previewOutput
|
|
||||||
videoPipeline.setRecordingSessionOutput(this.recording)
|
videoPipeline.setRecordingSessionOutput(this.recording)
|
||||||
videoPipeline.setFrameProcessorOutput(this.frameProcessor)
|
videoPipeline.setFrameProcessorOutput(this.frameProcessor)
|
||||||
}
|
}
|
||||||
@ -377,7 +374,7 @@ class CameraSession(private val context: Context,
|
|||||||
return currentDevice
|
return currentDevice
|
||||||
}
|
}
|
||||||
// Close previous device
|
// Close previous device
|
||||||
cameraDevice?.tryClose()
|
cameraDevice?.close()
|
||||||
cameraDevice = null
|
cameraDevice = null
|
||||||
|
|
||||||
val device = cameraManager.openCamera(cameraId, { camera, reason ->
|
val device = cameraManager.openCamera(cameraId, { camera, reason ->
|
||||||
@ -410,7 +407,7 @@ class CameraSession(private val context: Context,
|
|||||||
captureSession?.close()
|
captureSession?.close()
|
||||||
captureSession = null
|
captureSession = null
|
||||||
|
|
||||||
val session = cameraDevice.createCaptureSession(cameraManager, SessionType.REGULAR, outputs, { session ->
|
val session = cameraDevice.createCaptureSession(cameraManager, outputs, { session ->
|
||||||
Log.d(TAG, "Capture Session Closed ($captureSession == $session)")
|
Log.d(TAG, "Capture Session Closed ($captureSession == $session)")
|
||||||
if (captureSession == session) {
|
if (captureSession == session) {
|
||||||
// The current CameraCaptureSession has been closed, handle that!
|
// The current CameraCaptureSession has been closed, handle that!
|
||||||
|
@ -66,6 +66,6 @@ class PreviewView(context: Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "NativePreviewView"
|
private const val TAG = "PreviewView"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,10 +108,7 @@ class VideoPipeline(val width: Int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the Pipeline to also call the given [FrameProcessor].
|
* Configures the Pipeline to also call the given [FrameProcessor] (or null).
|
||||||
* * If the [frameProcessor] is `null`, this output channel will be removed.
|
|
||||||
* * If the [frameProcessor] is not `null`, the [VideoPipeline] will create Frames
|
|
||||||
* using an [ImageWriter] and call the [FrameProcessor] with those Frames.
|
|
||||||
*/
|
*/
|
||||||
fun setFrameProcessorOutput(frameProcessor: FrameProcessor?) {
|
fun setFrameProcessorOutput(frameProcessor: FrameProcessor?) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@ -138,9 +135,7 @@ class VideoPipeline(val width: Int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the Pipeline to also write Frames to a Surface from a [MediaRecorder].
|
* Configures the Pipeline to also write Frames to a Surface from a [MediaRecorder] (or null)
|
||||||
* * If the [surface] is `null`, this output channel will be removed.
|
|
||||||
* * If the [surface] is not `null`, the [VideoPipeline] will write Frames to this Surface.
|
|
||||||
*/
|
*/
|
||||||
fun setRecordingSessionOutput(recordingSession: RecordingSession?) {
|
fun setRecordingSessionOutput(recordingSession: RecordingSession?) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
@ -22,8 +22,7 @@ class CameraOutputs(val cameraId: String,
|
|||||||
val photo: PhotoOutput? = null,
|
val photo: PhotoOutput? = null,
|
||||||
val video: VideoOutput? = null,
|
val video: VideoOutput? = null,
|
||||||
val enableHdr: Boolean? = false,
|
val enableHdr: Boolean? = false,
|
||||||
val callback: Callback
|
val callback: Callback): Closeable {
|
||||||
): Closeable {
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "CameraOutputs"
|
private const val TAG = "CameraOutputs"
|
||||||
const val PHOTO_OUTPUT_BUFFER_SIZE = 3
|
const val PHOTO_OUTPUT_BUFFER_SIZE = 3
|
||||||
|
@ -5,9 +5,6 @@ import android.util.Log
|
|||||||
import android.util.Size
|
import android.util.Size
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
/**
|
|
||||||
* A [SurfaceOutput] that uses an [ImageReader] as it's surface.
|
|
||||||
*/
|
|
||||||
class ImageReaderOutput(private val imageReader: ImageReader,
|
class ImageReaderOutput(private val imageReader: ImageReader,
|
||||||
outputType: OutputType,
|
outputType: OutputType,
|
||||||
dynamicRangeProfile: Long? = null): Closeable, SurfaceOutput(imageReader.surface, Size(imageReader.width, imageReader.height), outputType, dynamicRangeProfile) {
|
dynamicRangeProfile: Long? = null): Closeable, SurfaceOutput(imageReader.surface, Size(imageReader.width, imageReader.height), outputType, dynamicRangeProfile) {
|
||||||
|
@ -10,9 +10,6 @@ import android.view.Surface
|
|||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
/**
|
|
||||||
* A general-purpose Camera Output that writes to a [Surface]
|
|
||||||
*/
|
|
||||||
open class SurfaceOutput(val surface: Surface,
|
open class SurfaceOutput(val surface: Surface,
|
||||||
val size: Size,
|
val size: Size,
|
||||||
val outputType: OutputType,
|
val outputType: OutputType,
|
||||||
|
@ -5,9 +5,6 @@ import android.util.Size
|
|||||||
import com.mrousavy.camera.core.VideoPipeline
|
import com.mrousavy.camera.core.VideoPipeline
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
/**
|
|
||||||
* A [SurfaceOutput] that uses a [VideoPipeline] as it's surface.
|
|
||||||
*/
|
|
||||||
class VideoPipelineOutput(val videoPipeline: VideoPipeline,
|
class VideoPipelineOutput(val videoPipeline: VideoPipeline,
|
||||||
outputType: OutputType,
|
outputType: OutputType,
|
||||||
dynamicRangeProfile: Long? = null): Closeable, SurfaceOutput(videoPipeline.surface, Size(videoPipeline.width, videoPipeline.height), outputType, dynamicRangeProfile) {
|
dynamicRangeProfile: Long? = null): Closeable, SurfaceOutput(videoPipeline.surface, Size(videoPipeline.width, videoPipeline.height), outputType, dynamicRangeProfile) {
|
||||||
|
@ -16,24 +16,10 @@ import kotlinx.coroutines.suspendCancellableCoroutine
|
|||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
enum class SessionType {
|
|
||||||
REGULAR,
|
|
||||||
HIGH_SPEED;
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.P)
|
|
||||||
fun toSessionType(): Int {
|
|
||||||
return when(this) {
|
|
||||||
REGULAR -> SessionConfiguration.SESSION_REGULAR
|
|
||||||
HIGH_SPEED -> SessionConfiguration.SESSION_HIGH_SPEED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val TAG = "CreateCaptureSession"
|
private const val TAG = "CreateCaptureSession"
|
||||||
private var sessionId = 1000
|
private var sessionId = 1000
|
||||||
|
|
||||||
suspend fun CameraDevice.createCaptureSession(cameraManager: CameraManager,
|
suspend fun CameraDevice.createCaptureSession(cameraManager: CameraManager,
|
||||||
sessionType: SessionType,
|
|
||||||
outputs: CameraOutputs,
|
outputs: CameraOutputs,
|
||||||
onClosed: (session: CameraCaptureSession) -> Unit,
|
onClosed: (session: CameraCaptureSession) -> Unit,
|
||||||
queue: CameraQueues.CameraQueue): CameraCaptureSession {
|
queue: CameraQueues.CameraQueue): CameraCaptureSession {
|
||||||
@ -85,7 +71,7 @@ suspend fun CameraDevice.createCaptureSession(cameraManager: CameraManager,
|
|||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
Log.i(TAG, "Using new API (>=28)")
|
Log.i(TAG, "Using new API (>=28)")
|
||||||
val config = SessionConfiguration(sessionType.toSessionType(), outputConfigurations, queue.executor, callback)
|
val config = SessionConfiguration(SessionConfiguration.SESSION_REGULAR, outputConfigurations, queue.executor, callback)
|
||||||
this.createCaptureSession(config)
|
this.createCaptureSession(config)
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, "Using legacy API (<28)")
|
Log.i(TAG, "Using legacy API (<28)")
|
||||||
|
@ -35,7 +35,7 @@ suspend fun CameraManager.openCamera(cameraId: String,
|
|||||||
} else {
|
} else {
|
||||||
onDisconnected(camera, CameraDisconnectedError(cameraId, CameraDeviceError.DISCONNECTED))
|
onDisconnected(camera, CameraDisconnectedError(cameraId, CameraDeviceError.DISCONNECTED))
|
||||||
}
|
}
|
||||||
camera.tryClose()
|
camera.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(camera: CameraDevice, errorCode: Int) {
|
override fun onError(camera: CameraDevice, errorCode: Int) {
|
||||||
@ -46,7 +46,7 @@ suspend fun CameraManager.openCamera(cameraId: String,
|
|||||||
} else {
|
} else {
|
||||||
onDisconnected(camera, CameraDisconnectedError(cameraId, error))
|
onDisconnected(camera, CameraDisconnectedError(cameraId, error))
|
||||||
}
|
}
|
||||||
camera.tryClose()
|
camera.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,12 +57,3 @@ suspend fun CameraManager.openCamera(cameraId: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CameraDevice.tryClose() {
|
|
||||||
try {
|
|
||||||
Log.i(TAG, "Camera $id: Closing...")
|
|
||||||
this.close()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Log.e(TAG, "Camera $id: Failed to close!", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package com.mrousavy.camera.extensions
|
|
||||||
|
|
||||||
import android.os.Handler
|
|
||||||
import java.util.concurrent.Semaphore
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Posts a Message to this Handler and blocks the calling Thread until the Handler finished executing the given job.
|
|
||||||
*/
|
|
||||||
fun Handler.postAndWait(job: () -> Unit) {
|
|
||||||
val semaphore = Semaphore(0)
|
|
||||||
|
|
||||||
this.post {
|
|
||||||
try {
|
|
||||||
job()
|
|
||||||
} finally {
|
|
||||||
semaphore.release()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
semaphore.acquire()
|
|
||||||
}
|
|
@ -15,9 +15,6 @@ fun List<Size>.closestToOrMax(size: Size?): Size {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotate by a given Surface Rotation
|
|
||||||
*/
|
|
||||||
fun Size.rotated(surfaceRotation: Int): Size {
|
fun Size.rotated(surfaceRotation: Int): Size {
|
||||||
return when (surfaceRotation) {
|
return when (surfaceRotation) {
|
||||||
Surface.ROTATION_0 -> Size(width, height)
|
Surface.ROTATION_0 -> Size(width, height)
|
||||||
|
@ -3,8 +3,7 @@ package com.mrousavy.camera.extensions
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
||||||
// React does not trigger onLayout events for dynamically added views (`addView`).
|
// React does not trigger onLayout events for dynamically added views (`addView`). This fixes that.
|
||||||
// This fixes that.
|
|
||||||
// https://github.com/facebook/react-native/issues/17968#issuecomment-633308615
|
// https://github.com/facebook/react-native/issues/17968#issuecomment-633308615
|
||||||
fun ViewGroup.installHierarchyFitter() {
|
fun ViewGroup.installHierarchyFitter() {
|
||||||
setOnHierarchyChangeListener(object : ViewGroup.OnHierarchyChangeListener {
|
setOnHierarchyChangeListener(object : ViewGroup.OnHierarchyChangeListener {
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package com.mrousavy.camera.extensions
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.WritableMap
|
|
||||||
|
|
||||||
fun WritableMap.putInt(key: String, value: Int?) {
|
|
||||||
if (value == null)
|
|
||||||
this.putNull(key)
|
|
||||||
else
|
|
||||||
this.putInt(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun WritableMap.putDouble(key: String, value: Double?) {
|
|
||||||
if (value == null)
|
|
||||||
this.putNull(key)
|
|
||||||
else
|
|
||||||
this.putDouble(key, value)
|
|
||||||
}
|
|
@ -74,9 +74,7 @@ class VisionCameraProxy(context: ReactApplicationContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// private C++ funcs
|
// private C++ funcs
|
||||||
private external fun initHybrid(
|
private external fun initHybrid(jsContext: Long,
|
||||||
jsContext: Long,
|
|
||||||
jsCallInvokerHolder: CallInvokerHolderImpl,
|
jsCallInvokerHolder: CallInvokerHolderImpl,
|
||||||
scheduler: VisionCameraScheduler
|
scheduler: VisionCameraScheduler): HybridData
|
||||||
): HybridData
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user