2

I'm stuck on a really frustrating AVFoundation problem. I'm building a video editor that uses a custom AVVideoCompositor to add effects, and I need the final output to be 60 FPS.

So basically, I create an AVMutableComposition to sequence my video clips. I create an AVMutableVideoComposition and set the frame rate to 60 FPS: videoComposition.frameDuration = CMTime(value: 1, timescale: 60)

I assign my CustomVideoCompositor class to the videoComposition.

I create an AVPlayerItem with the composition and video composition.

The Problem:

Playback Works: When I play the AVPlayerItem in an AVPlayer, it's perfect. It plays at a smooth 60 FPS, and my custom compositor's startRequest method is called 60 times per second.

Export Fails: When I try to export the exact same composition and video composition using AVAssetExportSession, the final .mp4 file is always 30 FPS (or 29.97).

I've logged inside my custom compositor during the export, and it's definitely being called 30 times per second, so it's generating the 30 frames. It seems like AVAssetExportSession is just dropping every other frame when it encodes the video.

My source videos are screen recordings which I recorded using ScreenCaptureKit itself with the minimum frame interval to be 60.

Here is my export function. I'm using the AVAssetExportPresetHighestQuality preset :-

func exportVideo(to outputURL: URL) async throws {
    
    guard let composition = composition,
          let videoComposition = videoComposition else {
        throw VideoCompositionError.noValidVideos
    }
    try? FileManager.default.removeItem(at: outputURL)
    guard let exportSession = AVAssetExportSession(
        asset: composition,
        presetName: AVAssetExportPresetHighestQuality
    ) else {
        throw VideoCompositionError.trackCreationFailed
    }
    exportSession.outputFileType = .mp4
    exportSession.videoComposition = videoComposition // This has the 60fps setting

    try await exportSession.export(to: outputURL, as: .mp4)
}

I've created a bare bones sample project that shows this exact bug in action. The resulting video is 60fps during playback, but only 30fps during the export. https://github.com/zaidbren/SimpleEditor

My Question:

Why is AVAssetExportSession ignoring my 60 FPS frameDuration and defaulting to 30 FPS, even though AVPlayer respects it?

1 Answer 1

2

Using AVAssetExportPresetPassthrough instead of AVAssetExportPresetHighestQuality gives you 60 fps output for your sample app.

However once your AVComposition becomes more complicated, passthrough may fail or give you surprising results, because your composition needs to be transcoded, but passthrough does not transcode.

Your main problem is that AVAssetExportSession is configurable only through presets and if the presets don't cover your use case, then you're out of luck.

For more control, try transcoding with an AVAssetReader / AVAssetWriter pair.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.