H.264解码器工作异常求助:解码后CMSampleBuffer无法正常渲染
我之前也踩过几乎一模一样的坑!反复查解码器代码、调参数,没报错但就是不出画面,折腾了好几天才摸清楚门道。给你几个按优先级排序的排查方向:
先死磕时间戳(Presentation Time Stamp)
这是最容易被忽略但概率最高的问题!AVSampleBufferDisplayLayer对时间戳的连续性和合理性要求极其严格,哪怕你的CMSampleBuffer过了CMSampleBufferIsValid()校验,只要时间戳乱序、重复,或者时间基准(timeScale)和layer不匹配,它就会默默“吃”掉你的帧不渲染。
你可以打印每个buffer的presentationTimeStamp和duration,确保它们是严格递增的,而且统一用标准时间基准(比如CMTimeMakeWithSeconds(1, 1000)毫秒级)。另外,首次传帧前可以手动设置displayLayer.currentTime为第一个buffer的时间戳,强制它启动渲染。验证SPS/PPS是否正确注入解码器
H.264裸流的关键帧必须依赖SPS/PPS才能解码出可显示的画面,很多时候解码出的buffer看似有效,但实际因为缺少序列参数集,像素数据是无效的。你可以检查:- 是不是在解码第一个关键帧之前,就把包含SPS/PPS的NALU传给了解码器?
- 用
CMSampleBufferGetFormatDescription(buffer)获取格式描述,确认里面的AVVideoFormatDescription包含了正确的SPS/PPS数据。
检查像素格式兼容性
AVSampleBufferDisplayLayer只认特定的像素格式,iOS上最常用的是kCVPixelFormatType_420YpCbCr8BiPlanarFullRange和kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange。你可以用CVPixelBufferGetPixelFormatType(CMSampleBufferGetImageBuffer(buffer))查看解码后buffer的像素格式,如果是其他格式(比如RGB或者不兼容的YUV变体),layer根本不会渲染。这种情况要么在解码时指定输出格式,要么把buffer转成兼容格式。确认AVSampleBufferDisplayLayer的基础配置没漏
别小看最基础的配置,我见过有人忘了把layer加到视图层级里:- 有没有执行
view.layer.addSublayer(displayLayer)? - 有没有正确设置layer的
frame或bounds?如果layer尺寸是0,肯定看不到画面 - 有没有调用
displayLayer.requestMediaDataWhenReady(on: .main)启动渲染循环? - 试试调用
displayLayer.flush()清除缓存,再重新传入第一个buffer
- 有没有执行
深挖CMSampleBuffer的隐性问题
CMSampleBufferIsValid()返回true只是基础校验,不代表所有属性都正常:- 用
CMSampleBufferGetImageBuffer(buffer)获取CVPixelBuffer,确认它不是nil,而且CVPixelBufferLockBaseAddress(buffer, .readOnly)能成功(说明像素数据真的存在) - iOS 13+可以直接看buffer的
isReadyForDisplay属性,这个字段直接告诉你buffer能不能被显示层渲染
- 用
我当时就是因为时间戳的timeScale和layer默认的时间基准不匹配,导致明明buffer有效,layer却一直处于rendering状态但不输出画面。你可以先从时间戳入手排查,大概率能找到问题!
内容的提问来源于stack exchange,提问作者phil

