Save AVCaptureVideoDataOutput to movie file using AVAssetWriter in Swift
I was able to find out how to use AVAssetWriter. In case anyone else needs help the code I used is as follows:
func setUpWriter() { do { outputFileLocation = videoFileLocation() videoWriter = try AVAssetWriter(outputURL: outputFileLocation!, fileType: AVFileType.mov) // add video input videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [ AVVideoCodecKey : AVVideoCodecType.h264, AVVideoWidthKey : 720, AVVideoHeightKey : 1280, AVVideoCompressionPropertiesKey : [ AVVideoAverageBitRateKey : 2300000, ], ]) videoWriterInput.expectsMediaDataInRealTime = true if videoWriter.canAdd(videoWriterInput) { videoWriter.add(videoWriterInput) print("video input added") } else { print("no input added") } // add audio input audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil) audioWriterInput.expectsMediaDataInRealTime = true if videoWriter.canAdd(audioWriterInput!) { videoWriter.add(audioWriterInput!) print("audio input added") } videoWriter.startWriting() } catch let error { debugPrint(error.localizedDescription) }}func canWrite() -> Bool { return isRecording && videoWriter != nil && videoWriter?.status == .writing} //video file location methodfunc videoFileLocation() -> URL { let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString let videoOutputUrl = URL(fileURLWithPath: documentsPath.appendingPathComponent("videoFile")).appendingPathExtension("mov") do { if FileManager.default.fileExists(atPath: videoOutputUrl.path) { try FileManager.default.removeItem(at: videoOutputUrl) print("file removed") } } catch { print(error) } return videoOutputUrl}// MARK: AVCaptureVideoDataOutputSampleBufferDelegatefunc captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { let writable = canWrite() if writable, sessionAtSourceTime == nil { // start writing sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) videoWriter.startSession(atSourceTime: sessionAtSourceTime!) //print("Writing") } if output == videoDataOutput { connection.videoOrientation = .portrait if connection.isVideoMirroringSupported { connection.isVideoMirrored = true } } if writable, output == videoDataOutput, (videoWriterInput.isReadyForMoreMediaData) { // write video buffer videoWriterInput.append(sampleBuffer) //print("video buffering") } else if writable, output == audioDataOutput, (audioWriterInput.isReadyForMoreMediaData) { // write audio buffer audioWriterInput?.append(sampleBuffer) //print("audio buffering") }}// MARK: Start recordingfunc start() { guard !isRecording else { return } isRecording = true sessionAtSourceTime = nil setUpWriter() print(isRecording) print(videoWriter) if videoWriter.status == .writing { print("status writing") } else if videoWriter.status == .failed { print("status failed") } else if videoWriter.status == .cancelled { print("status cancelled") } else if videoWriter.status == .unknown { print("status unknown") } else { print("status completed") }}// MARK: Stop recordingfunc stop() { guard isRecording else { return } isRecording = false videoWriterInput.markAsFinished() print("marked as finished") videoWriter.finishWriting { [weak self] in self?.sessionAtSourceTime = nil } //print("finished writing \(self.outputFileLocation)") captureSession.stopRunning() performSegue(withIdentifier: "videoPreview", sender: nil)}
I now have another problem where this solution doesn't work when I'm using AVCaptureMetadataOutput, AVCaptureVideoDataOutput and AVCaptureAudioDataOutput together. The app crashes when I add AVCaptureAudioDataOutput.