Trouble writing with AVAssetWriterInput

I have setup my `AVCaptureSession` with input from the camera and output to `AVCaptureVideoDataOutput`:


private func setupCaptureOutputs() {
    let videoDataOutput = AVCaptureVideoDataOutput()
    guard captureSession.canAddOutput(videoDataOutput) else { return } // captureSession is instance var
    captureSession.addOutput(videoDataOutput)
    videoDataOutput.alwaysDiscardsLateVideoFrames = false
    videoDataOutput.setSampleBufferDelegate(self, queue: captureQueue)
}


I have also created `AVAssetWriter` with `AVAssetWriterInput`:

assetWriter = try? AVAssetWriter(outputURL: videoPath, fileType: AVFileTypeQuickTimeMovie)

let assistant = AVOutputSettingsAssistant(preset: AVOutputSettingsPreset1280x720)
let outputSettings = assistant?.videoSettings
let formatHint = assistant?.sourceVideoFormat

let assetWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: outputSettings, sourceFormatHint: formatHint)
assetWriterInput.expectsMediaDataInRealTime = true
assetWriterInput.mediaTimeScale = 30


I start writing and start a session with `kCMTimeZero` on user's button tap in simple `IBAction`:

    @IBAction func toggleCapture(_ sender: UIButton!) {
        guard let aw = self.assetWriter else { return }
        guard let awi = self.assetWriterInput else { return }
        sessionStarted = !sessionStarted

        if sessionStarted == false {
            awi.markAsFinished()
            aw.endSession(atSourceTime: self.latestTimestamp!)
            aw.finishWriting {
                print("done writing")
            }
        } else {
            startDate = Date()
            aw.startWriting()
            aw.startSession(atSourceTime: self.latestTimestamp!)
        }
    }


In output's delegate method I get the latestTimestamp and append the sample to writer's input:

func captureOutput(_ captureOutput: AVCaptureOutput!,
    didOutputSampleBuffer sampleBuffer: CMSampleBuffer!,
    from connection: AVCaptureConnection!) {
    self.latestTimestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
    guard let awi = self.assetWriterInput else { return }
    guard sessionStarted == true else { return }
    if self.assetWriter?.status == .writing {
        awi.append(sampleBuffer)
    }
}


When I download the app's container and look at the video file it has length of few hours and only last few seconds display actual video. How would I go about manipulating `CMTime` instances to actual recorded video length?

Replies

Don't start at CMTimeZero. Start with the time of the first buffer you want to be presented in the movie (in capture time). Please take a look at the RosyWriter sample, which shows how to hook up a video data output and a asset writer.


https://developer.apple.com/library/content/samplecode/RosyWriter/Introduction/Intro.html

@bford Could you update that rosy writer example? There's no good resource/example out there for using AVAssetwriter it seems. Preferably in Swift.