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

iOS中AVAssetExportSession裁剪视频后Network发送未生效问题排查

问题排查与解决

核心问题1:裁剪起始时间未正确赋值

在autoTrimBeforeSending函数中,你计算了startTimeSec = videoDurationInSeconds - VideoConstants.autoTrimSec(即取最后4秒),但这个计算后的值并没有被用来创建startCMTime,你依然使用了初始的startTimeSec = 0.0生成起始时间,导致裁剪范围还是从视频开头到结尾,等于没有执行有效裁剪。

修改后的autoTrimBeforeSending代码:

func autoTrimBeforeSending(completion: @escaping () -> Void) {
    let options: [String : Any] = [AVURLAssetPreferPreciseDurationAndTimingKey: false]
    let videoURLAsset = AVURLAsset(url: theVideoURL, options: options)
    let videoDurationInSeconds = videoURLAsset.duration.seconds
    // 直接计算目标起始时间
    let startTimeSec = videoDurationInSeconds - VideoConstants.autoTrimSec // 取最后4秒
    // 用计算后的起始时间创建CMTime
    let startCMTime = CMTimeMakeWithSeconds(startTimeSec, preferredTimescale: 600)
    let composition = AVMutableVideoComposition(propertiesOf: videoURLAsset)
    let endTime = CMTimeMakeWithSeconds(videoDurationInSeconds, preferredTimescale: 600)
    
    VideoUtils.export(videoURLAsset, to: theVideoURL, startTime: startCMTime, endTime: endTime, composition: composition, completion: { _ in
        completion()
    })
}

核心问题2:输入输出URL相同可能引发异常

你将导出的输出URL设置为原视频的URL(theVideoURL),虽然代码中先尝试删除旧文件,但如果原视频文件此时正被AVURLAsset持有引用,可能会导致删除失败或者导出过程中出现文件占用问题,最终导出失败但你未处理completion的false状态,直接执行了发送逻辑。

建议改为使用临时文件URL作为输出,示例:

func autoTrimBeforeSending(completion: @escaping () -> Void) {
    let options: [String : Any] = [AVURLAssetPreferPreciseDurationAndTimingKey: false]
    let videoURLAsset = AVURLAsset(url: theVideoURL, options: options)
    let videoDurationInSeconds = videoURLAsset.duration.seconds
    let startTimeSec = videoDurationInSeconds - VideoConstants.autoTrimSec
    let startCMTime = CMTimeMakeWithSeconds(startTimeSec, preferredTimescale: 600)
    let composition = AVMutableVideoComposition(propertiesOf: videoURLAsset)
    let endTime = CMTimeMakeWithSeconds(videoDurationInSeconds, preferredTimescale: 600)
    
    // 生成临时输出URL
    let tempDir = FileManager.default.temporaryDirectory
    let tempOutputURL = tempDir.appendingPathComponent("trimmed_video_\(UUID().uuidString).mov")
    
    VideoUtils.export(videoURLAsset, to: tempOutputURL, startTime: startCMTime, endTime: endTime, composition: composition, completion: { success in
        if success {
            networkSession.sendVideo(from: tempOutputURL)
            // 发送完成后清理临时文件
            try? FileManager.default.removeItem(at: tempOutputURL)
        } else {
            // 处理导出失败逻辑,比如提示用户
        }
        completion()
    })
}

额外注意:处理导出失败的情况

当前代码中忽略了export回调的失败状态,直接调用completion(),这会导致即使导出失败,依然执行发送原视频的逻辑。建议根据success状态决定是否继续发送,避免发送未裁剪的原视频。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:32:54