如何使用AVCaptureDeviceDiscoverySession获取前置摄像头、后置摄像头和音频?

55
在iOS 10发布之前,我使用以下代码来获取视频和音频捕获以用于我的视频录制器:
 for device in AVCaptureDevice.devices()
 {
     if (device as AnyObject).hasMediaType( AVMediaTypeAudio )
     {
         self.audioCapture = device as? AVCaptureDevice
     }
     else if (device as AnyObject).hasMediaType( AVMediaTypeVideo )
     {
         if (device as AnyObject).position == AVCaptureDevicePosition.back
         {
             self.backCameraVideoCapture = device as? AVCaptureDevice
         }
         else
         {
             self.frontCameraVideoCapture = device as? AVCaptureDevice
         }
     }
 }
当iOS 10终于推出时,我在运行代码时收到了以下警告。请注意,我的视频录制器仍顺畅地工作了约2周。
“’devices ()’在iOS 10.0中已被弃用:请使用AVCaptureDeviceDiscoverySession。”
今天早上我运行代码时,我的视频录制器停止工作了。xCode8没有给我任何错误,但相机捕获的previewLayer完全是白色的。当我开始录制时,我收到以下错误:
“错误域= AVFoundationErrorDomain Code=-11800“操作无法完成”UserInfo={NSLocalizedDescription=操作无法完成,NSUnderlyingError=0x17554440 {错误域= NSOSStatusErrorDomain Code=-12780“(null)”},NSLocalizedFailureReason=发生未知错误(-12780)}”
我认为这与我使用已弃用的方法AVCaptureDevice.devices()有关。因此,我想知道如何改用AVCaptureDeviceDiscoverySession
提前感谢您的帮助!
12个回答

112

您可以通过以下方法获得前置摄像头:

AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front)

后置摄像头:

AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)

而麦克风:

AVCaptureDevice.default(.builtInMicrophone, for: AVMediaType.audio, position: .unspecified)

结果证明,我的iPhone相机坏了,因此在预览层中显示白色。尽管如此,还是谢谢您的答案,至少我可以摆脱Xcode8不断提醒我的警告。 - Andi
1
你知道如何使用Objective-C来使用后置摄像头做同样的事情吗? - fi12
1
似乎所有答案都使用.builtInWideAngleCamera作为设备类型。你能解释一下为什么要使用这种类型而不是其他许多类型吗?例如,还有.builtInDualWideCamera。使用你的代码是否仍会返回双广角相机? - ndreisg
1
@ndreisg,你可以在苹果的文档中找到答案:https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/choosing_a_capture_device - Ali Amin
@AliAmin 这个链接提供了获取最佳相机的最佳方法。附注:你应该在双摄像头之前添加三摄像头选项以获得最佳效果,因为该链接似乎有点过时。 - Mostafa ElShazly

14

这是我的代码(Swift 3)来获取摄像机位置:

// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found
func cameraWithPosition(_ position: AVCaptureDevicePosition) -> AVCaptureDevice?
{
    if let deviceDescoverySession = AVCaptureDeviceDiscoverySession.init(deviceTypes: [AVCaptureDeviceType.builtInWideAngleCamera],
                                                          mediaType: AVMediaTypeVideo,
                                                          position: AVCaptureDevicePosition.unspecified) {

        for device in deviceDescoverySession.devices {
            if device.position == position {
                return device
            }
        }
    }

    return nil
}

如果您想要,您也可以通过更改deviceTypes数组来获取iPhone 7+(双摄像头)的新deviceTypes。

这是一篇不错的阅读:https://forums.developer.apple.com/thread/63347


13

Swift 4、iOS 10+ 和 Xcode 10.1 取代了

if let cameraID = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)?.localizedName {
       //cameraID = "Front Camera"
}

使用 AVCaptureDevice.DiscoverySession 实现

if let cameraID = AVCaptureDevice.DiscoverySession.init(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: .video, position: .front).devices.first?.localizedName{
        //cameraID = "Front Camera"
} 

需要用 #available(iOS 10,*) 进行检查包装。


