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

AVSampleBufferDisplayLayer实现画中画(PIP)仅显示加载指示器问题排查

问题根因与修复方案

你的实现存在以下几处问题,按优先级排序如下:

  • 未配置AVAudioSession权限
    画中画功能强制要求App提前激活播放类型的音频会话,即使你的视频内容没有音轨也必须配置,否则系统会拒绝渲染PIP窗口内容,仅显示加载指示器。
    修复代码:在viewDidLoad或viewDidAppear中添加如下配置:
    do {
        try AVAudioSession.sharedInstance().setCategory(.playback)
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {
        print(error)
    }
    
  • 未开启后台PIP权限
    需要在Xcode项目的Signing & Capabilities中添加Background Modes能力,勾选Audio, AirPlay, and Picture in Picture选项,否则PIP功能无法正常调用。
  • 播放时间范围返回逻辑错误
    你当前在pictureInPictureControllerTimeRangeForPlayback代理方法中依赖缓冲队列首个元素的时长返回时间范围,当PIP启动时缓冲队列为空,会返回无效的时间区间,导致PIP无法识别流类型。由于你是实时生成流内容,应该统一返回直播流的时间范围:
    func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
        // 直播流固定返回开始为0,时长为正无穷
        return CMTimeRange(start: .zero, duration: .positiveInfinity)
    }
    
  • setPlaying代理方法空实现
    PIP启动时会主动调用该方法通知你需要开始/暂停播放内容,你需要在该方法中保证缓冲入队逻辑正常运行,不要阻塞流输出,简单标记播放状态保证requestMediaDataWhenReady的回调持续入队有效缓冲即可。
  • SampleBuffer时间戳不连续
    你每次录制1秒视图生成的视频文件,提取的SampleBuffer时间戳都是从0开始计数,入队到同一个AVSampleBufferDisplayLayer时会出现时间戳回退的问题,导致渲染队列卡住。你需要维护一个全局的时间偏移量,给每个新入队的SampleBuffer重新打时间戳,保证时间线单调递增。
  • 频繁调用flush清空缓冲
    你每次录制完成都调用layer.flush(),会清空所有已入队的缓冲,PIP启动时如果刚好触发flush操作,就会出现无缓冲可渲染的问题,建议移除不必要的flush调用,仅在需要重置播放时调用。
  • PIP控制器初始化时机过晚
    你当前在第一次录制完成的异步回调中才初始化PIP控制器,如果在录制完成前点击启动PIP按钮,控制器为nil不会正常启动,建议将PIP控制器的初始化逻辑提前到viewDidLoad或viewDidAppear中,不要依赖录制回调。

内容的提问来源于stack exchange,提问作者Emma Labbé

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 12:36:03