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

AVAssetWriterInput的isReadyForMoreMediaData持续返回false问题求助

解决AVAssetWriterInput持续返回isReadyForMoreMediaData=false的问题

可能的原因及修复思路

1. 编码性能过载导致缓冲区阻塞

  • 检查AVVideoAverageBitRateKey设置的比特率是否过高:如果分辨率(比如4K)对应的比特率远超设备编码能力,编码器会积压大量待处理数据,直接导致写入器无法接收新数据。
    • 修复:根据设备性能动态调整比特率,比如1080p建议5-10Mbps,4K建议15-25Mbps;同时可以添加AVVideoMaxKeyFrameIntervalKey(比如设为帧率的2倍),减少关键帧编码压力。
  • 分辨率超出硬件编码能力:旧设备无法高效处理高分辨率实时编码,会拖慢写入流程。
    • 修复:根据设备芯片型号限制录制分辨率,比如给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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:55:22