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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 12:18:20