Swift: AVAssetWriter output issue with duration

276 Views Asked by At

I am using AVAssetWriter to write data captured using AVCaptureOutput. I can able to create the output mp4 but the mp4 generated duration is not in sync with actual frames captured. For eg: If I recorded video for 30 sec with 30fps (900 frames) then the duration of the output mp4 files is 30.05 which is not the actual one expected.

But the same test If I did without appending audio then I am getting the exact duration of 30.0sec.

Here is my code used. Why the durations are mismatching with and without audio?

This .05 seconds is affecting with bigger impact in total duration when I try to merge large number of files.

public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        guard CMSampleBufferDataIsReady(sampleBuffer) else {
            return
        }

 if sessionAtSourceTime == nil{
                sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
                videoWriter.startSession(atSourceTime: sessionAtSourceTime!)
    }
       if output is AVCaptureVideoDataOutput  && videoWriterInput.isReadyForMoreMediaData {
              videoWriterInput.append(sampleBuffer)
       }else if output is AVCaptureAudioDataOutput &&  audioWriterInput.isReadyForMoreMediaData {
             audioWriterInput.append(sampleBuffer)
       }   
    }

func setupWriter() {
 let url = "URL"
videoWriter = try AVAssetWriter(url: url, fileType: AVFileType.mp4)

         //Add video input
         videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [
           AVVideoCodecKey: AVVideoCodecType.h264,
           AVVideoWidthKey: frameSize.width,
           AVVideoHeightKey: frameSize.height,
                 AVVideoCompressionPropertiesKey: [
                    AVVideoAverageBitRateKey: 1000000 * bitRate //16  //2300000,
                 ],
             ])
         videoWriterInput.mediaTimeScale = CMTimeScale(bitPattern: 600)
         videoWriterInput.expectsMediaDataInRealTime = true
         if videoWriter.canAdd(videoWriterInput) {
             videoWriter.add(videoWriterInput)
         }

         //Add audio input
         audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: [
                 AVFormatIDKey: kAudioFormatMPEG4AAC,
                 AVNumberOfChannelsKey: 1,
                 AVSampleRateKey: 44100,
                 AVEncoderBitRateKey: 64000,
             ])
         audioWriterInput.expectsMediaDataInRealTime = true
         if videoWriter.canAdd(audioWriterInput) {
             videoWriter.add(audioWriterInput)
         }

         videoWriter.startWriting() 
}
1

There are 1 best solutions below

0
On

Your code looks fine. Try changing the start time to this:

videoWriter.startSession(atSourceTime: CMClockGetTime(CMClockGetHostTimeClock()))

I would also try doing it outside of the captureOutput function.