1
发现会话的代码现在应该是: if let cameraID = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.front).devices.first?.localizedName{ //cameraID = "Front Camera" } AVCaptureDeviceTypeAVCaptureDevice.DeviceType 取代,而 AVCaptureDevicePositionAVCaptureDevice.Position 取代(XCode 9.2 / Swift 4) - esco_
设备数组为空,您知道为什么吗? - Ricardo Ruiz Romero

9

3

示例:iOS 11 Swift 4

override func viewDidLoad() {
    super.viewDidLoad()

    // Get the back-facing camera for capturing videos

    // AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)
    let deviceDiscoverySession = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)

   guard let captureDevice = deviceDiscoverySession else {
       print("Failed to get the camera device")
       return
   }

    do {
        // Get an instance of the AVCaptureDeviceInput class using the previous device object.
        let input = try AVCaptureDeviceInput(device: captureDevice)

        // Set the input device on the capture session.
        captureSession.addInput(input)

    } catch {
        // If any error occurs, simply print it out and don't continue any more.
        print(error)
        return
    }

    // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
    videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    videoPreviewLayer?.frame = view.layer.bounds
    view.layer.addSublayer(videoPreviewLayer!)

    // Start video capture.
    captureSession.startRunning()

有没有人发现这个在10+手机上无法与最新的beta 11.3 SDK一起使用?这在我的手机上可以运行,但是在我的测试飞行测试者的手机上都无法创建视频预览层。 - justdan0227

3

Swift 3

选择后置摄像头:(根据需要可更改为 .back)

要选择另一个设备类型,只需将其添加到 [ ] 中 (例如:

[deviceTypeCamera, AVCaptureDeviceType.builtInMicrophone])

(或者像代码中的后置摄像头一样创建一个私有 let...)

 private let position = AVCaptureDevicePosition.back
 private let deviceTypeBackCamera = AVCaptureDeviceType.builtInWideAngleCamera

 private func selectCaptureDevice() -> AVCaptureDevice? {
    return AVCaptureDeviceDiscoverySession(deviceTypes: [deviceTypeBackCamera], mediaType: AVMediaTypeVideo, position: position).devices.first

 }

Xcode 9 刚刚要求我使用 __deviceTypes: 而不是 deviceTypes:,除此之外,它工作正常。 - epx

2

尝试使用以下代码获取相机ID:

NSString *cameraID = nil;

NSArray *captureDeviceType = @[AVCaptureDeviceTypeBuiltInWideAngleCamera];
AVCaptureDeviceDiscoverySession *captureDevice = 
              [AVCaptureDeviceDiscoverySession 
                discoverySessionWithDeviceTypes:captureDeviceType 
                mediaType:AVMediaTypeVideo 
                position:AVCaptureDevicePositionUnspecified];

cameraID = [captureDevice.devices.lastObject localizedName];

2

Swift 4 (xCode 10.1)

以下是我在最新版本的Swift中使用的方法。我没有看到这个答案,所以我花了一些时间来搞清楚如何获取前置摄像头。

原始答案:

 if let device = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera , mediaType: AVMediaTypeVideo, position: .front)  {
    //Do the camera thing here..
}

2

Simplified:

func getCamera(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    let deviceDescoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera], mediaType: .video, position: .unspecified)
    return deviceDescoverySession.devices.first(where: { $0.position == position })
}

// and you can use like that:

guard let device = getCamera(with: .back) else { return }

1

我的视频捕捉应用程序使用以下代码来获取麦克风、前置和后置摄像头,我已经测试了这段代码从iOS 7到10.0.2。

        var frontCamera : AVCaptureDevice?
        var rearCamera : AVCaptureDevice?

        captureSession = AVCaptureSession()

        let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)

        let audioDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeAudio)

        for mic in audioDevices {
            audioDevice = mic as? AVCaptureDevice
            audioCapturePossible = true
        }

        for device in devices {
            if device.position == AVCaptureDevicePosition.Front {
                frontCamera = device as? AVCaptureDevice
                hasFrontCamera = true
            }
            else if device.position == AVCaptureDevicePosition.Back {
                rearCamera = device as? AVCaptureDevice
                hasRearCamera = true
            }

        }

1
使用AVCaptureDevice.devicesWithMediaType仍然会收到“已弃用警告”。 - hefgi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接