diff --git a/android/app/src/main/kotlin/com/dronex/rec/recording/RecordingCameraController.kt b/android/app/src/main/kotlin/com/dronex/rec/recording/RecordingCameraController.kt index 44c1408..00f0d12 100644 --- a/android/app/src/main/kotlin/com/dronex/rec/recording/RecordingCameraController.kt +++ b/android/app/src/main/kotlin/com/dronex/rec/recording/RecordingCameraController.kt @@ -225,11 +225,13 @@ class RecordingCameraController( fun zoomCapabilitiesMap(): Map { val zoomState = camera?.cameraInfo?.zoomState?.value + val logicalMin = zoomState?.minZoomRatio ?: 1f + // 兜底两路超广角来源:独立超广角镜头(0.6) 与 逻辑相机原生 <1.0 变焦范围,取更小者。 val minZoom = if (hasUltraWideCamera()) { - ultraWideZoomRatio + minOf(ultraWideZoomRatio, logicalMin) } else { - zoomState?.minZoomRatio ?: 1f + logicalMin } val maxZoom = zoomState?.maxZoomRatio ?: 3f val zoom = @@ -239,6 +241,11 @@ class RecordingCameraController( (zoomState?.zoomRatio ?: currentZoomRatio).coerceIn(minZoom, maxZoom) } currentZoomRatio = zoom + Log.d( + TAG, + "zoomCapabilities hasUltraWide=${hasUltraWideCamera()} logicalMin=$logicalMin " + + "ultraWideZoomRatio=$ultraWideZoomRatio minZoom=$minZoom maxZoom=$maxZoom zoom=$zoom", + ) return mapOf( "zoomRatio" to zoom.toDouble(), "minZoomRatio" to minZoom.toDouble(), @@ -385,6 +392,11 @@ class RecordingCameraController( val mainProfile = excludedCameraId?.let { backCameraProfile(manager, it) } val widest = candidates.firstOrNull() ?: return null + val candidatesDesc = + candidates.joinToString { "id=${it.cameraId} fov=${it.horizontalFov} focal=${it.minFocalLength}" } + val mainDesc = + mainProfile?.let { "id=${it.cameraId} fov=${it.horizontalFov} focal=${it.minFocalLength}" } + Log.d(TAG, "ultraWide candidates=[$candidatesDesc] main=$mainDesc") if (mainProfile == null) { return UltraWideCamera(widest.cameraId, DEFAULT_ULTRA_WIDE_ZOOM_RATIO) } @@ -392,6 +404,11 @@ class RecordingCameraController( val meaningfullyWider = widest.horizontalFov > mainProfile.horizontalFov * ULTRA_WIDE_FOV_FACTOR || widest.minFocalLength < mainProfile.minFocalLength * ULTRA_WIDE_FOCAL_FACTOR + Log.d( + TAG, + "ultraWide decision widest=${widest.cameraId} meaningfullyWider=$meaningfullyWider " + + "(fovFactor=$ULTRA_WIDE_FOV_FACTOR focalFactor=$ULTRA_WIDE_FOCAL_FACTOR)", + ) if (!meaningfullyWider) { return null } @@ -564,7 +581,8 @@ class RecordingCameraController( companion object { private const val TAG = "RecordingCamera" private const val DEFAULT_ULTRA_WIDE_ZOOM_RATIO = 0.6f - private const val ULTRA_WIDE_FOV_FACTOR = 1.08 - private const val ULTRA_WIDE_FOCAL_FACTOR = 0.92 + // 适度放宽判定宽容度,覆盖更多机型(更小的 FOV/焦距差异也视为超广角)。 + private const val ULTRA_WIDE_FOV_FACTOR = 1.04 + private const val ULTRA_WIDE_FOCAL_FACTOR = 0.96 } } diff --git a/buildServer.json b/buildServer.json new file mode 100644 index 0000000..ea64bc0 --- /dev/null +++ b/buildServer.json @@ -0,0 +1,19 @@ +{ + "name": "xcode build server", + "version": "1.3.0", + "bspVersion": "2.2.0", + "languages": [ + "c", + "cpp", + "objective-c", + "objective-cpp", + "swift" + ], + "argv": [ + "/opt/homebrew/bin/xcode-build-server" + ], + "workspace": "/Users/ZhuanZ/Documents/gdfw/record-tool/ios/Runner.xcworkspace", + "build_root": "/Users/ZhuanZ/Library/Developer/Xcode/DerivedData/Runner-ckjfuyjdkgumnpbnnftroxddsppq", + "scheme": "Runner", + "kind": "xcode" +} \ No newline at end of file diff --git a/ios/Runner/RecordingPlugin.swift b/ios/Runner/RecordingPlugin.swift index a14b114..83b3353 100644 --- a/ios/Runner/RecordingPlugin.swift +++ b/ios/Runner/RecordingPlugin.swift @@ -336,7 +336,9 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco } do { - let nextZoom = self.clampedZoomRatio(ratio, for: device) + // 入参是显示倍率(1.0x = 主摄),按 S 基准换算回设备 zoomFactor。 + let baseline = self.mainBaselineFactor(for: device) + let nextZoom = self.clampedZoomRatio(ratio * baseline, for: device) try device.lockForConfiguration() device.videoZoomFactor = nextZoom device.unlockForConfiguration() @@ -427,11 +429,7 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco return } - guard - let videoDevice = AVCaptureDevice.default( - .builtInWideAngleCamera, for: .video, position: .back) - ?? AVCaptureDevice.default(for: .video) - else { + guard let videoDevice = Self.preferredVideoDevice() else { throw NSError( domain: "RecordingCamera", code: 1, userInfo: [NSLocalizedDescriptionKey: "No camera device available"]) @@ -461,10 +459,39 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco session.commitConfiguration() configured = true + // 默认以主摄(显示 1.0x)开场:虚拟多摄设备里主摄对应的 zoomFactor 是 S。 + currentZoomRatio = mainBaselineFactor(for: videoDevice) try applyCurrentZoom() try configureAudioInput(enabled: withAudio) } + /// 优先选用包含超广角的虚拟多摄设备,使 minAvailableVideoZoomFactor 能低于主摄(从而支持 0.6x)。 + private static func preferredVideoDevice() -> AVCaptureDevice? { + let preferredTypes: [AVCaptureDevice.DeviceType] = [ + .builtInTripleCamera, + .builtInDualWideCamera, + .builtInWideAngleCamera, + ] + for type in preferredTypes { + if let device = AVCaptureDevice.default(type, for: .video, position: .back) { + return device + } + } + return AVCaptureDevice.default(for: .video) + } + + /// 虚拟多摄设备中「主摄(显示 1.0x)」对应的设备 zoomFactor 基准 S。 + /// 取 ultra-wide → wide 的切换点;非虚拟设备无切换点时返回 1.0(向后兼容)。 + private func mainBaselineFactor(for device: AVCaptureDevice) -> CGFloat { + if let first = device.virtualDeviceSwitchOverVideoZoomFactors.first { + let value = CGFloat(truncating: first) + if value > 0 { + return value + } + } + return 1.0 + } + private func currentZoomCapabilitiesMap() -> [String: Any] { guard let device = videoInput?.device else { return [ @@ -474,14 +501,16 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco ] } + // 设备 zoomFactor 以 S 为基准换算成 App 使用的「显示倍率」(1.0x = 主摄)。 + let baseline = mainBaselineFactor(for: device) let minZoom = device.minAvailableVideoZoomFactor let maxZoom = device.maxAvailableVideoZoomFactor let zoom = clampedZoomRatio(device.videoZoomFactor, for: device) currentZoomRatio = zoom return [ - "zoomRatio": Double(zoom), - "minZoomRatio": Double(minZoom), - "maxZoomRatio": Double(maxZoom), + "zoomRatio": Double(zoom / baseline), + "minZoomRatio": Double(minZoom / baseline), + "maxZoomRatio": Double(maxZoom / baseline), ] }