I’m trying to understand why videoZoomFactor
is enlarging the image by different amounts based on whether I use builtInTripleCamera
or builtInUltraWideCamera
on my iPhone 16 Pro:
Here’s my setup code:
var singleLensCamera: AVCaptureDevice.DeviceType = .builtInWideAngleCamera
var currentDeviceCamera: AVCaptureDevice.DeviceType = .builtInWideAngleCamera
var combinedLensCamera: AVCaptureDevice.DeviceType?
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(
deviceTypes: [ .builtInWideAngleCamera, .builtInUltraWideCamera, .builtInTelephotoCamera, .builtInTripleCamera, .builtInDualCamera, .builtInDualWideCamera ],
mediaType: .video,
position: .back
)
let avCaptureDevices = deviceDiscoverySession.devices.map { $0.deviceType }
if avCaptureDevices.contains(.builtInTripleCamera) {
combinedLensCamera = .builtInTripleCamera
} else if avCaptureDevices.contains(.builtInDualWideCamera) {
combinedLensCamera = .builtInDualWideCamera
} else if avCaptureDevices.contains(.builtInDualCamera) {
combinedLensCamera = .builtInDualCamera
}
combinedLensCamera = nil // use this to show the single camera, comment it out to see the combined camera
if avCaptureDevices.contains(.builtInUltraWideCamera) {
singleLensCamera = .builtInUltraWideCamera
} else {
singleLensCamera = .builtInWideAngleCamera
}
var deviceType: AVCaptureDevice.DeviceType {
if combinedLensCamera != nil { return combinedLensCamera! }
else { return singleLensCamera }
}
currentDeviceCamera = deviceType
let defaultVideoDevice = AVCaptureDevice.default(deviceType, for: .video, position: .back)
guard let videoDevice = defaultVideoDevice else {
print("^^Could not find any video device")
setupResult = .configurationFailed
return
}
do {
videoInput = try AVCaptureDeviceInput(device: videoDevice)
} catch {
print("^^Could not create video device input: \(error)")
setupResult = .configurationFailed
return
}
session.beginConfiguration()
session.sessionPreset = .photo
phoneCameraAOV = videoDevice.activeFormat.videoFieldOfView
print("^^phoneCameraAOV \(phoneCameraAOV)")
// Add a video input.
guard session.canAddInput(videoInput) else {
print("^^Could not add video device input to the session")
setupResult = .configurationFailed
sessionmitConfiguration()
return
}
session.addInput(videoInput)
// Add a video data output
if session.canAddOutput(videoDataOutput) {
session.addOutput(videoDataOutput)
videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)]
videoDataOutput.setSampleBufferDelegate(self, queue: dataOutputQueue)
} else {
print("^^Could not add video data output to the session")
setupResult = .configurationFailed
sessionmitConfiguration()
return
}
// Add photo output
if session.canAddOutput(photoOutput) {
session.addOutput(photoOutput)
photoOutput.isHighResolutionCaptureEnabled = true
} else {
print("^^Could not add photo output to the session")
setupResult = .configurationFailed
sessionmitConfiguration()
return
}
sessionmitConfiguration()
And here’s the zoom code:
let focalScaleFactor = 2.0
if let combinedLensCamera {
if let device = AVCaptureDevice.default(combinedLensCamera, for: .video, position: .back) {
try? device.lockForConfiguration()
device.videoZoomFactor = focalScaleFactor
device.unlockForConfiguration()
}
} else {
if let device = AVCaptureDevice.default(singleLensCamera, for: .video, position: .back) {
try? device.lockForConfiguration()
device.videoZoomFactor = focalScaleFactor
device.unlockForConfiguration()
}
When I set the scale factor to 1, both images are the same. And both report the same angle of view when I print videoDevice.activeFormat.videoFieldOfView
. But setting an amount greater than 1 results in the builtInUltraWideCamera
zooming further.
Here’s a project file if you want to try it yourself. Launch the app, see what it looks like, then uncomment line 214 of “CameraViewMetal.swift” and launch again.