Optional Types in Swift AVCaptureDevice - swift

let captureDeviceInput: AVCaptureDeviceInput?
do {
captureDeviceInput = try AVCaptureDeviceInput(device: device)
if session.canAddInput(captureDeviceInput) {
session.addInput(captureDeviceInput)
}
}
Getting a compile error:
"Value of optional type 'AVCaptureDeviceInput?' not unwrapped".
Any ways to fix this?

Any ways to fix this?
Yes. The property is an optional type. You need to unwrap it.
captureDeviceInput = try AVCaptureDeviceInput(device: device)
if let captureDeviceInput = captureDeviceInput
{
if session.canAddInput(captureDeviceInput) {
session.addInput(captureDeviceInput)
}
}
else
{
// Do something for a nil result (or nothing, if reasonable)
}

Try this:
import Cocoa
import AVFoundation
var captureDeviceInput: AVCaptureDeviceInput!
var device: AVCaptureDevice!
var session: AVCaptureSession!
do {
captureDeviceInput = try AVCaptureDeviceInput(device: device)
if ((session?.canAddInput(captureDeviceInput)) != nil) {
session?.addInput(captureDeviceInput)
}
}

Related

"Initializer for conditional binding...." after I fix, I get error "use of unresolved indentifier"

I've created a function called prepareCamera. It checks for device type, media type, and camera position.
When I use the if/ let on my object availableDevices, I get the error "Initializer for conditional binding must have optional type. After going through stack flow, I realized that my object is not an optional and if/let should only be used for optional type. I removed the if/ let, and I get the error, use of unresolved identifier.
My code is below. This is my first time using stackflow so bare with me haha. Any help would be greatly appreciated.
import UIKit
import AVFoundation
class goliveViewController: UIViewController {
let captureSession = AVCaptureSession()
var previewLayer:CALayer!
var captureDevice:AVCaptureDevice!
override func viewDidLoad() {
super.viewDidLoad()
prepareCamera()
// Do any additional setup after loading the view.
}
func prepareCamera () {
captureSession.sessionPreset = AVCaptureSession.Preset.photo
if let availableDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera] , mediaType: AVMediaType.video, position: .front).devices {
captureDevice = availableDevices.first
beginSession()
}
}
func beginSession () {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice)
captureSession.addInput(captureDeviceInput)
}catch {
print(error.localizedDescription)
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) {
self.previewLayer = previewLayer
self.view.layer.addSublayer(self.previewLayer)
self.previewLayer.frame = self.view.layer.frame
captureSession.startRunning()
let dataOutput = AVCaptureVideoDataOutput()
dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString):NSNumber(value:kCVPixelFormatType_32BGRA)]
dataOutput.alwaysDiscardsLateVideoFrames = true
if captureSession.canAddOutput(dataOutput) {
captureSession.addOutput(dataOutput)
}
captureSession.commitConfiguration()
}
}

Value of optional type 'AVCaptureDevice?' must be unwrapped to a value of type 'AVCaptureDevice'

I was following a tutorial on how to capture a barcode scanner from an ipad camera and this is the code that was written. The tutorial was written in xcode 8 and I am using Xcode 10. I am getting an error that
"Value of optional type 'AVCaptureDevice?' must be unwrapped to a
value of type 'AVCaptureDevice'"
in the do try catch statement. Can someone please tell me the correct way to deal with the optional value in this situation? When I change the line to read "let input = try AVCaptureDeviceInput(device: captureDevice!)"
the app crashes.
import AVFoundation
import UIKit
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var video = AVCaptureVideoPreviewLayer() //contains what the camera is pointing at
override func viewDidLoad() {
super.viewDidLoad()
//creates session
let session = AVCaptureSession()
//define capture device
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
do{
let input = try AVCaptureDeviceInput(device: captureDevice)//Error occurs here
session.addInput(input) //input coming from camera
}
catch{
print("Error")
}
let output = AVCaptureMetadataOutput()
session.addOutput(output)
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
output.metadataObjectTypes = [AVMetadataObject.ObjectType.code93, AVMetadataObject.ObjectType.code39] //may need to change this based on barcode type
video = AVCaptureVideoPreviewLayer(session: session)
video.frame = view.layer.bounds
view.layer.addSublayer(video)
session.startRunning()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
When I searched answer for this issue, it first showed your question only. Then I sought help from my colleague as well as finally it run without any error. Try below code.
let captureDevice = AVCaptureDevice.default(for: .video)
do{
let input = try AVCaptureDeviceInput(device: captureDevice!)
if self.session.canAddInput(input) {
self.captureSession.addInput(input)
}
}
catch{
print("Error")
}

AVCapturePhoto Why is my photo always nil?

I'm trying to implement some custom camera similar to snapchat. I cannot see why my image is always nil during segue. Maybe a fresh pair of eyes may help as I have been working on this for 2 days now...
When I tap the take photo button (to run "livePhotoTapped"), app crashes with error: fatal error: unexpectedly found nil while unwrapping an Optional value, referring to the image being nil
Any help would be nice :)
#IBOutlet weak var cameraView: UIView!
//session to capture data
var captureSession = AVCaptureSession()
//which camera to use
var backFacingCamera: AVCaptureDevice?
var frontFacingCamera: AVCaptureDevice?
var currentDevice: AVCaptureDevice?
var stillImageOutput: AVCaptureStillImageOutput?
var stillImage: UIImage?
//camera preview layer
var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
func setupCaptureSessionCamera() {
//this makes sure to get full res of camera
captureSession.sessionPreset = AVCaptureSession.Preset.photo
var devices = AVCaptureDevice.devices(for: .video)
//query available devices
for device in devices {
if device.position == .front {
frontFacingCamera = device
} else if device.position == .back {
backFacingCamera = device
}
}//end iteration
//set a default device
currentDevice = backFacingCamera
//configure session w output for capturing still img
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput?.outputSettings = [AVVideoCodecKey : AVVideoCodecType.jpeg]
do {
//capture the data from whichevr camera we r using..imagine as buffer to translate data into real world image
let captureDeviceInput = try AVCaptureDeviceInput(device: currentDevice!)
captureSession.addInput(captureDeviceInput)
captureSession.addOutput(stillImageOutput!)
//setup camera preview layer
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
//add the preview to our specified view in the UI
view.layer.addSublayer(cameraPreviewLayer!)
cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
cameraPreviewLayer?.frame = cameraView.frame
captureSession.startRunning()
} catch let error {
print(error)
}//end do
}
#IBAction func livePhotoTapped(_ sender: UIButton) {
let videoConnection = stillImageOutput?.connection(with: .video)
//capture still image async
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection!, completionHandler: { (imageDataBuffer, error) in
if let imageData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: imageDataBuffer!, previewPhotoSampleBuffer: imageDataBuffer!) {
self.stillImage = UIImage(data: imageData)
self.performSegue(withIdentifier: "toPreviewPhoto", sender: self)
}
})
}
Use like this :
For CMSampleBufferIsValid check this link
#IBAction func livePhotoTapped(_ sender: UIButton) {
let videoConnection = stillImageOutput?.connection(with: .video)
//capture still image async
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection!, completionHandler: { (imageDataBuffer, error) in
if error != nil {
print("error \(error)")
} else {
if let imageBuffer = imageDataBuffer, CMSampleBufferIsValid(imageBuffer) {
if let imageData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: imageDataBuffer!, previewPhotoSampleBuffer: imageDataBuffer!) {
self.stillImage = UIImage(data: imageData)
self.performSegue(withIdentifier: "toPreviewPhoto", sender: self)
}
} else {
print("imageDataBuffer is nil or not valid")
}
}
})
}
You are force unwrapping a nil object.
var currentDevice: AVCaptureDevice?
It looks like this method has been deprecated:
+ (NSArray<AVCaptureDevice *> *)devices NS_DEPRECATED(10_7, NA, 4_0, 10_0, "Use AVCaptureDeviceDiscoverySession instead.");
Have you tried "AVCaptureDeviceDiscoverySession"?

