AVAssetWriterInput的isReadyForMoreMediaData持续返回false问题求助
解决AVAssetWriterInput持续返回isReadyForMoreMediaData=false的问题
可能的原因及修复思路
1. 编码性能过载导致缓冲区阻塞
- 检查
AVVideoAverageBitRateKey设置的比特率是否过高:如果分辨率(比如4K)对应的比特率远超设备编码能力,编码器会积压大量待处理数据,直接导致写入器无法接收新数据。- 修复:根据设备性能动态调整比特率,比如1080p建议5-10Mbps,4K建议15-25Mbps;同时可以添加
AVVideoMaxKeyFrameIntervalKey(比如设为帧率的2倍),减少关键帧编码压力。
- 修复:根据设备性能动态调整比特率,比如1080p建议5-10Mbps,4K建议15-25Mbps;同时可以添加
- 分辨率超出硬件编码能力:旧设备无法高效处理高分辨率实时编码,会拖慢写入流程。
- 修复:根据设备芯片型号限制录制分辨率,比如给A11以下芯片限制在1080p以内。
2. 异步写入队列调度不合理
你把append(buffer)放在processQueue.async中,如果这个队列是串行队列且有其他耗时任务,会导致append操作被延迟,写入器缓冲区一直处于满载状态。
- 修复:让
processQueue成为专门处理AVAssetWriter写入的串行队列,不要在这个队列中执行编码、压缩等其他耗时操作;或者在确认isReadyForMoreMediaData为true时,直接同步执行append(注意不要阻塞主线程,建议在专门的后台线程处理帧接收与写入判断)。
3. 未利用系统通知监听就绪状态
不要只在收到帧时单次检查isReadyForMoreMediaData,应该依靠系统通知来触发写入,避免错过写入器就绪的时机。
- 修复:
同时,遇到// 初始化videoInput后添加通知监听 NotificationCenter.default.addObserver( self, selector: #selector(handleMediaDataReady), name: .AVAssetWriterInputMediaDataReadyForMoreData, object: videoInput ) // 处理就绪通知的方法 @objc private func handleMediaDataReady() { // 用缓存队列暂存未写入的帧,通知触发时批量处理 while videoInput?.isReadyForMoreMediaData == true, let cachedBuffer = frameCache.first { frameCache.removeFirst() videoInput?.append(cachedBuffer) } }isReadyForMoreMediaData为false时,不要直接丢弃帧,把帧缓存到队列里等待处理。
4. 缓冲区时间戳异常
如果传入的CMSampleBuffer时间戳不连续、重复或者时间线混乱,AVAssetWriter会卡住并拒绝接收新数据。
- 修复:
- 确保每个缓冲区的时间戳基于
CMClockGetHostTimeClock()生成,且严格递增; - 检查是否存在重复时间戳或时间跳跃过大的情况,必要时修正时间戳后再执行append。
- 确保每个缓冲区的时间戳基于
5. 未检测写入器错误状态
AVAssetWriter或AVAssetWriterInput进入错误状态(比如磁盘空间不足、写入权限异常)时,isReadyForMoreMediaData会一直返回false,但你当前没有做状态检测。
- 修复:
同时监听// 在关键节点检查写入器状态 if let writer = assetWriter, writer.status == .failed { print("录制错误:\(writer.error?.localizedDescription ?? "未知错误")") // 这里执行错误处理逻辑,比如停止录制、提示用户清理磁盘空间 }AVAssetWriterFailedNotification,及时捕获写入失败事件。
6. 实时缩放增加编码负担
你设置了AVVideoScalingModeResizeAspect,如果输入缓冲区的尺寸和输出设置的宽高不匹配,会触发实时缩放计算,加剧编码压力导致写入阻塞。
- 修复:在屏幕捕获阶段就调整分辨率,确保输入的CMSampleBuffer尺寸和
videoSettings中的宽高一致,避免实时缩放。
额外注意点
- 不要用
RunLoop.current.run(until:)来等待就绪,这会阻塞当前线程,反而让问题更严重; expectsMediaDataInRealTime设为true是正确的,但要确保写入速度能跟上录制帧率(比如30fps的话,每33ms要完成一帧的写入)。
内容的提问来源于stack exchange,提问作者LiYanan2004
相关产品推荐
相关产品推荐

