Record video with AVAssetWriter: first frames are black

SWIFT 4

SOLUTION #1:

I resolved this by calling file_writer?.startWriting() as soon as possible upon launching the app. Then when you want to start recording, do the file_writer?.startSession(atSourceTime:...).

When you are done recording and call finishRecording, when you get the callback that says that's complete, set up a new writing session again.

SOLUTION #2:

I resolved this by adding half a second to the starting time when calling AVAssetWriter.startSession, like this:

start_recording_time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
let startingTimeDelay = CMTimeMakeWithSeconds(0.5, 1000000000)
let startTimeToUse = CMTimeAdd(start_recording_time!, startingTimeDelay)

file_writer?.startSession(atSourceTime: startTimeToUse)

SOLUTION #3:

A better solution here is to record the timestamp of the first frame you receive and decide to write, and then start your session with that. Then you don't need any delay:

//Initialization, elsewhere:

var is_session_started = false
var videoStartingTimestamp = CMTime.invalid

// In code where you receive frames that you plan to write:

if (!is_session_started) {
    // Start writing at the timestamp of our earliest sample
    videoStartingTimestamp = currentTimestamp
    print ("First video sample received: Starting avAssetWriter Session: \(videoStartingTimestamp)")
    avAssetWriter?.startSession(atSourceTime: videoStartingTimestamp)

    is_session_started = true
}

// add the current frame
pixelBufferAdapter?.append(myPixelBuffer, withPresentationTime: currentTimestamp)

Ok, stupid mistake...

When launching the app, I init my AVCaptureSession, add inputs, outputs, etc. And I was just calling start_new_record a bit too soon, just before commitConfiguration was called on my capture session.

At least my code might be useful to some people.