You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AVAssetImageGenerator异步生成视频帧重复问题求助

Fixing Frame Duplication in generateCGImagesAsynchronously

It sounds like you're hitting a common gotcha with AVAssetImageGenerator's asynchronous method: default time tolerance settings that prioritize performance over precision. Let me break down what's happening and how to fix it.

What's Causing the Duplicate Frames?

By default, AVAssetImageGenerator uses non-zero values for requestedTimeToleranceBefore and requestedTimeToleranceAfter. This lets it return the nearest keyframe instead of the exact timestamp you requested—great for speed, but terrible for precision when you need every individual frame. In your case, the first second's keyframes are being reused for all subsequent timestamps that fall within the tolerance window, hence the repeated frames and mismatched timestamps.

Your synchronous copyCGImage(at:actualTime:) call works because it defaults to strict precision (unless you explicitly set a tolerance), which is why it’s slower but accurate.

The Fix: Enforce Exact Timestamp Matching

To get the precise frames you requested in the asynchronous method, you need to set both tolerance properties to kCMTimeZero. This tells the generator to ignore keyframe optimization and generate the exact frame at your requested time.

Here's how to update your code:

// First, initialize your image generator and set strict tolerance
let imageGenerator = AVAssetImageGenerator(asset: yourVideoAsset)
imageGenerator.requestedTimeToleranceBefore = kCMTimeZero
imageGenerator.requestedTimeToleranceAfter = kCMTimeZero

// Your existing NSValue array generation stays valid
var values : [NSValue] = [] 
let timeScale = 30 // Match your video's fps/timescale
let duration = 300 // 10s * 30fps
let frameDuration = CMTimeMake(1, timeScale) 
for i in 0..<duration{ 
    let lastFrameTime = CMTimeMake(Int64(i), timeScale) 
    let presentationTime = (i == 0) ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration) 
    values.append(NSValue(time: presentationTime)) 
}

// Run the asynchronous generation with the fixed generator
imageGenerator.generateCGImagesAsynchronously(forTimes: values) { (requestedTime, image, actualTime, result, error) in
    guard let image = image, result == .succeeded else {
        // Handle errors here (e.g., invalid time, asset issues)
        return
    }
    // Process your frame—now it should match the requested timestamp
    let imageUrl = FileManagerUtil.getTempFileName(parentFolder: FrameExtractor.EXTRACTED_IMAGE, fileNameWithExtension: "\(Constants.FRAME_SUFFIX)\(i)\".jpeg")
    // Save or use the image as needed
}

Additional Notes

  • Enforcing exact timestamps will increase processing time compared to the default asynchronous behavior, but it should still be faster than the synchronous method for bulk frame extraction. This tradeoff is necessary if you need frame-perfect results.
  • For better reliability, use your video asset's native duration.timescale instead of hardcoding a value like 30—this ensures your timestamp calculations align with the video's internal timing.
  • You can cross-verify using the actualTime parameter in the callback; with zero tolerance enabled, this should match your requestedTime exactly.

内容的提问来源于stack exchange,提问作者Mohammed Atif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:42:29