This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

chore: android use wide angle camera

+58 -4
+1 -1
posedetection/build.gradle.kts
··· 6 6 7 7 mavenPublishing { 8 8 publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) 9 - coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.5.1") 9 + coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.6.0") 10 10 11 11 pom { 12 12 name.set("Pose Detection")
+57 -3
posedetection/src/androidMain/kotlin/com.performancecoachlab/posedetection/camera/CameraView.android.kt
··· 55 55 import kotlinx.coroutines.launch 56 56 import org.tensorflow.lite.support.image.TensorImage 57 57 import org.tensorflow.lite.task.vision.detector.ObjectDetector 58 + import android.hardware.camera2.CameraCharacteristics 59 + import androidx.camera.camera2.interop.Camera2CameraInfo 60 + import androidx.camera.core.CameraInfo 61 + import androidx.camera.core.CameraSelector 62 + import co.touchlab.kermit.Logger 58 63 59 64 // Data class to hold recording state for each recording ID 60 65 data class RecordingSlot( ··· 62 67 var firstTimestampMs: Long? = null, 63 68 val outputPath: String 64 69 ) 70 + 71 + private fun buildBackUltraWideSelectorOrNull(cameraProvider: ProcessCameraProvider): CameraSelector? { 72 + return try { 73 + val bestBackInfo: CameraInfo? = cameraProvider.availableCameraInfos 74 + .asSequence() 75 + .filter { info -> 76 + Camera2CameraInfo.from(info) 77 + .getCameraCharacteristic(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK 78 + } 79 + .mapNotNull { info -> 80 + val focalLengths: FloatArray? = Camera2CameraInfo.from(info) 81 + .getCameraCharacteristic(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) 82 + val minFocal = focalLengths?.minOrNull() 83 + if (minFocal != null) info to minFocal else null 84 + } 85 + // Smallest focal length => widest FOV (ultra-wide on multi-cam devices) 86 + .minByOrNull { (_, minFocal) -> minFocal } 87 + ?.first 88 + 89 + bestBackInfo?.let { selectedInfo -> 90 + CameraSelector.Builder() 91 + .addCameraFilter { cameraInfos -> 92 + // Defensive: ensure we ONLY ever return a back-facing camera. 93 + cameraInfos.filter { candidate -> 94 + candidate == selectedInfo && 95 + Camera2CameraInfo.from(candidate) 96 + .getCameraCharacteristic(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK 97 + } 98 + } 99 + .build() 100 + } 101 + } catch (t: Throwable) { 102 + Logger.w(t) { "Failed to select ultra-wide back camera, falling back to default back." } 103 + null 104 + } 105 + } 65 106 66 107 @OptIn(ExperimentalGetImage::class) 67 108 @Composable ··· 193 234 194 235 } 195 236 196 - LaunchedEffect(lifecycleOwner) { 237 + LaunchedEffect(lifecycleOwner, frontCamera) { 197 238 val cameraProvider = ProcessCameraProvider.getInstance(context).get() 198 239 cameraProvider.unbindAll() 199 - val cameraSelector = if (frontCamera) DEFAULT_FRONT_CAMERA else DEFAULT_BACK_CAMERA 240 + 241 + val cameraSelector = if (frontCamera) { 242 + DEFAULT_FRONT_CAMERA 243 + } else { 244 + buildBackUltraWideSelectorOrNull(cameraProvider) ?: DEFAULT_BACK_CAMERA 245 + } 246 + 200 247 val preview = Preview.Builder().build().also { 201 248 it.surfaceProvider = previewView.surfaceProvider 202 249 } ··· 234 281 } 235 282 } 236 283 } 237 - cameraProvider.bindToLifecycle( 284 + val camera = cameraProvider.bindToLifecycle( 238 285 lifecycleOwner, 239 286 cameraSelector, 240 287 preview, 241 288 imageAnalysis 242 289 ) 290 + 291 + // Helpful debug: see which physical camera ID CameraX picked. 292 + runCatching { 293 + val cameraId = Camera2CameraInfo.from(camera.cameraInfo).cameraId 294 + Logger.d { "CameraX bound cameraId=$cameraId frontCamera=$frontCamera" } 295 + } 296 + 243 297 previewView.scaleType = PreviewView.ScaleType.FIT_CENTER 244 298 } 245 299 Box(