I'm getting started taking simple photos with my iPhone using Xcode and swift. I've boiled down a couple of sample projects to a simple class below, derived from AVCapturePhotoCaptureDelegate, with Initialize, TakePhoto methods, and a callback photoOutput -- i.e., dead simple. To test, I created a simple app with "Initialize" and "Take Photo" buttons.
When I take the photo and the "photoOutput.capturePhoto" is called, it halts with an exception "No active and enabled video connection."
Apparently I've missed something fundamental in the boil down. One thing I left out from the sample project is the preview layer... does this require an active preview to function? Is that what it means by lacking a "video" connection? why would it require that?
Or is there something else I'm missing?
Thanks very much.
import UIKit
import AVFoundation
class cPhotoCaptureNormal: NSObject, AVCapturePhotoCaptureDelegate
{
private let photoOutput = AVCapturePhotoOutput()
public func Initialize()
{
let captureSession = AVCaptureSession()
if let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) {
do {
let input = try AVCaptureDeviceInput(device: captureDevice)
if captureSession.canAddInput(input) {
captureSession.addInput(input)
}
} catch let error {
print("Failed to set input device with error: \(error)")
}
if captureSession.canAddOutput(photoOutput) {
captureSession.addOutput(photoOutput)
}
else
{
print("Failed to add output device")
}
captureSession.startRunning()
}
}
public func TakePhoto()
{
let photoSettings = AVCapturePhotoSettings()
if let photoPreviewType = photoSettings.availablePreviewPhotoPixelFormatTypes.first {
photoSettings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: photoPreviewType]
// EXCEPTION OCCURS ON FOLLOwING LINE
photoOutput.capturePhoto(with: photoSettings, delegate: self)
}
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
guard let imageData = photo.fileDataRepresentation() else { return }
let previewImage = UIImage(data: imageData)
// ... post process and save UIImage
}
}
Assuming you are calling your
Initialize()function prior to callingTakePhoto(), the most likely cause of your issue that yourAVCaptureSessionis going out of scope at the end ofInitialize. MakecaptureSessiona property instead of a local variable. This will keep the session alive and allow you take a photo.You should also call
captureSession.stopRunning()at some point.On an unrelated note, it is standard practice in Swift to begin function names with lowercase letters. Only class, struct, and enum names start with uppercase letters.