4

我为使用 AVFoundation 实现的自定义相机提供了缩放功能(1x 以上)。这在 iPhone X 型号之前都很好。但我想在 iPhone 11 和 iPhone 11 Pro 设备上实现 0.5 倍变焦。

我编写的代码无法将其设置为 0.5 倍缩放。我已经尝试了所有可能的组合[.builtInTripleCamera, .builtInDualWideCamera, .builtInUltraWideCamera]。具有设备类型的捕获设备.builtinUltraWideCamera未提供 0.5 的minAvailableVideoZoomFactor.

在 iPhone 11 上进行测试时,我还[.builtInDualCamera, .builtInTelephotoCamera, .builtInWideAngleCamera, .builtInTrueDepthCamera]deviceTypes.

感谢任何帮助解决这个问题。下面是适用于 1 倍放大的代码。

/// Called from -handlePinchGesture
private func zoom(_ scale: CGFloat) {
    let captureDevice = cameraDevice(.back)
            
    do {
        try captureDevice?.lockForConfiguration()

        var minZoomFactor: CGFloat = captureDevice?.minAvailableVideoZoomFactor ?? 1.0
        let maxZoomFactor: CGFloat = captureDevice?.maxAvailableVideoZoomFactor ?? 1.0
        
        if #available(iOS 13.0, *) {
            if captureDevice?.deviceType == .builtInDualWideCamera || captureDevice?.deviceType == .builtInTripleCamera || captureDevice?.deviceType == .builtInUltraWideCamera {
                minZoomFactor = 0.5
            }
        }
        zoomScale = max(minZoomFactor, min(beginZoomScale * scale, maxZoomFactor))
        captureDevice?.videoZoomFactor = zoomScale

        captureDevice?.unlockForConfiguration()
    } catch {
        print("ERROR: locking configuration")
    }
}

@objc private func handlePinchGesture(_ recognizer: UIPinchGestureRecognizer) {
    var allTouchesOnPreviewLayer = true
    let numTouch = recognizer.numberOfTouches
    
    for i in 0 ..< numTouch {
        let location = recognizer.location(ofTouch: i, in: view)
        let convertedTouch = previewLayer.convert(location, from: previewLayer.superlayer)
        if !previewLayer.contains(convertedTouch) {
            allTouchesOnPreviewLayer = false
            break
        }
    }
    if allTouchesOnPreviewLayer {
        zoom(recognizer.scale)
    }
}

func cameraDevice(_ position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    var deviceTypes = [AVCaptureDevice.DeviceType]()
    deviceTypes.append(contentsOf: [.builtInDualCamera, .builtInTelephotoCamera, .builtInWideAngleCamera, .builtInTrueDepthCamera])
    
    if #available(iOS 13.0, *) {
        deviceTypes.append(contentsOf: [.builtInTripleCamera, .builtInDualWideCamera, .builtInUltraWideCamera])
    }

    let availableCameraDevices = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: .video, position: position).devices

    guard availableCameraDevices.isEmpty == false else {
        debugPrint("ERROR: No camera devices found!!!")
        return nil
    }

    for device in availableCameraDevices {
        if device.position == position {
            return device
        }
    }

    guard let defaultDevice = AVCaptureDevice.default(for: AVMediaType.video) else {
        debugPrint("ERROR: Can't initialize default back camera!!!")
        return nil
    }
    return defaultDevice
}
4

4 回答 4

0

问题是当您尝试从中获取某种类型的设备时,discoverySession.devices它会返回默认设备,该设备不支持您需要的超宽。

我的 iPhone 12Pro Max 就是这种情况,只返回一个设备用于返回位置,报告类型BuiltInWideAngleCamera,但这只是碱液,它是中置摄像头,不是广角,不是长焦。不知道为什么苹果开发人员会这样做,看起来像是一个过时的遗留架构。

解决方案并不明显:用于AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back)获得能够从 1 缩放的真实设备(您的逻辑 0.5)。

于 2021-05-31T09:24:37.127 回答
0

为希望将光学变焦级别设置为 0.5 倍的人进行更新

礼貌:https ://github.com/NextLevel/NextLevel/issues/187

public class func primaryVideoDevice(forPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    
    // -- Changes begun
    if #available(iOS 13.0, *) {

        let hasUltraWideCamera: Bool = true // Set this variable to true if your device is one of the following - iPhone 11, iPhone 11 Pro, & iPhone 11 Pro Max
        
        if hasUltraWideCamera {

            // Your iPhone has UltraWideCamera.
            let deviceTypes: [AVCaptureDevice.DeviceType] = [AVCaptureDevice.DeviceType.builtInUltraWideCamera]
            let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: AVMediaType.video, position: position)
            return discoverySession.devices.first
            
        }
        
    }
    // -- Changes end
    

    var deviceTypes: [AVCaptureDevice.DeviceType] = [AVCaptureDevice.DeviceType.builtInWideAngleCamera] // builtInWideAngleCamera // builtInUltraWideCamera
    if #available(iOS 11.0, *) {
        deviceTypes.append(.builtInDualCamera)
    } else {
        deviceTypes.append(.builtInDuoCamera)
    }
    
    // prioritize duo camera systems before wide angle
    let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: AVMediaType.video, position: position)
    for device in discoverySession.devices {
        if #available(iOS 11.0, *) {
            if (device.deviceType == AVCaptureDevice.DeviceType.builtInDualCamera) {
                return device
            }
        } else {
            if (device.deviceType == AVCaptureDevice.DeviceType.builtInDuoCamera) {
                return device
            }
        }
    }
    
    return discoverySession.devices.first
    
}
于 2020-12-09T12:45:43.423 回答
0

根据Apple Docs,AVCaptureDevice 的最小“zoomFactor”属性不能小于 1.0 。这有点令人困惑,因为根据您选择的相机,变焦系数为 1 将是不同的视野或光学视角。默认的 iPhone 相机应用程序显示标签为“0.5”,但这只是超广角镜头相对于标准相机变焦系数的标签。

您已经从设备中获取了 minZoomFactor(可能为 1),因此您应该使用正在读取的设备的最小值和最大值来设置您输入到“captureDevice.videoZoomFactor”中的因子的范围。然后,当您选择超广角镜头时,将变焦因子设置为 1 将尽可能宽!(相对于标准镜头的视场为 0.5 倍)。

于 2021-04-04T22:06:58.527 回答
0

我们不能将缩放因子设置为小于 1。

我通过使用“.builtInDualWideCamera”解决了这个问题。

在这种情况下,我们使用“超广角相机”,其缩放系数 2.0(将是默认值)等于“广角相机”上的正常缩放系数。(最小值为 1.0)

如果您的 iPhone 不支持“.builtInDualWideCamera”,我们将照常使用“.builtInWideAngleCamera”,缩放系数为 1.0(最小值)

 func getCameraDevices() -> [AVCaptureDevice] {
        var deviceTypes = [AVCaptureDevice.DeviceType]()
   
        if #available(iOS 13.0, *) {
            deviceTypes.append(contentsOf: [.builtInDualWideCamera])
            self.isUltraWideCamera = true
            self.defaultZoomFactor = 2.0
        }
        
        if(deviceTypes.isEmpty){
            deviceTypes.append(contentsOf: [.builtInWideAngleCamera])
            self.isUltraWideCamera = false
            self.defaultZoomFactor = 1.0
        }

        return AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: .video, position: .unspecified).devices
    }
于 2021-11-03T09:15:02.567 回答