AVAssetWiter status failed when appending audio sample buffer to AVAssetwriterInput - OSX, Swift

345 views Asked by At

I am trying to record screen with audio in OSX with AVFoundation, When i record video is working perfectly. But when adding audio input and appending it to AVAssetWriterInput, the asset writer status changes to .failed.

if let sampleBuffer = sampleBuffer {
            if CMSampleBufferDataIsReady(sampleBuffer) {
                if assetWriter.status == .unknown {
                    let startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
                    assetWriter.startWriting()
                    assetWriter.startSession(atSourceTime: startTime)
                }
                if assetWriter.status == .failed {
                    print("writer error \(String(describing: assetWriter.error?.localizedDescription))")
                    return false
                }
                if isVideo {
                    if videoInputWriter.isReadyForMoreMediaData {
                        videoInputWriter.append(sampleBuffer)
                        return true
                    }
                } else {
                    if audioInputWriter.isReadyForMoreMediaData {
                        audioInputWriter.append(sampleBuffer)
                        return true
                    }
                }
            }
        }

The error message is

Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (-12780), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x600002841320 {Error Domain=NSOSStatusErrorDomain Code=-12780 "(null)"}}
1

There are 1 answers

2
Frank Rupprecht On

Welcome!

I'm guessing, but it seems you are using the same callback for processing the audio and video samples. The problem might be that audio and video samples will be delivered concurrently in different queues (threads), which means that assetWriter.startSession(atSourceTime: startTime) could be accidentally executed multiple times in different threads—which is not allowed.

You need to somehow (atomically) protect that call, for instance by using a separate synchronization queue. Alternatively, you could only start the session with the first video buffer that arrives and ignore any audio buffer that comes before that (which would also prevent accidental black frames at the beginning of the video).