I need to record a video and show a video with an AVPlayer at the same time. The result needs to be synchronized: if the video I'm showing is a metronome, or someone clapping, the recorded video and the player should click or clap at the same time.
I play the AVPlayer using preroll and setRate, with a delegate in the camera controller.
Using AVCaptureMovieFileOutput, I've tried calling setRate on the player once fileOutput(output:didStartRecordingTo) is called, but the videos end up desynchronized, with the recorded video going behind the player.
Using an AssetWriter, I've tried calling setRate on the player once captureOutput(captureOutput:sampleBuffer) is called, and the first buffer is appended, but the result is the same.
Is there any other way to do this?
EDIT: Adding some code to show what I'm doing:
Camera with AVCaptureMovieFileOutput:
func startRecordingVideo() {
guard let movieFileOutput = self.movieFileOutput else {
return
}
sessionQueue.async {
if !movieFileOutput.isRecording {
let movieFileOutputConnection = movieFileOutput.connection(with: .video)
movieFileOutput.setOutputSettings([AVVideoCodecKey: AVVideoCodecH264], for: movieFileOutputConnection!)
let outputFileName = NSUUID().uuidString
let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!)
movieFileOutput.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: self)
} else {
movieFileOutput.stopRecording()
}
}
}
func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
cameraDelegate?.startedRecording()
}
Implementing delegate's startRecording in the viewController:
private func setRateForAll() {
let hostTime = CMClockGetTime(CMClockGetHostTimeClock())
activePlayers.forEach {
$0.setRate(atHostTime: hostTime)
}
}
Once the active player or players end, I call stopRecording on the camera, and show the resulting recorded video in another player, along with the player or players I've been showing.