I'm using AVAssetWriterInput to record video but when I want to stop recording I'm getting this error only 1/10 times.
-[AVAssetWriterInput markAsFinished] Cannot call method when status is 0'
Here is the stop method :
func stopRecording(completion: ((String?)-> Void)? = nil) {
sessionQueue.async { [self] in
guard let captureSession = self.session, captureSession.isRunning else {
print(CameraControllerError.captureSessionIsMissing)
completion?(nil)
return
}
if(!isRecording) {
completion?(nil)
return
}
isRecording = false
do {
if (assetWriter?.status == .writing) {
videoWriterInput?.markAsFinished()
audioWriterInput?.markAsFinished()
videoWriterInputPixelBufferAdaptor!.assetWriterInput.markAsFinished()
print("video finished")
print("audio finished")
} else{
print("not writing")
}
self.assetWriter?.finishWriting() {
print("finished writing")
}
}
catch {
if let e=self.assetWriter?.error{
print("stop record error:", e)
}
}
if(self.audioCaptureSession!.isRunning) {
let inputs = self.audioCaptureSession!.inputs
for oldInput:AVCaptureInput in inputs {
self.audioCaptureSession!.removeInput(oldInput)
}
let outputs = self.audioCaptureSession!.outputs
for oldOutput:AVCaptureOutput in outputs {
self.audioCaptureSession!.removeOutput(oldOutput)
}
self.audioCaptureSession!.stopRunning()
}
self.audioCaptureSession = nil
let path = assetWriter?.outputURL.path
self.videoRecordCompletionBlock?(path)
videoWriterInputPixelBufferAdaptor = nil
}
}
Start recording method is also configuring the written :
func configureWritter(path: String) {
do {
assetWriter = try AVAssetWriter(outputURL: URL(fileURLWithPath: path), fileType: AVFileType.mp4)
let videoSettings = self.recommendedVideoSettings(videoOutput: videoDataOutput, fileType: AVFileType.mp4, videoCodec: AVVideoCodecType.h264)
videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
videoWriterInput!.expectsMediaDataInRealTime = true
if (assetWriter?.canAdd(videoWriterInput!))!
{
assetWriter?.add(videoWriterInput!)
print("Added AVAssetWriterInput: Video")
} else{
print("Could not add VideoWriterInput to VideoWriter")
}
videoWriterInputPixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoWriterInput!, sourcePixelBufferAttributes: [
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
kCVPixelBufferWidthKey as String: 1080,
kCVPixelBufferHeightKey as String: 1920,
kCVPixelFormatOpenGLESCompatibility as String: true,
])
// ------ AUDIO --------
// Start audio session
self.audioCaptureSession?.startRunning()
//Audio Settings
let audioSettings = self.audioDataOutput.recommendedAudioSettingsForAssetWriter(writingTo: .mp4)
audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: audioSettings)
audioWriterInput!.expectsMediaDataInRealTime = true
if (assetWriter?.canAdd(audioWriterInput!))!
{
assetWriter?.add(audioWriterInput!)
print("Added AVAssetWriterInput: Audio")
} else{
print("Could not add AudioWriterInput to VideoWriter")
}
let recordingClock = self.session!.masterClock
assetWriter?.startWriting()
assetWriter?.startSession(atSourceTime: CMClockGetTime(recordingClock!))
switch self.assetWriter?.status {
case .writing:
print("status writing")
case .failed:
print("status failed")
case .cancelled:
print("status cancelled")
case .unknown:
print("status unknown")
default:
print("status completed")
}
}
catch {
return
}
}
Append method from the delegate :
func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from _: AVCaptureConnection) {
if(!isRecording) {
return
}
guard CMSampleBufferDataIsReady(sampleBuffer) else {
print("data are not ready")
return
}
if(self.assetWriter == nil) {
return
}
else if (self.assetWriter?.status != .writing) {
return
}
switch captureOutput {
case is AVCaptureVideoDataOutput:
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
print("error to get image buffer")
return
}
let time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
if(videoWriterInputPixelBufferAdaptor != nil) {
if(videoWriterInputPixelBufferAdaptor!.assetWriterInput.isReadyForMoreMediaData) {
videoWriterInputPixelBufferAdaptor!.append(imageBuffer, withPresentationTime: time)
print("append video writer")
}
else {
print("input pixel writer is not ready for media data")
}
}
else {
print("input pixel writer was null")
}
case is AVCaptureAudioDataOutput:
audioWriterInput?.append(sampleBuffer)
print("append audio input writer")
default:
break
}
}
}
What does mean this error and why this it happening ?
Maybe the problem is inside another part of my camera config which is large and complex, but better understand the reason of this error, which I didn't found, will help me a lot to fix the situation so thanks for any help or explanations
I think you forgot to add your writer inputs to AVAssetWriter or maybe it is not called sometimes for some reason. Please show your writer initialization code maybe I will find the problem with a fresh look.