设置AVAssetExportSession的videoComposition时AVAsset视频旋转不生效
解决AVAssetExportSession旋转视频不生效的问题
我之前也碰到过类似的坑,你用AVAssetWriter写完视频后,用AVAssetExportSession设置旋转没生效,大概率是没处理好原视频的轨道信息、导出参数或者transform的组合方式。下面给你一步步排查和解决的方法:
1. 先检查原视频的旋转元数据
有时候你捕获的视频本身已经带有旋转信息,直接叠加新的transform会导致冲突。先打印原视频轨道的preferredTransform看看:
let firstAsset = AVURLAsset(url: self.movieURL() as URL) if let videoTrack = firstAsset.tracks(withMediaType: .video).first { print("原视频轨道旋转信息:\(videoTrack.preferredTransform)") }
如果输出不是.identity,说明原视频已经有旋转设置,后续要基于这个transform来叠加你需要的90度旋转。
2. 正确组合旋转Transform
不要直接给exportSession设置单一的旋转transform,要和原视频的transform拼接起来,这样才会生效。比如你要顺时针旋转90度,可以这么写:
guard let exporter = AVAssetExportSession(asset: firstAsset, presetName: AVAssetExportPresetHighestQuality) else { print("创建导出会话失败") return } // 获取原视频轨道的transform guard let videoTrack = firstAsset.tracks(withMediaType: .video).first else { return } let originalTransform = videoTrack.preferredTransform // 组合90度顺时针旋转的transform(如果要逆时针就用 -.pi/2) let rotation90 = CGAffineTransform(rotationAngle: .pi/2) let finalTransform = originalTransform.concatenating(rotation90) exporter.outputTransform = finalTransform
3. 确保导出格式支持旋转元数据
有些视频格式对旋转信息的兼容性不好,建议优先用.mov格式,或者确认.mp4的设置正确:
exporter.outputFileType = .mov
4. 输出路径必须唯一
如果导出的URL和原视频URL相同,会导致覆盖失败或者读取异常,一定要设置一个新的输出路径:
// 生成临时输出路径,你也可以改成自定义的沙盒路径 let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("rotated_video_\(Date().timeIntervalSince1970).mov") // 如果路径已存在,先删除 if FileManager.default.fileExists(atPath: outputURL.path) { try? FileManager.default.removeItem(at: outputURL) } exporter.outputURL = outputURL
5. 完善导出回调的错误处理
导出完成后一定要检查状态,看看有没有报错,方便定位问题:
exporter.exportAsynchronously { [weak self] in DispatchQueue.main.async { switch exporter.status { case .completed: print("旋转完成!视频路径:\(outputURL)") // 这里可以把视频保存到相册或者做其他处理 case .failed: print("导出失败:\(exporter.error?.localizedDescription ?? "未知错误")") case .cancelled: print("导出被取消") default: break } } }
额外提醒:写入视频时的方向处理
如果上面的方法还是没效果,可能是你用AVAssetWriter写入的时候就没正确设置方向。捕获视频时,要把设备方向转换成AVAssetWriterInput的transform,比如:
// 自定义方法,根据当前设备方向返回对应的transform func getCaptureTransform() -> CGAffineTransform { let orientation = UIDevice.current.orientation switch orientation { case .portraitUpsideDown: return CGAffineTransform(rotationAngle: .pi) case .landscapeLeft: return CGAffineTransform(rotationAngle: .pi/2) case .landscapeRight: return CGAffineTransform(rotationAngle: -.pi/2) default: return .identity } } // 给AVAssetWriterInput设置transform videoInput.transform = getCaptureTransform()
按照这些步骤调整,应该就能解决旋转不生效的问题了。
内容的提问来源于stack exchange,提问作者Chewie The Chorkie
相关产品推荐
相关产品推荐

