AVAssetExportSession exportAsynchronously导出过慢问题求解决方案
解决AVAssetExportSession无滤镜导出性能极差的问题
你遇到的问题根源在于使用了AVVideoComposition(asset:applyingCIFiltersWithHandler:)初始化视频合成对象——哪怕你的handler只是直接返回源图像,这个API也会强制将视频的每一帧都送入Core Image处理管线,包括像素格式转换、帧数据在CPU/GPU间来回传输等额外开销,完全没必要的处理流程拖慢了导出速度。正常情况下,若不需要对视频帧做任何处理,直接导出应该是接近实时甚至更快的。
解决方案:
- 仅在需要滤镜时才创建带CIFilter的AVVideoComposition:如果当前场景不需要任何滤镜,直接给
exportSession.videoComposition传nil,让系统走原生快速导出路径,跳过Core Image的处理环节。 - 若必须保留VideoComposition结构(比如后续要扩展滤镜),可以用更轻量的方式初始化AVVideoComposition,避免触发Core Image处理链。
修改后的代码示例:
场景1:不需要滤镜时直接导出
// 不需要滤镜时,不要创建带CIFilter的AVVideoComposition func exportVideo(completion: @escaping (_ outputURL: NSURL?) -> ()) { let exportSession = AVAssetExportSession(asset: self, presetName: AVAssetExportPresetHighestQuality)! let croppedOutputFileUrl = URL(fileURLWithPath: NSTemporaryDirectory() + NSUUID().uuidString + ".mov") exportSession.outputURL = croppedOutputFileUrl exportSession.outputFileType = AVFileType.mov // 关键:不需要处理的话,videoComposition设为nil exportSession.videoComposition = nil exportSession.exportAsynchronously(completionHandler: { guard exportSession.status != .failed else { completion(nil) return } if exportSession.status == .completed { DispatchQueue.main.async { completion(croppedOutputFileUrl as NSURL) } } else { completion(nil) } }) }
场景2:需要动态切换滤镜/无滤镜
// 先判断是否需要应用滤镜,再决定创建哪种VideoComposition func createVideoComposition(for asset: AVAsset, applyFilter: Bool) -> AVVideoComposition? { guard applyFilter else { // 不需要滤镜时,返回基于asset轨道的轻量合成对象,或者直接返回nil let track = asset.tracks(withMediaType: .video).first! let composition = AVMutableVideoComposition() composition.renderSize = track.naturalSize composition.frameDuration = track.minFrameDuration let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track) let instruction = AVMutableVideoCompositionInstruction() instruction.timeRange = CMTimeRangeMake(start: .zero, duration: asset.duration) instruction.layerInstructions = [layerInstruction] composition.instructions = [instruction] return composition } // 需要滤镜时才用Core Image的处理链 return AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in request.finish(with: request.sourceImage, context: nil) }) } // 导出函数调用时传入是否需要滤镜 func exportVideo(applyFilter: Bool, completion: @escaping (_ outputURL: NSURL?) -> ()) { let exportSession = AVAssetExportSession(asset: self, presetName: AVAssetExportPresetHighestQuality)! let croppedOutputFileUrl = URL(fileURLWithPath: NSTemporaryDirectory() + NSUUID().uuidString + ".mov") exportSession.outputURL = croppedOutputFileUrl exportSession.outputFileType = AVFileType.mov exportSession.videoComposition = createVideoComposition(for: self, applyFilter: applyFilter) exportSession.exportAsynchronously(completionHandler: { guard exportSession.status != .failed else { completion(nil) return } if exportSession.status == .completed { DispatchQueue.main.async { completion(croppedOutputFileUrl as NSURL) } } else { completion(nil) } }) }
补充说明:
AVAssetExportSession的预设(比如AVAssetExportPresetLowQuality)主要影响输出视频的分辨率、码率,无法抵消Core Image处理管线带来的固定开销,所以之前换预设没用。只有跳过不必要的帧处理流程,才能恢复导出性能。
内容的提问来源于stack exchange,提问作者SwiftiSwift
相关产品推荐
相关产品推荐

