【问题标题】:Back camera doesn't really work in Swift后置摄像头在 Swift 中不起作用
【发布时间】:2017-08-25 19:27:02
【问题描述】:

我正在尝试在我的应用上创建自定义相机。真的很简单,我想拍一张照片,然后把抓到的图片发给下一个视图控制器。不过不知道为什么,用前置摄像头拍照的时候摄像头还可以,但是用后置摄像头就不行了。

当我按下按钮拍照时,可能会有 7 秒的延迟,应用程序两次崩溃。

这是我的代码:

var captureSession = AVCaptureSession()
   var backCamera: AVCaptureDevice?
   var frontCamera: AVCaptureDevice?
   var currentCamera: AVCaptureDevice?

   var photoOutput: AVCapturePhotoOutput?
   var cameraPreviewLayer: AVCaptureVideoPreviewLayer?

   var image: UIImage?

   override func viewDidLoad() {
      super.viewDidLoad()

      setupCaptureSession()
      setupDevice()
      setupInputOutput()
      setupPreviewLayer()
      startRunningCaptureSession()

   }

   func setupCaptureSession(){
      captureSession.sessionPreset = AVCaptureSession.Preset.photo
   }

   func setupDevice(){
      let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: .video, position: AVCaptureDevice.Position.unspecified)
      let devices = deviceDiscoverySession.devices

      for device in devices {
         if device.position == AVCaptureDevice.Position.back {
            backCamera = device
         } else if device.position == AVCaptureDevice.Position.front {
            frontCamera = device
         }
      }
      currentCamera = backCamera
   }

   func setupInputOutput(){
      do {
         let captureDeviceInput = try AVCaptureDeviceInput(device: currentCamera!)
         captureSession.addInput(captureDeviceInput)
         photoOutput = AVCapturePhotoOutput()
         if #available(iOS 11.0, *) {
            photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
         } else {
            // Fallback on earlier versions
            photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecJPEG])], completionHandler: nil)
         }
         captureSession.addOutput(photoOutput!)
      } catch {
         print(error)
      }
   }

   func setupPreviewLayer(){
      cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
      cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
      cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
      cameraPreviewLayer?.frame = CGRect(x: 0, y: 0, width: self.cameraView.frame.size.width, height: self.cameraView.frame.size.height)
      cameraView.layer.addSublayer(cameraPreviewLayer!)
      //self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
   }

   func startRunningCaptureSession(){
      captureSession.startRunning()
   }

   @IBAction func switchCameraAction(_ sender: Any) {
      swapCamera()
   }

   /// Swap camera and reconfigures camera session with new input
   fileprivate func swapCamera() {
      // Get current input
      guard let input = captureSession.inputs[0] as? AVCaptureDeviceInput else { return }

      // Begin new session configuration and defer commit
      captureSession.beginConfiguration()
      defer { captureSession.commitConfiguration() }

      // Create new capture device
      var newDevice: AVCaptureDevice?
      if input.device.position == .back {
         newDevice = captureDevice(with: .front)
         isFront = true
      } else {
         newDevice = captureDevice(with: .back)
         isFront = false
      }

      // Create new capture input
      var deviceInput: AVCaptureDeviceInput!
      do {
         deviceInput = try AVCaptureDeviceInput(device: newDevice!)
      } catch let error {
         print(error.localizedDescription)
         return
      }

      // Swap capture device inputs
      captureSession.removeInput(input)
      captureSession.addInput(deviceInput)
   }

   fileprivate func captureDevice(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {

      let devices = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: .video, position: AVCaptureDevice.Position.unspecified).devices

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

   }

   func crop(_ image: UIImage, withWidth width: Double, andHeight height: Double) -> UIImage? {

      if let cgImage = image.cgImage {

         let contextImage: UIImage = UIImage(cgImage: cgImage)

         let contextSize: CGSize = contextImage.size

         var posX: CGFloat = 0.0
         var posY: CGFloat = 0.0
         var cgwidth: CGFloat = CGFloat(width)
         var cgheight: CGFloat = CGFloat(height)

         // See what size is longer and create the center off of that
         if contextSize.width > contextSize.height {
            posX = ((contextSize.width - contextSize.height) / 2)
            posY = 0
            cgwidth = contextSize.height
            cgheight = contextSize.height
         } else {
            posX = 0
            posY = ((contextSize.height - contextSize.width) / 2)
            cgwidth = contextSize.width
            cgheight = contextSize.width
         }

         let rect: CGRect = CGRect(x: posX, y: posY, width: cgwidth, height: cgheight)

         // Create bitmap image from context using the rect
         var croppedContextImage: CGImage? = nil
         if let contextImage = contextImage.cgImage {
            if let croppedImage = contextImage.cropping(to: rect) {
               croppedContextImage = croppedImage
            }
         }

         // Create a new image based on the imageRef and rotate back to the original orientation
         if let croppedImage:CGImage = croppedContextImage {
            let image: UIImage = UIImage(cgImage: croppedImage, scale: image.scale, orientation: image.imageOrientation)
            return image
         }
      }

      return nil
   }

   @IBAction func takePhotoAction(_ sender: Any) {
      var settingsCamera = AVCapturePhotoSettings()
      let previewPixelType = settingsCamera.availablePreviewPhotoPixelFormatTypes.first
      settingsCamera.flashMode = .off
      if isFront == false && hasFlash{
         settingsCamera.flashMode = .on
      }

      let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
                           kCVPixelBufferWidthKey as String: 160,
                           kCVPixelBufferHeightKey as String: 160]

      settingsCamera.previewPhotoFormat = previewFormat
      photoOutput?.capturePhoto(with: settingsCamera, delegate: self)
   }

}

