feat: Implement focus()
on Android (#2523)
* feat: Implement `focus()` on Android * Throw if not supported * Do focus in example * Format * fix: Properly convert layer point to camera coordinates * Fix * Set trigger back to IDLE * Fix rotation maybe? * Rotated by * fix: Fix display point calculation * Try other * Invoke `capture` callback on same thread * Center metering rectangle * Reset AF Trigger to IDLE * Reset it to it's default AF mode again, i dont even know anymore * Update CameraPage.tsx * Format * Apply options to repeating * Set * Use scene mode * Update CameraPage.tsx * Update CameraDeviceDetails.kt * It fucking works * Update PersistentCameraCaptureSession.kt * Update PersistentCameraCaptureSession.kt * Update PersistentCameraCaptureSession.kt * Create CameraCaptureSession+setRepeatingRequestAndWait.kt * Oh my god it works * Also focus AE * Cancel reset request * Rename to AF * Format * Update PersistentCameraCaptureSession.kt
This commit is contained in:
@@ -5,7 +5,6 @@ import android.hardware.camera2.CaptureFailure
|
||||
import android.hardware.camera2.CaptureRequest
|
||||
import android.hardware.camera2.TotalCaptureResult
|
||||
import android.media.MediaActionSound
|
||||
import com.mrousavy.camera.core.CameraQueues
|
||||
import com.mrousavy.camera.core.CaptureAbortedError
|
||||
import com.mrousavy.camera.core.UnknownCaptureError
|
||||
import kotlin.coroutines.resume
|
||||
@@ -23,29 +22,36 @@ suspend fun CameraCaptureSession.capture(captureRequest: CaptureRequest, enableS
|
||||
override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
|
||||
super.onCaptureCompleted(session, request, result)
|
||||
|
||||
continuation.resume(result)
|
||||
shutterSound?.release()
|
||||
if (request == captureRequest) {
|
||||
continuation.resume(result)
|
||||
shutterSound?.release()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCaptureStarted(session: CameraCaptureSession, request: CaptureRequest, timestamp: Long, frameNumber: Long) {
|
||||
super.onCaptureStarted(session, request, timestamp, frameNumber)
|
||||
|
||||
if (enableShutterSound) {
|
||||
shutterSound?.play(MediaActionSound.SHUTTER_CLICK)
|
||||
if (request == captureRequest) {
|
||||
if (enableShutterSound) {
|
||||
shutterSound?.play(MediaActionSound.SHUTTER_CLICK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCaptureFailed(session: CameraCaptureSession, request: CaptureRequest, failure: CaptureFailure) {
|
||||
super.onCaptureFailed(session, request, failure)
|
||||
val wasImageCaptured = failure.wasImageCaptured()
|
||||
val error = when (failure.reason) {
|
||||
CaptureFailure.REASON_ERROR -> UnknownCaptureError(wasImageCaptured)
|
||||
CaptureFailure.REASON_FLUSHED -> CaptureAbortedError(wasImageCaptured)
|
||||
else -> UnknownCaptureError(wasImageCaptured)
|
||||
|
||||
if (request == captureRequest) {
|
||||
val wasImageCaptured = failure.wasImageCaptured()
|
||||
val error = when (failure.reason) {
|
||||
CaptureFailure.REASON_ERROR -> UnknownCaptureError(wasImageCaptured)
|
||||
CaptureFailure.REASON_FLUSHED -> CaptureAbortedError(wasImageCaptured)
|
||||
else -> UnknownCaptureError(wasImageCaptured)
|
||||
}
|
||||
continuation.resumeWithException(error)
|
||||
}
|
||||
continuation.resumeWithException(error)
|
||||
}
|
||||
},
|
||||
CameraQueues.cameraQueue.handler
|
||||
null
|
||||
)
|
||||
}
|
||||
|
@@ -0,0 +1,47 @@
|
||||
package com.mrousavy.camera.extensions
|
||||
|
||||
import android.hardware.camera2.CameraCaptureSession
|
||||
import android.hardware.camera2.CaptureFailure
|
||||
import android.hardware.camera2.CaptureRequest
|
||||
import android.hardware.camera2.CaptureResult
|
||||
import android.hardware.camera2.TotalCaptureResult
|
||||
import android.util.Log
|
||||
import com.mrousavy.camera.core.CaptureAbortedError
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
private const val TAG = "CameraCaptureSession"
|
||||
|
||||
/**
|
||||
* Set a new repeating request for the [CameraCaptureSession] that contains an AF trigger, and wait until AF has locked.
|
||||
*/
|
||||
suspend fun CameraCaptureSession.setRepeatingRequestAndWaitForAF(request: CaptureRequest) =
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
this.setRepeatingRequest(
|
||||
request,
|
||||
object : CameraCaptureSession.CaptureCallback() {
|
||||
override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
|
||||
super.onCaptureCompleted(session, request, result)
|
||||
|
||||
if (continuation.isActive) {
|
||||
val afState = result.get(CaptureResult.CONTROL_AF_STATE)
|
||||
Log.i(TAG, "AF State: $afState")
|
||||
if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
|
||||
continuation.resume(Unit)
|
||||
session.setRepeatingRequest(request, null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onCaptureFailed(session: CameraCaptureSession, request: CaptureRequest, failure: CaptureFailure) {
|
||||
super.onCaptureFailed(session, request, failure)
|
||||
|
||||
if (continuation.isActive) {
|
||||
continuation.resumeWithException(CaptureAbortedError(failure.wasImageCaptured()))
|
||||
session.setRepeatingRequest(request, null, null)
|
||||
}
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
}
|
@@ -2,7 +2,7 @@ package com.mrousavy.camera.extensions
|
||||
|
||||
import android.util.Size
|
||||
import android.util.SizeF
|
||||
import android.view.Surface
|
||||
import com.mrousavy.camera.types.Orientation
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
@@ -14,13 +14,10 @@ fun List<Size>.closestToOrMax(size: Size?): Size =
|
||||
this.maxBy { it.width * it.height }
|
||||
}
|
||||
|
||||
fun Size.rotated(surfaceRotation: Int): Size =
|
||||
when (surfaceRotation) {
|
||||
Surface.ROTATION_0 -> Size(width, height)
|
||||
Surface.ROTATION_90 -> Size(height, width)
|
||||
Surface.ROTATION_180 -> Size(width, height)
|
||||
Surface.ROTATION_270 -> Size(height, width)
|
||||
else -> Size(width, height)
|
||||
fun Size.rotatedBy(orientation: Orientation): Size =
|
||||
when (orientation) {
|
||||
Orientation.PORTRAIT, Orientation.PORTRAIT_UPSIDE_DOWN -> this
|
||||
Orientation.LANDSCAPE_LEFT, Orientation.LANDSCAPE_RIGHT -> Size(height, width)
|
||||
}
|
||||
|
||||
val Size.bigger: Int
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.mrousavy.camera.extensions
|
||||
|
||||
import android.util.Log
|
||||
import android.view.SurfaceHolder
|
||||
import androidx.annotation.UiThread
|
||||
import kotlin.coroutines.resume
|
||||
@@ -15,14 +16,18 @@ suspend fun SurfaceHolder.resize(width: Int, height: Int) {
|
||||
return@suspendCancellableCoroutine
|
||||
}
|
||||
|
||||
Log.i("SurfaceHolder", "Resizing SurfaceHolder to $width x $height...")
|
||||
|
||||
val callback = object : SurfaceHolder.Callback {
|
||||
override fun surfaceCreated(holder: SurfaceHolder) = Unit
|
||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||
holder.removeCallback(this)
|
||||
Log.i("SurfaceHolder", "Resized SurfaceHolder to $width x $height!")
|
||||
continuation.resume(Unit)
|
||||
}
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
holder.removeCallback(this)
|
||||
Log.e("SurfaceHolder", "Failed to resize SurfaceHolder to $width x $height!")
|
||||
continuation.cancel(Error("Tried to resize SurfaceView, but Surface has been destroyed!"))
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user