I’m working with Apple’s AVCamFilter demo app. Unfortunately it doesn’t include movie recording capability, so I tried creating a movie output, right below the photo output, at the top of the class:
let movieOutput = AVCaptureMovieFileOutput()
I then added the output (again, right below where the photo output is added) in configureSession() like so:
if session.canAddOutput(movieOutput) {
session.addOutput(movieOutput)
} else {
print("Could not add movie output to the session")
setupResult = .configurationFailed
session.commitConfiguration()
return
}
On my iPhone (13 Pro), this works and I can succesfully record video. But on my iPad Air the camera preview just goes black. No error comes up, and setupResult prints as "success", but there's no video. Interestingly, if I take a photo with the shutter button, it successfully captures (with an image) to the photo library.
I've made no other modifications to the project, so you can try this yourself by downloading the demo app and just adding those lines.
Update: I've found some related posts about how AVCaptureMovieFileOutput may be incompatible with AVCaptureVideoDataOutput. But if that's true why does it work on my iPhone?
I never figured out why it worked on my iPhone, but as a workaround I implemented AVAssetWriter. This should allow AVCamFilter to record video (and audio!) on any device.
First, add
AVCaptureAudioDataOutputSampleBufferDelegateto the class declaration.Add these variables to the class:
I put the audio on a seperate session becuase I wanted to include haptics (see note below), but you can put them on the same session if you wish.
In
configureSession(), after the finalsession.commitConfiguration(), add:Then replace the contents of
captureOutput(_ didOutput from:)with this:(You can do whatever you want with the URL, it’s saved to the photo library here as an example)
Lastly you’ll need this to sync the audio and video:
To actually trigger the video recording, change
_captureStateto.start, and change it to.endto finish.Notes:
-You may see black frames at the start and end of videos. I tried a variety of approaches to solve this but none worked, so I changed
writer.startSession(atSourceTime: .zero)towriter.startSession(atSourceTime: CMTime(seconds: 0.25, preferredTimescale: CMTimeScale(600))), which simply trims 0.25 seconds off the start. For the end, right before_assetWriterVideoInput?.markAsFinished(), adding this seems to fix it:-Running the mic disables haptics. This is why I used a seperate audio session: so that I can tell the session to startRunning when the video recording starts, and stopRunning when it ends. As long as it's not recording, you should be able to use haptics. Note that you will of course have to get audio permissions before audio recording will work.
-Credit to here for some of the AVAssetWriter code: https://gist.github.com/yusuke024/b5cd3909d9d7f9e919291491f6b381f0
-I’m by no means an expert! So anyone feel free to point out if something here is unnecessary/wrong.