extension UploadViewController: AVCapturePhotoCaptureDelegate {


   func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {

      if let error = error {
         print("error occure : \(error.localizedDescription)")
      }

      if  let sampleBuffer = photoSampleBuffer,
         let previewBuffer = previewPhotoSampleBuffer,
         let dataImage =  AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer:  sampleBuffer, previewPhotoSampleBuffer: previewBuffer) {

         let dataProvider = CGDataProvider(data: dataImage as CFData)
         let cgImageRef: CGImage! = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)

         var orientation = UIImageOrientation(rawValue: 0)

         if isFront {
            orientation = UIImageOrientation.leftMirrored
         } else {
            orientation = UIImageOrientation.right
         }

         let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: orientation!)
         // var flippedImage = UIImage(CGImage: picture.CGImage!, scale: picture.scale, orientation: .leftMirrored)
         let timage = crop(image, withWidth: 100, andHeight: 100)

         let photoSecondVC = self.storyboard?.instantiateViewController(withIdentifier: "uploadSecondVC") as! UploadSecondViewController
         photoSecondVC.imageData = timage!
         photoSecondVC.isFront = isFront
         self.navigationController?.pushViewController(photoSecondVC, animated: false)

      } else {
         print("some error here")
      }
   }

}

这是我在App崩溃时出现的(不知道有没有链接):

2017-08-25 16:50:36.125052+0200 Fitshare[93231:3349636] 无法在 (UITabBarItem) 上设置 (keyPath) 用户定义的检查属性:[ setValue:forUndefinedKey:]:此类不是键值编码- 符合键 keyPath。 2017-08-25 16:50:36.125584+0200 Fitshare [93231:3349636] 无法在 (UITabBarItem) 上设置 (keyPath) 用户定义的检查属性:[setValue:forUndefinedKey:]:此类不符合键值编码关键keyPath。 2017-08-25 16:50:36.300650+0200 Fitshare[93231:3349636] [MC] 延迟加载 NSBundle MobileCoreServices.framework 2017-08-25 16:50:36.302462+0200 Fitshare[93231:3349636] [MC] 加载 MobileCoreServices.framework 2017-08-25 16:50:36.311211+0200 Fitshare[93231:3349636] [MC] systemgroup.com.apple.configurationprofiles 路径的系统组容器是 /Users/kevinboirel/Library/Developer/CoreSimulator/Devices/B48E7503-47C0 -4A75-AC5C-C3DEF6CC8507/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles 2017-08-25 16:50:36.363022+0200 Fitshare[93231:3349636] [Snapshotting] 对至少未渲染一次的视图(0x7fbb38f2b0c0,Fitshare.ALThreeCircleSpinner)进行快照需要 afterScreenUpdates:YES。 2017-08-25 16:50:36.469416+0200 Fitshare[93231:3349636] +[CATransaction 同步] 在事务中调用 2017-08-25 16:50:36.469800+0200 Fitshare[93231:3349636] +[CATransaction 同步] 在事务中调用

奇怪的事实是我在 XCode 中有这个消息错误:

【问题讨论】:

  • 崩溃发生时控制台的输出是什么?
  • 我编辑了我的代码 ;)
  • 我遇到了这种问题,这是由于内存消耗造成的。设备无法处理它并且首先与 XCode 断开连接(没有响应),然后有时会崩溃。
  • crop()photoOutput() 的所有相关内容与 CFData 等都是 CPU 消耗的。如果不使用,还有问题吗?
  • 可以用非Beta XCode版本和iOS版本来检查吗?但很明显,后置摄像头而不是前置摄像头的问题表明存在内存问题(拍摄的照片会更大)。如果你评论了if let sampleBuffer = photoSampleBuffer,的所有代码,你还有问题吗?你能发到UploadSecondViewController吗?

标签: ios swift swift3 camera


【解决方案1】:

您需要两个协议委托,它们是:UIImagePickerControllerDelegateUINavigationControllerDelegate

// MARK: - Global Declaration

@IBOutlet var imgProfile: UIImageView!

var imagePicker = UIImagePickerController()

// MARK: - Camera Methods

func PickingImageFromCamera()

{
    let picker = UIImagePickerController()

    picker.delegate = self

    picker.allowsEditing = false
    picker.sourceType = .camera

    picker.cameraCaptureMode = .photo

    present(picker, animated: true, completion: nil)
}
//----------------------------------

func imagePickerController(_ picker: UIImagePickerController, 
 didFinishPickingMediaWithInfo info: [String : Any]) 
{

    if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
            imgProfile.contentMode = .scaleToFill
            imgProfile.image = pickedImage
      }

    dismiss(animated: true, completion: nil)
}

//----------------------------------    

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    dismiss(animated: true, completion: nil)
}
//----------------------------------

我认为这段代码会对你有所帮助...

【讨论】:

  • 以上代码用两侧摄像头(前置摄像头和第二个摄像头)测试。但是当您选择视频模式时,应用程序崩溃
【解决方案2】:

这是由于 UploadSecondViewController ...

我刚刚将发送到第二个 ViewController 的图片调整为更小的尺寸,应用程序现在可以了!

感谢您的回答!

【讨论】:

    猜你喜欢
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 2019-06-16
    • 2017-08-28
    • 1970-01-01
    • 2020-08-13
    • 2016-03-06
    相关资源
    最近更新 更多