如何为AVAssetWriterInput设置预期帧率?解决高帧率视频慢动作问题
解决高帧率视频编码时出现慢动作的问题
嘿,我之前做视频处理工具的时候也碰到过一模一样的问题!当处理120fps以上的视频时,输出结果变成慢动作,核心原因是AVAssetWriter没有正确识别输入帧的实际帧率,导致它默认用了较低的标准帧率(比如30fps)来合成视频,把原本快速的帧序列拉长播放了。下面是我亲测有效的解决步骤:
1. 正确使用AVVideoExpectedSourceFrameRateKey
你提到的这个键,不能直接设置给AVAssetWriterInput的属性,而是要放在视频输出设置字典里,作为初始化AVAssetWriterInput的参数之一。很多人在这里踩坑,直接把键加到错误的地方,导致不生效。
举个Swift代码示例:
// 先获取源视频的实际帧率(不要硬编码,适配不同帧率的视频) let sourceVideoTrack = yourSourceAsset.tracks(withMediaType: .video).first! let sourceFrameRate = sourceVideoTrack.nominalFrameRate // 构建视频输出设置字典 let videoSettings: [String: Any] = [ AVVideoCodecKey: AVVideoCodecType.h264, // 或者你用的其他编码格式 AVVideoWidthKey: outputSize.width, AVVideoHeightKey: outputSize.height, AVVideoExpectedSourceFrameRateKey: sourceFrameRate // 关键:这里传入源帧率 ] // 用包含帧率设置的字典初始化AVAssetWriterInput let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
2. 确保每帧的时间戳准确对应帧率
慢动作的另一个常见原因是:你传入AVAssetWriterInput的CMSampleBuffer时间戳间隔不对。比如源视频是120fps,每帧的时间间隔应该是1/120秒,但如果你的代码里错误地用了1/30秒的间隔,AVAssetWriter就会认为这是30fps的视频,把120帧拉成4秒播放,自然变成慢动作。
处理帧的时候,一定要计算正确的展示时间戳:
// 假设frameIndex是当前处理的帧序号(从0开始) let frameDuration = CMTimeMake(value: 1, timescale: Int32(sourceFrameRate)) let presentationTime = CMTimeMultiply(frameDuration, Int64(frameIndex)) // 将这个presentationTime设置到你的CMSampleBuffer中 // 比如创建SampleBuffer时,用CMSampleBufferCreateWithImageBuffer等方法指定时间戳
3. 调整expectsMediaDataInRealTime属性
如果你的视频处理是离线模式(不是实时摄像头采集),一定要把AVAssetWriterInput的这个属性设为false:
videoInput.expectsMediaDataInRealTime = false
如果设为true,AVAssetWriter会强制按实时速度处理帧,高帧率下可能因为处理速度跟不上,导致时间轴异常或者丢帧,最终出现慢动作效果。
4. 验证输出视频的帧率
写完视频后,建议验证一下输出结果的实际帧率,确认问题是否解决:
let outputAsset = AVAsset(url: yourOutputVideoURL) guard let outputVideoTrack = outputAsset.tracks(withMediaType: .video).first else { return } print("输出视频实际帧率:\(outputVideoTrack.nominalFrameRate)")
如果打印结果和你设置的源帧率一致(比如120),说明问题已经解决了。
内容的提问来源于stack exchange,提问作者Eugene Alexeev




