视频导出卡住问题分析与解决方案
问题描述
现象
在导出某些特定时间范围的视频片段时,导出进度会卡在 23% 左右无法继续,持续数分钟甚至更长时间都没有进展。但是,如果将开始时间向前调整一点点(比如 0.2 秒),或者将结束时间向后调整一点点,导出就能正常完成。
具体案例
- 失败的时间范围: 65.328s - 73.529s → 卡在 23% 不动
- 成功的时间范围: 调整开始/结束时间后 → 正常导出完成
系统环境
- iOS 18+
- 使用 AVAssetExportSession 进行视频导出
- 导出状态显示为 “exporting”(正在导出中),没有报错
- 进度条长时间停留在某个百分比不变
问题分析过程
第一步:添加诊断日志
为了定位问题,我们添加了详细的诊断功能:
进度卡住检测
- 监控导出进度是否在同一数值停留超过 10 秒
- 发现确实卡在 23% 持续很长时间
关键帧分析
- 分析视频编码结构
- 检查时间范围起始点和结束点附近的关键帧(I-frame)分布
第二步:关键帧分析结果
通过分析发现了关键信息:
1 | 🔍 关键帧分析: |
第三步:根本原因确定
关键帧对齐问题
视频编码采用 GOP (Group of Pictures) 结构:
- 关键帧(I-frame): 完整的图像数据,可以独立解码
- 预测帧(P-frame/B-frame): 依赖其他帧的差异数据
当裁剪时间范围的起始点不在关键帧上时:
AVAssetExportSession 无法直接复制压缩数据
- 因为预测帧需要依赖前面的关键帧才能解码
系统尝试重新编码
- 从最近的关键帧(65.11s)开始解码
- 重新编码 65.11s → 65.328s 之间的帧
在某些边界条件下会卡住
- 视频合成(videoComposition)的时间指令可能与实际视频轨道不匹配
- 导致导出进程无法继续
验证假设
当我们将开始时间从 65.328s 调整到最近的关键帧 65.11s 时,导出能正常完成,证实了关键帧对齐问题是根本原因。
解决方案
方案设计原则
在视频处理的入口点进行对齐
- 在
processVideo方法中,创建所有视频合成(videoComposition)之前 - 确保所有后续处理都基于对齐后的时间范围
- 在
对齐策略
- 起始点: 只向前对齐(提前开始),不向后,确保不丢失用户想要的内容
- 结束点: 可以向前或向后对齐,误差小即可
- 安全限制: 调整量不超过 1 秒,避免过度偏离用户意图
为什么不能在导出阶段对齐?
- 如果在创建 AVAssetExportSession 时才对齐时间范围
- videoComposition 中的轨迹绘制、慢动作等时间指令已经基于原时间范围创建
- 会导致 “The video could not be composed” 错误(-11841)
实现步骤
1. 关键帧查找
实现 findNearestKeyFrame() 函数:
- 使用 AVAssetReader 读取视频帧
- 检查每一帧的 attachment 属性判断是否为关键帧
- 返回目标时间附近最近的关键帧时间
2. 时间范围对齐
实现 alignTimeRangeToKeyFrames() 函数:
- 查找起始点最近的关键帧(只向前查找)
- 查找结束点最近的关键帧(可前后查找)
- 返回对齐后的时间范围
3. 在入口点应用对齐
在 processVideo 方法中:
1 | 原始时间范围 → 对齐到关键帧 → 创建 videoComposition → 导出 |
效果验证
对齐前 (失败)
1 | 时间范围: 65.328s - 73.529s |
对齐后 (成功)
1 | 原始范围: 65.328s - 73.529s |
技术要点总结
1. 视频编码基础
- GOP 结构:关键帧 + 预测帧
- 关键帧间隔通常 0.5-2 秒
- 裁剪操作最好对齐关键帧
2. AVFoundation 导出机制
- AVAssetExportSession 优先复制压缩数据(快速)
- 无法对齐时需要重新编码(慢,可能失败)
- videoComposition 的时间指令必须与视频轨道时间匹配
3. 用户体验考虑
- 自动对齐是透明的,用户无感知
- 起始点向前调整不会丢失内容
- 结束点微调(< 0.1s)用户难以察觉
- 调整量有上限(1秒),避免过度偏离
4. 诊断方法
- 添加进度卡住检测
- 分析关键帧分布
- 检查导出状态和错误信息
- 验证时间范围对齐情况
参考资料
文档版本: 1.0
创建日期: 2026-02-09
最后更新: 2026-02-09