简体   繁体   中英

Swift 4 Capture Photo, photoOutput returns nil

Currently I have two different view controllers and a button that switches between them. On each of them I want to be able to snap a photo of the device input.

I currently am able to snap a Photo of the back camera for processing and that works perfectly, however when i tried writing the same code in the other controller for the second view, the photo output returns nil, but when I log each device, it still shows front and back camera.

I am fairly new to swift and not sure why this is happening.

ViewController class, viewDidLoad and variables:

class AddUserController: UIViewController , AVCaptureVideoDataOutputSampleBufferDelegate , UITextFieldDelegate{

   //variable for captureing video feed
   var captureSessionFront = AVCaptureSession()
   //variable for rendering camera to the view
   var videoPreviewLayer: AVCaptureVideoPreviewLayer?

   var frontCamera: AVCaptureDevice?
   var backCamera: AVCaptureDevice?
   var currentCamera2: AVCaptureDevice?
   var PhotoOutputFront: AVCapturePhotoOutput?
   var cameraPreviewLayer2: AVCaptureVideoPreviewLayer?

   var tempImage: UIImage?

   var tempstring: String?

   private var maskLayer = [CAShapeLayer]()



   @IBOutlet weak var textField: UITextField!

   //button action to save the user to the collection
   @IBAction func saveFaceBtn(_ sender: Any) {
       let settings = AVCapturePhotoSettings()
       PhotoOutputFront?.capturePhoto(with: settings, delegate: self)
       //print(PhotoOutputFront!)
   }

   override func viewDidLoad() {
       super.viewDidLoad()
       // Do any additional setup after loading the view, typically from a nib.

       //hide keyboard
       self.textField.delegate = self

       //video capture functions
       setupCaptureSession()
       setupDevice()
       setupInputOutput()
       setupPreview()
       startRunningCaptureSession()

Functions:

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

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

       //find devices and check if frint or back cameras discovered
       let devices = deviceDiscoverySession.devices

       for device in devices{
           print(device)
           if device.position == AVCaptureDevice.Position.front{
               frontCamera = device

           } else if device.position == AVCaptureDevice.Position.back{
               backCamera = device
           }
       }

       currentCamera2 = frontCamera

   }

   func setupInputOutput() {

       do
       {

           let captureDeviceInput2 = try AVCaptureDeviceInput(device: currentCamera2!)

           captureSessionFront.addInput(captureDeviceInput2)
           PhotoOutputFront?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
           print(PhotoOutputFront)
       }
       catch
       {
           print(error)
       }
   }

   func setupPreview() {
       cameraPreviewLayer2 = AVCaptureVideoPreviewLayer(session: captureSessionFront)
       cameraPreviewLayer2?.videoGravity = AVLayerVideoGravity.resizeAspectFill
       cameraPreviewLayer2?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
       cameraPreviewLayer2?.frame = self.view.frame
       self.view.layer.insertSublayer(cameraPreviewLayer2!, at: 0)
   }

   func startRunningCaptureSession() {
       captureSessionFront.startRunning()
   }

Extension which saves the captured photo:

extension AddUserController: AVCapturePhotoCaptureDelegate {

   func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
       print("before if let")
       if let imageData = photo.fileDataRepresentation(){
           tempImage = UIImage(data: imageData)
           print(tempImage!)

           //check to see if name is empty
           let tempstring = self.textField.text
           if(tempstring != nil || tempstring != ""){

               print(tempstring!)
               //addPhotoToCollection()
           }


       }
   }

}

It must be something setting up the Input Output, but I'm not sure where I went wrong as this code works for the back camera in my main viewcontroller. I think it has to do with this function as in my other controller "PhotoOutput"doesn't return nil. Where as here, "PhotoOutputFront" returns nil.

view    func setupInputOutput() {

       do
       {

           let captureDeviceInput2 = try AVCaptureDeviceInput(device: currentCamera2!)

           captureSessionFront.addInput(captureDeviceInput2)
           PhotoOutputFront?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
           print(PhotoOutputFront)
       }
       catch
       {
           print(error)
       }
   }

Any help would be greatly appreciated. Thanks in advance!

The problem was that I was not adding the capture device as an input to the capture session as well as not adding the output of my capture session.

Hope this helps anyone else who was having trouble with avcapture devices. :)

func setupInputOutput() {

       do
       {

           let captureDeviceInput2 = try AVCaptureDeviceInput(device: currentCamera2!)

           captureSessionFront.addInput(captureDeviceInput2)
           PhotoOutputFront = AVCapturePhotoOutput()
           PhotoOutputFront?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
           captureSessionFront.addOutput(PhotoOutputFront!)
       }
       catch
       {
           print(error)
       }
   }

Add the output:

if captureSessionFront?.canAddOutput(PhotoOutputFront) {
  let settings = AVCapturePhotoSettings()
  let previewPixelType = 
  settings.__availablePreviewPhotoPixelFormatTypes.first!
  let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
                   kCVPixelBufferWidthKey as String: 160,
                   kCVPixelBufferHeightKey as String: 160]
  settings.previewPhotoFormat = previewFormat
  settings.isHighResolutionPhotoEnabled = 
  PhotoOutputFront.isHighResolutionCaptureEnabled
  PhotoOutputFront.setPreparedPhotoSettingsArray([settings], completionHandler: { (finished, anError) in
    guard let error = anError else { return }
    debugPrint("Failed to set photo settings with: \(error.localizedDescription)")
  })
  captureSessionFront.addOutput(PhotoOutputFront)
}

Before adding the output, add the input:

if captureSessionFront.canAddInput(captureDeviceInput2) {
    captureSessionFront.addInput(captureDeviceInput2)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM