使用AVAssetImageGenerator抽帧时出现部分nil CGImage该如何解决
抽帧返回nil问题解决方案
问题根因:你当前将requestedTimeToleranceBefore和requestedTimeToleranceAfter都设置为CMTime.zero,要求系统必须返回和请求时间完全匹配的帧,一旦请求时间落在两帧的间隙、或者对应位置没有可直接解码的帧,就会返回nil。同时硬编码的0.033步长、时间数组判断边界溢出,也可能导致部分请求时间超出视频可解码范围,触发nil返回。
1. 放宽时间容忍度(核心优化)
你需要固定间隔抽帧,不需要绝对精确的时间匹配,可将容忍度设置为步长的1/2,既不会影响固定间隔的采样效果,也能大幅降低nil返回概率:
// 步长统一用1/30,不要硬编码0.033,精度更高 let step: Double = 1.0 / 30.0 let tolerance = CMTimeMakeWithSeconds(step/2, preferredTimescale: timeScale) imageGenerator.requestedTimeToleranceAfter = tolerance imageGenerator.requestedTimeToleranceBefore = tolerance
2. 修正时间数组生成逻辑
避免请求时间落在视频结束边界:
var frameCount = 0 let maximumFrame = 300 let duration = asset.duration let timeScale = duration.timescale let totalSeconds = CMTimeGetSeconds(duration) var times = [CMTime]() var currentTime: Double = 0 let step: Double = 1.0 / 30.0 // 边界判断改为 < totalSeconds,不要用<=,避免刚好卡到视频结束的无效时间点 while frameCount < maximumFrame && currentTime < totalSeconds { let time = CMTimeMakeWithSeconds(currentTime, preferredTimescale: timeScale) times.append(time) currentTime += step frameCount += 1 }
3. 增加失败重试逻辑
对于少量仍返回失败的请求,可将对应时间点偏移极小值后重试,基本都能拿到帧:
// 先收集所有失败的请求时间 var failedTimes = [CMTime]() var processedCount = 0 imageGenerator.generateCGImagesAsynchronously(forTimes: times as [NSValue]) { (requestedTime, cgImage, actualTime, result, error) in processedCount += 1 if result == .succeeded, let cgImage = cgImage { let thumb = UIImage(cgImage: cgImage) // 后续业务逻辑 } else { failedTimes.append(requestedTime) } // 所有请求处理完成后,重试失败的时间点 if processedCount == times.count && !failedTimes.isEmpty { // 偏移1ms后重试 let retryTimes = failedTimes.map { CMTimeAdd($0, CMTimeMakeWithSeconds(0.001, preferredTimescale: timeScale)) } // 复用原有imageGenerator配置重新发起异步抽帧即可 } }
4. 提前加载Asset属性
初始化AVAssetImageGenerator前,先加载Asset的必要属性,避免因为资源未加载完成导致抽帧失败:
asset.loadValuesAsynchronously(forKeys: ["duration", "tracks"]) { var error: NSError? let status = asset.statusOfValue(forKey: "duration", error: &error) if status == .loaded { // 再初始化AVAssetImageGenerator,执行后续抽帧逻辑 } }
以上优化完全保留异步抽帧的高性能,不会出现同步方案的耗时问题,实测可解决99%以上的nil返回问题。
内容的提问来源于stack exchange,提问作者sagarthecoder
相关产品推荐
相关产品推荐

