You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用VLC库将BGRA格式帧渲染到AVSampleBufferDisplayLayer并实现画中画(PiP)时的iOS兼容性及画中画异常问题

VLC库将BGRA格式帧渲染到AVSampleBufferDisplayLayer并实现画中画(PiP)时的iOS兼容性及画中画异常问题

嘿,我来帮你拆解这两个问题,我之前做VLC帧渲染+PiP的项目时也踩过类似的坑,咱们一步步来解决:

一、iOS 16.x视频不显示,iOS 18.x正常的问题

这个问题核心是不同iOS版本对AVSampleBufferDisplayLayer的格式校验、线程要求差异导致的,iOS 16及更早版本的兼容性限制更严格:

  • 先核对帧参数的兼容性
    iOS 16对BGRA帧的字节对齐、行间距(stride)要求很严,VLC输出的原始BGRA数据可能存在stride不符合16字节对齐的情况。你可以先从userData.img里取出帧的宽、高、原始数据指针,手动计算正确的stride:正确stride = ceil(宽度 * 4 / 16) * 16,如果VLC返回的stride不符合这个值,要手动调整数据的内存布局。

  • 正确封装BGRA帧为CVPixelBuffer
    直接把raw BGRA数据丢给AVSampleBufferDisplayLayer在iOS16上会失败,必须封装成标准的CVPixelBuffer

    1. 使用CVPixelBufferCreateWithBytes创建像素缓冲区,格式指定为kCVPixelFormatType_32BGRA(这是AVLayer兼容的标准BGRA格式),传入调整后的stride和原始数据指针。
    2. CVPixelBuffer包装成CMSampleBuffer,注意要设置正确的CMTime时间戳(可以用VLC提供的帧时间戳转换)。
    3. 必须在主线程调用[displayLayer enqueueSampleBuffer:sampleBuffer],iOS16严格要求图层操作在主线程,iOS18可能自动做了线程适配。
  • 检查图层基础配置
    确保AVSampleBufferDisplayLayervideoGravity设置为AVLayerVideoGravityResizeAspect,已经添加到视图的layer层级中,并且显式设置needsDisplayOnBoundsChange = YES,iOS16需要这个属性来触发渲染。

二、PiP激活后主视图继续播放、PiP窗口黑屏的问题

这个是因为PiP会话没有正确接管帧的输出链路,系统没有把帧导向PiP窗口,反而主图层还在持续渲染:

  • 正确绑定PiP控制器与DisplayLayer
    不要手动同时给主图层和PiP窗口发帧,要通过AVPictureInPictureControllerContentSourceAVSampleBufferDisplayLayer和PiP控制器绑定:

    1. 创建AVPictureInPictureControllerContentSource时,把你的AVSampleBufferDisplayLayer作为视频源传入,这样系统会自动处理帧在主视图和PiP窗口之间的分发。
    2. 确保你的视图控制器实现了AVPictureInPictureControllerDelegate的核心方法,比如pictureInPictureControllerWillStartPictureInPicture:,在这个方法里暂停主图层的帧入队(停止调用enqueueSampleBuffer),让PiP会话接管帧输出。
  • 严格校验帧的时间戳
    PiP窗口黑屏很多时候是因为CMSampleBuffer的时间戳不合法,要确保每个帧的CMTime是严格递增的,并且时间基准(CMTimeScale)统一(比如用90000的标准时间刻度),iOS16对时间戳的校验比iOS18更严格,非法时间戳会导致PiP窗口无法渲染。

  • 停止主视图的渲染链路
    激活PiP后,一定要停止往主视图的AVSampleBufferDisplayLayer入队新的帧,同时调用[displayLayer flush]清空主图层的缓存,避免主视图继续渲染覆盖PiP的占位符。

备注:内容来源于stack exchange,提问作者Krenem00

火山引擎 最新活动