-[AVAssetWriterInput markAsFinished] Cannot call method when status is 0' camera record Swift iOS

636 Views Asked by At

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

1

There are 1 best solutions below

1
Bulat Yakupov On

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.