Как получить переднюю камеру, заднюю камеру и аудио с помощью AVCaptureDeviceDiscoverySession

#ios #swift #avfoundation #avcapturedevice

#iOS #swift #avfoundation #avcapturedevice

Вопрос:

До выхода 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 не выдает мне никаких ошибок, но предварительный просмотр для захвата камеры полностью белый. Когда я начинаю запись, я получаю следующую ошибку:

Ошибка Domain=AVFoundationErrorDomain Code =-11800 «Операция не может быть завершена» userInfo={NSLocalizedDescription= Операция не может быть завершена, NSUnderlyingError= 0x17554440 {Ошибка Domain=NSOSStatusErrorDomain Code =-12780 «(null)»}, NSLocalizedFailureReason = Неизвестный произошла ошибка (-12780)}

Я считаю, что это как-то связано с тем фактом, что я использую устаревший подход AVCaptureDevice.devices() . Следовательно, мне было интересно, как использовать AVCaptureDeviceDiscoverySession вместо этого?

Заранее благодарим вас за помощь!

Ответ №1:

Вы можете получить переднюю камеру с помощью следующего:

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

Задняя камера:

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

И микрофон:

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

Комментарии:

1. Оказалось, что моя камера на моем iPhone была сломана, отсюда и белый цвет, отображаемый в слое предварительного просмотра. Спасибо за ваш ответ, по крайней мере, я мог избавиться от своего предупреждения, которое xcode8 постоянно выдавал мне.

2. Знаете ли вы, как сделать то же самое, используя заднюю камеру с Objective-C вместо этого?

3. Кажется, все ответы используются .builtInWideAngleCamera в качестве типа устройства. Можете ли вы объяснить, почему вы используете этот тип, а не один из многих других? Например, есть также .builtInDualWideCamera . Будет ли по-прежнему возвращена двойная широкая камера с вашим кодом?

4. @ndreisg вы можете найти ответ в документации Apple developer.apple.com/documentation/avfoundation /…

5. @AliAmin по этой ссылке представлен наилучший подход к получению лучшей доступной камеры. ps: для достижения наилучших результатов вам следует добавить опцию тройной камеры перед двойной, поскольку эта ссылка кажется немного старой

Ответ №2:

Вот мой код (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
}
  

Если вы хотите, вы также можете получить новые типы устройств с iPhone 7 (двойная камера), изменив массив deviceTypes.

Вот хорошее чтение: https://forums.developer.apple.com/thread/63347

Ответ №3:

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" } AVCaptureDeviceType был заменен на AVCaptureDevice.DeviceType и AVCaptureDevicePosition был заменен на AVCaptureDevice.Position (XCode 9.2 / Swift 4)

2. Массив устройств пуст, вы знаете почему?

Ответ №4:

Он работает на Xcode 9.2 и Swift 4

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

https://developer.apple.com/documentation/avfoundation/avcapturedevice/2361508-default

Ответ №5:

Swift 3

Для выбора задней камеры: (также вы можете изменить.возвращайте по мере необходимости)

Для выбора другого типа устройства просто добавьте его в [] (т.е.:

[Тип камеры устройства, AVCaptureDeviceType.Встроенный микрофон]

(или создайте частное разрешение… как я сделал в коде с задней камерой)

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

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

 }
  

Комментарии:

1. Xcode 9 просто попросил меня использовать __deviceTypes: вместо deviceTypes:, кроме того, это работает.

Ответ №6:

пример: 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()
  

Комментарии:

1. Кто-нибудь обнаружил, что это не работает с последней бета-версией 11.3 SDK на телефонах 10 ? Это работает на моем телефоне, но не на моем телефоне тестировщиков testflight слой предварительного просмотра видео не создается.

Ответ №7:

Попробуйте приведенный ниже код, чтобы получить идентификатор камеры:

 NSString *cameraID = nil;

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

cameraID = [captureDevice.devices.lastObject localizedName];
  

Ответ №8:

Swift 4 (xCode 10.1)

Это то, что сработало для меня в последней версии Swift. Я не видел этого ответа, и мне потребовалось некоторое время, чтобы разобраться, поэтому вот как получить фронтальную камеру.

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

Ответ №9:

Упрощенный:

 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 }
  

Ответ №10:

Для моего приложения для захвата видео я использую следующий код, чтобы получить микрофон, переднюю и заднюю камеры, и я протестировал этот код с 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

Ответ №11:

В Swift 5 это проще

 AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .front)
  

Ответ №12:

05/2019 :

  //video
        self.session = AVCaptureSession()
        guard
            let videoDeviceInput = try? AVCaptureDeviceInput(device: device!),
            self.session!.canAddInput(videoDeviceInput)
            else { return }
        self.session!.addInput(videoDeviceInput)

  //audio
        guard
            let audioDeviceInput = try? AVCaptureDeviceInput(device: mic!),
            self.session!.canAddInput(audioDeviceInput)
            else { return }
        self.session!.addInput(audioDeviceInput)