AVAssetWriter error: Cannot append media data after ending session

大憨熊 提交于 2020-01-02 22:29:50

问题


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)
        }
    }
}
|improve this question

来源:https://stackoverflow.com/questions/41647342/avassetwriter-error-cannot-append-media-data-after-ending-session

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!