Use of unresolved identifier when referencing variable in do/catch block

I’m assigning a variable in a do / catch block, and then trying to reference that variable further down in my file. But when I do, I get the following error in Xcode:
Use of unresolved identifier 'captureDeviceInput'
This is my code:
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice) as AVCaptureDeviceInput
} catch let error {
print("\(error)")
return
}
captureSession = AVCaptureSession()
captureSession?.addInput(input: captureDeviceInput as AVCaptureDeviceInput)
It seems Xcode’s not recognising the captureDeviceInput variable. What can I do to resolve this?
captureDeviceInput is declared locally that means it's visible only in the do scope.
It's good habit to put all good code also in the do scope.
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice) as AVCaptureDeviceInput
captureSession = AVCaptureSession()
captureSession?.addInput(input: captureDeviceInput as AVCaptureDeviceInput)
} catch {
print("\(error)")
return
}

Var init in do-catch

Following code:
// Setup components
do {
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
let deviceInput = try AVCaptureDeviceInput(device: captureDevice)
let output = AVCaptureMetadataOutput()
let session = AVCaptureSession()
} catch {
return false
}
After this you can't access the initialized variables. The error is "Use of unresolved identifier" if I want to access e.g. deviceInput. But why? Either AVCaptureDeviceInput() crashes and the catch-Block returns or all is right and the variables are successfully initialized. What's the best solution to solve this ?
Vacawama's answer is perfectly correct, but just for educational purposes, here's a simplified version. You don't need anything but the initialization of deviceInput to happen inside a do block:
func test() {
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
let deviceInput : AVCaptureDeviceInput
do { deviceInput = try AVCaptureDeviceInput(device: captureDevice) } catch {return}
let output = AVCaptureMetadataOutput()
let session = AVCaptureSession()
// ... other stuff here
print("got to here")
}
If the try fails, "got to here" never prints; we have exited the function in good order.
Still another approach might be to let your surrounding function throw and just go for it, with no do...catch at all:
func test() throws {
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
let deviceInput = try AVCaptureDeviceInput(device: captureDevice)
let output = AVCaptureMetadataOutput()
let session = AVCaptureSession()
// ... other stuff here
print("got to here")
}
This moves the onus of error-checking onto the caller of test().
The do block defines a new scope. If you declare the variables with let or var inside of the do {}, then they are only accessible within that block. If you want to use them after the do {}, then declare them before the do statement. Note, that you don't have to give them initial values, even if they are declared with let because you will only be setting them once before using them:
func foo() -> Bool {
// Setup components
let deviceInput: AVCaptureDeviceInput
let captureDevice: AVCaptureDevice
let output: AVCaptureMetadataOutput
let session: AVCaptureSession
do {
captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
deviceInput = try AVCaptureDeviceInput(device: captureDevice)
output = AVCaptureMetadataOutput()
session = AVCaptureSession()
} catch {
return false
}
// Do something to demo that the variables are accessible
print(deviceInput.description)
print(output.description)
print(session.description)
return false
}