This error occurs when capturing video with AVAssetWriter. However, after calling AVAssetWriter's finishWriting inside of endVideoCapture, there isn't another call to start writing again, so why is this occurring?
As you can see in the delegate function, captureOutput, we check the recording state before trying to append to the asset writer. The recording state is set to false in endVideoCapture.
Optional(Error Domain=AVFoundationErrorDomain Code=-11862 "Cannot append media data after ending session" UserInfo={NSLocalizedFailureReason=The application encountered a programming error., NSLocalizedDescription=The operation is not allowed, NSDebugDesc
func startVideoCapture() {
// Get capture resolution
let resolution = getCaptureResolution()
// Return if capture resolution not set
if resolution.width == 0 || resolution.height == 0 {
printError("Error starting capture because resolution invalid")
return
}
// If here, start capture
assetWriter = createAssetWriter(Int(resolution.width), outputHeight: Int(resolution.height))
let recordingClock = captureSession.masterClock
assetWriter!.startWriting()
assetWriter!.startSession(atSourceTime: CMClockGetTime(recordingClock!))
// Update time stamp
startTime = CACurrentMediaTime()
// Update <recording> flag & notify delegate
recording = true
delegate?.cameraDidStartVideoCapture()
}
func createAssetWriter(_ outputWidth: Int, outputHeight: Int) -> AVAssetWriter? {
// Update <outputURL> with temp file to hold video
let tempPath = gFile.getUniqueTempPath(gFile.MP4File)
outputURL = URL(fileURLWithPath: tempPath)
// Return new asset writer or nil
do {
// Create asset writer
let newWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileTypeMPEG4)
// Define video settings
let videoSettings: [String : AnyObject] = [
AVVideoCodecKey : AVVideoCodecH264 as AnyObject,
AVVideoWidthKey : outputWidth as AnyObject,
AVVideoHeightKey : outputHeight as AnyObject,
]
// Add video input to writer
assetWriterVideoInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoSettings)
assetWriterVideoInput!.expectsMediaDataInRealTime = true
newWriter.add(assetWriterVideoInput!)
// Define audio settings
let audioSettings : [String : AnyObject] = [
AVFormatIDKey : NSInteger(kAudioFormatMPEG4AAC) as AnyObject,
AVNumberOfChannelsKey : 2 as AnyObject,
AVSampleRateKey : NSNumber(value: 44100.0 as Double)
]
// Add audio input to writer
assetWriterAudioInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: audioSettings)
assetWriterAudioInput!.expectsMediaDataInRealTime = true
newWriter.add(assetWriterAudioInput!)
// Return writer
print("Created asset writer for \(outputWidth)x\(outputHeight) video")
return newWriter
} catch {
printError("Error creating asset writer: \(error)")
return nil
}
}
func endVideoCapture() {
// Update flag to stop data capture
recording = false
// Return if asset writer undefined
if assetWriter == nil {
return
}
// If here, end capture
// -- Mark inputs as done
assetWriterVideoInput!.markAsFinished()
assetWriterAudioInput!.markAsFinished()
// -- Finish writing
assetWriter!.finishWriting() {
self.assetWriterDidFinish()
}
}
func assetWriterDidFinish() {
print("Asset writer finished with status: \(getAssetWriterStatus())")
// Return early on error & tell delegate
if assetWriter!.error != nil {
printError("Error finishing asset writer: \(assetWriter!.error)")
delegate?.panabeeCameraDidEndVideoCapture(videoURL: nil, videoDur: 0, error: assetWriter!.error)
logEvent("Asset Writer Finish Error", userData: ["Error" : assetWriter!.error.debugDescription])
return
}
// If here, no error so extract video properties & tell delegate
let videoAsset = AVURLAsset(url: outputURL, options: nil)
let videoDur = CMTimeGetSeconds(videoAsset.duration)
let videoTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
print("Camera created video. Duration: \(videoDur). Size: \(videoTrack.naturalSize). Transform: \(videoTrack.preferredTransform). URL: \(outputURL).")
// Tell delegate
delegate?.cameraDidEndVideoCapture(videoURL: outputURL.path, videoDur: videoDur, error: assetWriter!.error)
// Reset <assetWriter> to nil
assetWriter = nil
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
// Return if not recording
if !recording {
return
}
// If here, capture data
// Write video data?
if captureOutput == videoOutput && assetWriterVideoInput!.isReadyForMoreMediaData {
assetWriterVideoQueue!.async {
self.assetWriterVideoInput!.append(sampleBuffer)
}
}
// No, write audio data?
if captureOutput == audioOutput && assetWriterAudioInput!.isReadyForMoreMediaData {
assetWriterAudioQueue!.async {
self.assetWriterAudioInput!.append(sampleBuffer)
}
}
}