兼容 IOS
This commit is contained in:
@@ -225,11 +225,13 @@ class RecordingCameraController(
|
|||||||
|
|
||||||
fun zoomCapabilitiesMap(): Map<String, Any> {
|
fun zoomCapabilitiesMap(): Map<String, Any> {
|
||||||
val zoomState = camera?.cameraInfo?.zoomState?.value
|
val zoomState = camera?.cameraInfo?.zoomState?.value
|
||||||
|
val logicalMin = zoomState?.minZoomRatio ?: 1f
|
||||||
|
// 兜底两路超广角来源:独立超广角镜头(0.6) 与 逻辑相机原生 <1.0 变焦范围,取更小者。
|
||||||
val minZoom =
|
val minZoom =
|
||||||
if (hasUltraWideCamera()) {
|
if (hasUltraWideCamera()) {
|
||||||
ultraWideZoomRatio
|
minOf(ultraWideZoomRatio, logicalMin)
|
||||||
} else {
|
} else {
|
||||||
zoomState?.minZoomRatio ?: 1f
|
logicalMin
|
||||||
}
|
}
|
||||||
val maxZoom = zoomState?.maxZoomRatio ?: 3f
|
val maxZoom = zoomState?.maxZoomRatio ?: 3f
|
||||||
val zoom =
|
val zoom =
|
||||||
@@ -239,6 +241,11 @@ class RecordingCameraController(
|
|||||||
(zoomState?.zoomRatio ?: currentZoomRatio).coerceIn(minZoom, maxZoom)
|
(zoomState?.zoomRatio ?: currentZoomRatio).coerceIn(minZoom, maxZoom)
|
||||||
}
|
}
|
||||||
currentZoomRatio = zoom
|
currentZoomRatio = zoom
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"zoomCapabilities hasUltraWide=${hasUltraWideCamera()} logicalMin=$logicalMin " +
|
||||||
|
"ultraWideZoomRatio=$ultraWideZoomRatio minZoom=$minZoom maxZoom=$maxZoom zoom=$zoom",
|
||||||
|
)
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"zoomRatio" to zoom.toDouble(),
|
"zoomRatio" to zoom.toDouble(),
|
||||||
"minZoomRatio" to minZoom.toDouble(),
|
"minZoomRatio" to minZoom.toDouble(),
|
||||||
@@ -385,6 +392,11 @@ class RecordingCameraController(
|
|||||||
|
|
||||||
val mainProfile = excludedCameraId?.let { backCameraProfile(manager, it) }
|
val mainProfile = excludedCameraId?.let { backCameraProfile(manager, it) }
|
||||||
val widest = candidates.firstOrNull() ?: return null
|
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) {
|
if (mainProfile == null) {
|
||||||
return UltraWideCamera(widest.cameraId, DEFAULT_ULTRA_WIDE_ZOOM_RATIO)
|
return UltraWideCamera(widest.cameraId, DEFAULT_ULTRA_WIDE_ZOOM_RATIO)
|
||||||
}
|
}
|
||||||
@@ -392,6 +404,11 @@ class RecordingCameraController(
|
|||||||
val meaningfullyWider =
|
val meaningfullyWider =
|
||||||
widest.horizontalFov > mainProfile.horizontalFov * ULTRA_WIDE_FOV_FACTOR ||
|
widest.horizontalFov > mainProfile.horizontalFov * ULTRA_WIDE_FOV_FACTOR ||
|
||||||
widest.minFocalLength < mainProfile.minFocalLength * ULTRA_WIDE_FOCAL_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) {
|
if (!meaningfullyWider) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -564,7 +581,8 @@ class RecordingCameraController(
|
|||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "RecordingCamera"
|
private const val TAG = "RecordingCamera"
|
||||||
private const val DEFAULT_ULTRA_WIDE_ZOOM_RATIO = 0.6f
|
private const val DEFAULT_ULTRA_WIDE_ZOOM_RATIO = 0.6f
|
||||||
private const val ULTRA_WIDE_FOV_FACTOR = 1.08
|
// 适度放宽判定宽容度,覆盖更多机型(更小的 FOV/焦距差异也视为超广角)。
|
||||||
private const val ULTRA_WIDE_FOCAL_FACTOR = 0.92
|
private const val ULTRA_WIDE_FOV_FACTOR = 1.04
|
||||||
|
private const val ULTRA_WIDE_FOCAL_FACTOR = 0.96
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
buildServer.json
Normal file
19
buildServer.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
@@ -336,7 +336,9 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
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()
|
try device.lockForConfiguration()
|
||||||
device.videoZoomFactor = nextZoom
|
device.videoZoomFactor = nextZoom
|
||||||
device.unlockForConfiguration()
|
device.unlockForConfiguration()
|
||||||
@@ -427,11 +429,7 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard
|
guard let videoDevice = Self.preferredVideoDevice() else {
|
||||||
let videoDevice = AVCaptureDevice.default(
|
|
||||||
.builtInWideAngleCamera, for: .video, position: .back)
|
|
||||||
?? AVCaptureDevice.default(for: .video)
|
|
||||||
else {
|
|
||||||
throw NSError(
|
throw NSError(
|
||||||
domain: "RecordingCamera", code: 1,
|
domain: "RecordingCamera", code: 1,
|
||||||
userInfo: [NSLocalizedDescriptionKey: "No camera device available"])
|
userInfo: [NSLocalizedDescriptionKey: "No camera device available"])
|
||||||
@@ -461,10 +459,39 @@ private final class RecordingCameraController: NSObject, AVCaptureFileOutputReco
|
|||||||
session.commitConfiguration()
|
session.commitConfiguration()
|
||||||
|
|
||||||
configured = true
|
configured = true
|
||||||
|
// 默认以主摄(显示 1.0x)开场:虚拟多摄设备里主摄对应的 zoomFactor 是 S。
|
||||||
|
currentZoomRatio = mainBaselineFactor(for: videoDevice)
|
||||||
try applyCurrentZoom()
|
try applyCurrentZoom()
|
||||||
try configureAudioInput(enabled: withAudio)
|
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] {
|
private func currentZoomCapabilitiesMap() -> [String: Any] {
|
||||||
guard let device = videoInput?.device else {
|
guard let device = videoInput?.device else {
|
||||||
return [
|
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 minZoom = device.minAvailableVideoZoomFactor
|
||||||
let maxZoom = device.maxAvailableVideoZoomFactor
|
let maxZoom = device.maxAvailableVideoZoomFactor
|
||||||
let zoom = clampedZoomRatio(device.videoZoomFactor, for: device)
|
let zoom = clampedZoomRatio(device.videoZoomFactor, for: device)
|
||||||
currentZoomRatio = zoom
|
currentZoomRatio = zoom
|
||||||
return [
|
return [
|
||||||
"zoomRatio": Double(zoom),
|
"zoomRatio": Double(zoom / baseline),
|
||||||
"minZoomRatio": Double(minZoom),
|
"minZoomRatio": Double(minZoom / baseline),
|
||||||
"maxZoomRatio": Double(maxZoom),
|
"maxZoomRatio": Double(maxZoom / baseline),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user