An easier way to record video on iOS is to set AVCaptureSession.sessionPreset .
But this does not work for me, since I want to control parameters such as binning, stabilization (cinematic, standard or none) and ISO.
I find the format I want and assign it activeFormat , but when I try to start recording, I get an error message:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] No active/enabled connections'
Here is my initialization code:
let device = AVCaptureDevice.defaultDevice( withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)! let session = AVCaptureSession() session.addInput(try! AVCaptureDeviceInput(device: device)) output = AVCaptureMovieFileOutput() session.addOutput(output) device.setFormatWithHighestIso() session.startRunning()
setFormatWithHighestIso() is defined as:
extension AVCaptureDevice { var goodVideoFormats: [AVCaptureDeviceFormat] { return (formats as! [AVCaptureDeviceFormat]) .filter { CMFormatDescriptionGetMediaSubType($0.formatDescription) != 875704422 } // 420f .filter { $0.autoFocusSystem == .phaseDetection } } func setFormatWithHighestIso() { let format = goodVideoFormats .filter { $0.maxISO > 1759 } .filter { $0.height < 1937 } .first! try! lockForConfiguration() defer { unlockForConfiguration() } activeFormat = format NSLog("\(format)") } }
The last log statement produces:
<AVCaptureDeviceFormat: 0x1702027d0 'vide'/'420f' 2592x1936, { 3- 30 fps}, HRSI:4032x3024, fov:58.986, max zoom:189.00 (upscales @1.56), AF System:2, ISO:22.0-1760.0, SS:0.000005-0.333333, supports wide color>
This is really the format I want, so setFormatWithHighestIso() works as expected. See Apple reference .
Some other things I've tried:
- Using 420v instead of 420f, changing == 875704422 to! =.
- Instead of launching the camera in photo mode, start it in video mode, and then change it in video mode by removing AVCapturePhotoOutput and adding AVCaptureMovieFileOutput.
- Verifying that AVCaptureConnection is enabled, and that.
Checking the connection activity, but it is not:
let conn = output.connection (withMediaType: AVMediaTypeVideo)! check (conn.isActive)
I also tried using some other AVCaptureDeviceFormats , and they work:
extension AVCaptureDevice { func setFormatWithCinematicVS() { let format = goodVideoFormats .filter { $0.isVideoStabilizationModeSupported(.cinematic) } .filter { $0.height == 720 } .first! try! lockForConfiguration() defer { unlockForConfiguration() } activeFormat = format } func setFormatWithStandardVS() { let format = goodVideoFormats .filter { $0.isVideoStabilizationModeSupported(.standard) } .filter { $0.height == 540 } .first! try! lockForConfiguration() defer { unlockForConfiguration() } activeFormat = format } }
This is only the highest ISO format that does not work. What is special about this format?
Do I need to manually create an AVCaptureConnection? But there is already a connection; it is simply inactive.
This is on the iPhone 7 Plus running iOS 10.3.3. How to record video in a specific format by setting the active format without using a session?
If instead of assigning activeFormat I use sessionPreset, it successfully records the video.
There are other issues related to this error message, but this is not a hoax, as I specifically have to shoot video without using a preset.