diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt index cf2c02a..f9b3228 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt @@ -28,7 +28,6 @@ import com.mrousavy.camera.core.outputs.BarcodeScannerOutput import com.mrousavy.camera.core.outputs.PhotoOutput import com.mrousavy.camera.core.outputs.SurfaceOutput import com.mrousavy.camera.core.outputs.VideoPipelineOutput -import com.mrousavy.camera.extensions.bigger import com.mrousavy.camera.extensions.capture import com.mrousavy.camera.extensions.closestToOrMax import com.mrousavy.camera.extensions.createCaptureSession @@ -38,7 +37,6 @@ import com.mrousavy.camera.extensions.getPreviewTargetSize import com.mrousavy.camera.extensions.getVideoSizes import com.mrousavy.camera.extensions.openCamera import com.mrousavy.camera.extensions.setZoom -import com.mrousavy.camera.extensions.smaller import com.mrousavy.camera.frameprocessor.FrameProcessor import com.mrousavy.camera.types.Flash import com.mrousavy.camera.types.Orientation @@ -48,6 +46,7 @@ import com.mrousavy.camera.types.Torch import com.mrousavy.camera.types.VideoStabilizationMode import com.mrousavy.camera.utils.ImageFormatUtils import java.io.Closeable +import java.lang.IllegalStateException import java.util.concurrent.CancellationException import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope @@ -246,6 +245,8 @@ class CameraSession(private val context: Context, private val cameraManager: Cam private fun destroyPreviewOutputSync() { Log.i(TAG, "Destroying Preview Output...") + // This needs to run synchronously because after this method returns, the Preview Surface is no longer valid, + // and trying to use it will crash. This might result in a short UI Thread freeze though. runBlocking { configure { config -> config.preview = CameraConfiguration.Output.Disabled.create() @@ -379,12 +380,7 @@ class CameraSession(private val context: Context, private val cameraManager: Cam if (preview != null) { // Compute Preview Size based on chosen video size val videoSize = videoOutput?.size ?: format?.videoSize - val size = if (videoSize != null) { - val formatAspectRatio = videoSize.bigger.toDouble() / videoSize.smaller - characteristics.getPreviewTargetSize(formatAspectRatio) - } else { - characteristics.getPreviewTargetSize(null) - } + val size = characteristics.getPreviewTargetSize(videoSize) val enableHdr = video?.config?.enableHdr ?: false @@ -396,7 +392,8 @@ class CameraSession(private val context: Context, private val cameraManager: Cam enableHdr ) outputs.add(output) - previewView?.size = size + // Size is usually landscape, so we flip it here + previewView?.size = Size(size.height, size.width) } // CodeScanner Output @@ -520,7 +517,11 @@ class CameraSession(private val context: Context, private val cameraManager: Cam if (!config.isActive) { isRunning = false - captureSession?.stopRepeating() + try { + captureSession?.stopRepeating() + } catch (e: IllegalStateException) { + // ignore - captureSession is already closed. + } return } if (captureSession == null) { diff --git a/package/android/src/main/java/com/mrousavy/camera/core/PreviewView.kt b/package/android/src/main/java/com/mrousavy/camera/core/PreviewView.kt index 8cdb4c5..cfda57a 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/PreviewView.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/PreviewView.kt @@ -19,8 +19,8 @@ class PreviewView(context: Context, callback: SurfaceHolder.Callback) : SurfaceV set(value) { field = value UiThreadUtil.runOnUiThread { - Log.i(TAG, "Resizing PreviewView to ${value.width} x ${value.height}...") - holder.setFixedSize(value.width, value.height) + Log.i(TAG, "Setting PreviewView Surface Size to $width x $height...") + holder.setFixedSize(value.height, value.width) requestLayout() invalidate() } @@ -44,20 +44,10 @@ class PreviewView(context: Context, callback: SurfaceHolder.Callback) : SurfaceV holder.addCallback(callback) } - /*fun resizeToInputCamera(cameraId: String, cameraManager: CameraManager, format: CameraDeviceFormat?) { - val characteristics = cameraManager.getCameraCharacteristics(cameraId) - - val targetPreviewSize = format?.videoSize - val formatAspectRatio = if (targetPreviewSize != null) targetPreviewSize.bigger.toDouble() / targetPreviewSize.smaller else null - size = characteristics.getPreviewTargetSize(formatAspectRatio) - }*/ - private fun getSize(contentSize: Size, containerSize: Size, resizeMode: ResizeMode): Size { - val contentAspectRatio = contentSize.height.toDouble() / contentSize.width + val contentAspectRatio = contentSize.width.toDouble() / contentSize.height val containerAspectRatio = containerSize.width.toDouble() / containerSize.height - Log.i(TAG, "Content Size: $contentSize ($contentAspectRatio) | Container Size: $containerSize ($containerAspectRatio)") - val widthOverHeight = when (resizeMode) { ResizeMode.COVER -> contentAspectRatio > containerAspectRatio ResizeMode.CONTAIN -> contentAspectRatio < containerAspectRatio diff --git a/package/android/src/main/java/com/mrousavy/camera/extensions/CameraCharacteristics+getPreviewSize.kt b/package/android/src/main/java/com/mrousavy/camera/extensions/CameraCharacteristics+getPreviewSize.kt index e7bda50..e758c45 100644 --- a/package/android/src/main/java/com/mrousavy/camera/extensions/CameraCharacteristics+getPreviewSize.kt +++ b/package/android/src/main/java/com/mrousavy/camera/extensions/CameraCharacteristics+getPreviewSize.kt @@ -4,13 +4,12 @@ import android.content.res.Resources import android.hardware.camera2.CameraCharacteristics import android.util.Size import android.view.SurfaceHolder -import kotlin.math.abs fun getMaximumPreviewSize(): Size { // See https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap // According to the Android Developer documentation, PREVIEW streams can have a resolution // of up to the phone's display's resolution, with a maximum of 1920x1080. - val display1080p = Size(1920, 1080) + val display1080p = Size(1080, 1920) val displaySize = Size( Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels @@ -20,28 +19,11 @@ fun getMaximumPreviewSize(): Size { return if (isHighResScreen) display1080p else displaySize } -fun CameraCharacteristics.getPreviewSizeFromAspectRatio(aspectRatio: Double): Size { +fun CameraCharacteristics.getPreviewTargetSize(targetSize: Size?): Size { val config = this.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!! val maximumPreviewSize = getMaximumPreviewSize() val outputSizes = config.getOutputSizes(SurfaceHolder::class.java) - .sortedByDescending { it.width * it.height } - .sortedBy { abs(aspectRatio - (it.bigger.toDouble() / it.smaller)) } + .filter { it.bigger <= maximumPreviewSize.bigger && it.smaller <= maximumPreviewSize.smaller } - return outputSizes.first { it.bigger <= maximumPreviewSize.bigger && it.smaller <= maximumPreviewSize.smaller } + return outputSizes.closestToOrMax(targetSize) } - -fun CameraCharacteristics.getAutomaticPreviewSize(): Size { - val config = this.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!! - val maximumPreviewSize = getMaximumPreviewSize() - val outputSizes = config.getOutputSizes(SurfaceHolder::class.java) - .sortedByDescending { it.width * it.height } - - return outputSizes.first { it.bigger <= maximumPreviewSize.bigger && it.smaller <= maximumPreviewSize.smaller } -} - -fun CameraCharacteristics.getPreviewTargetSize(aspectRatio: Double?): Size = - if (aspectRatio != null) { - getPreviewSizeFromAspectRatio(aspectRatio) - } else { - getAutomaticPreviewSize() - } diff --git a/package/android/src/main/java/com/mrousavy/camera/extensions/Size+Extensions.kt b/package/android/src/main/java/com/mrousavy/camera/extensions/Size+Extensions.kt index 1fb798e..b9664c5 100644 --- a/package/android/src/main/java/com/mrousavy/camera/extensions/Size+Extensions.kt +++ b/package/android/src/main/java/com/mrousavy/camera/extensions/Size+Extensions.kt @@ -9,7 +9,7 @@ import kotlin.math.min fun List.closestToOrMax(size: Size?): Size = if (size != null) { - this.minBy { abs(it.width - size.width) + abs(it.height - size.height) } + this.minBy { abs((it.width * it.height) - (size.width * size.height)) } } else { this.maxBy { it.width * it.height } } diff --git a/package/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessor.java b/package/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessor.java index ec9501a..d32de78 100644 --- a/package/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessor.java +++ b/package/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessor.java @@ -10,7 +10,6 @@ import com.facebook.proguard.annotations.DoNotStrip; /** * Represents a JS Frame Processor */ -@SuppressWarnings("JavaJniMissingFunction") // we're using fbjni. public final class FrameProcessor { /** * Call the JS Frame Processor function with the given Frame diff --git a/package/example/android/gradle.properties b/package/example/android/gradle.properties index c0a2f65..7f078ce 100644 --- a/package/example/android/gradle.properties +++ b/package/example/android/gradle.properties @@ -42,4 +42,4 @@ hermesEnabled=true # Can be set to true to disable the build setup #VisionCamera_disableFrameProcessors=true # Can be set to true to include the full 2.4 MB MLKit dependency -#VisionCamera_enableCodeScanner=true +VisionCamera_enableCodeScanner=true