上周收到研发小伙伴反馈的一个问题,说一台特殊服务器发过来视频流会直接导致我们应用黑屏,而且一直无法恢复,需要协助一下。
之前也碰到很多黑屏问题,所以让相关同学提供一下抓包和log,以便进一步分析和兼容。
问题分析
拿到抓包之后,一通猛分析,发现了一个端倪:STAP-A包后满都带着一个Access Delimiter Prefix字样,强烈的直觉大概率就是这个东西导致的,。
查找H264的 Spec可以得到如下定义
- 访问单元分隔符 (AUD):AUD 是可选的 NALU,可用于分隔基本流中的帧。它不是必需的(除非容器/协议另有说明,例如 TS),并且通常不包含它以节省空间,但它对于查找帧的开头而不需要完全解析每个 NALU 很有用。
H.264 中的访问单元分隔符 (AUD) 是一种特殊类型的网络抽象层 (NAL) 单元,用于指示新访问单元的开始。AUD 并不是解码 H.264 视频所必需的,但它对于流媒体和视频会议等应用非常有用。AUD 可以插入到 H.264 视频流中的任意位置。通常AUD通常被插入到每个访问单元的开头。
AUD的优点:
- 提高对网络错误的鲁棒性:AUD 可以帮助提高 H.264 视频对网络错误的鲁棒性。如果帧丢失,如果下一帧前面有 AUD,则解码器仍然可以解码下一帧。
- 减少延迟:AUD 可以帮助减少 H.264 视频的延迟。解码器一收到该帧的 AUD 就可以开始解码该帧。
- 改进的同步:AUD 可以帮助改进编码器和解码器之间 H.264 视频的同步。
AUD 的一些缺点:
- 增加标头开销:AUD 向视频流添加一些额外的标头开销。
- 编码器的复杂性增加:AUD 给编码器增加了一些额外的复杂性。
AUD 对于流媒体和视频会议等应用程序非常有用。例如,AUD可用于:
- 如果网络拥塞,允许解码器丢弃帧。
- 提高 H.264 视频对网络错误的鲁棒性。
- 减少 H.264 视频的延迟。
- 提高 H.264 视频编码器和解码器之间的同步性。
以下是AUD的一些具体应用场景:
- 流媒体:AUD 可用于允许解码器在网络拥塞时丢弃帧。这可以帮助用户保持流畅的播放体验。
- 视频会议:AUD可用于提高H.264视频对网络错误的鲁棒性。这有助于减少丢帧数量并提高视频通话的整体质量。
- 容错视频编码:AUD可用于提高H.264视频的容错能力。例如,AUD 可用于标记新片组的开始。即使切片组中的一些 NAL 单元丢失,这也允许解码器继续解码。
解决方案
由于该单元是可选的,所以给研发的建议是检测并跳过该单元即可。
补充知识
AUD在H264的Spec中NAL单元中相关定义如下:
AUD的 RBSP语法描述
访问单元分隔符将用于识别一个基本编码图像中存在的条带的类型以及简化访问单元之间边界的检测。没有与访问单元分隔符相关的标准化的解码过程。
primary_pic_type 表示基本编码图像所有条带的 slice_type 值都是表 7-5 列出的组的元素,并对应给出的primary_pic_type值。
Prefix单元 RBSP语法描述
H264 Spec中也给出了NAL单元的解码顺序如下:在基本编码图像的最后一个 VCL NAL 单元之后的第一个任何下列 NAL 单元代表了一个新的访问单元的开始。
- — 如果存在,解析访问单元分隔 NAL 单元
- — 如果存在,序列参数集(SPS) NAL 单元
- — 如果存在,图像参数集(PPS) NAL 单元
- — 如果存在,SEI NAL 单元
- — 如果存在,nal_unit_type 值在 14-18 之间(包括)的 NAL 单元
- — 总是存在,基本编码图像的第一个 VCL NAL 单元(总是存在)
特别备注:当一个访问单元分隔NAL单元存在时,它应该是第一个NAL单元。在任何访问单元中应至多有一个访问单元分隔NAL单元。
FFMPEG代码走读
ff_h264_decoder()
FFMPEG中ff_h264_decoder相关流程,如下图所示:
h264_decoder_frame()
之后会调用h264_decoder_frame相关接口:
h264_decode_frame函数是FFmpeg库中的一个函数,用于解码H.264视频帧,最终将解码后的帧复制到输出缓冲区。
decode_nal_units()
decode_nal_units()用于解码H.264 NAL单元。首先从缓冲区解析 H.264 NAL 单元。然后对每个 H.264 NAL 单元进行解码,并返回已解码的 H.264 NAL 单元的信息。
其中AUD相关内容直接返回不做处理。
CBS解码
CBS的解析也是一样的过程:
cbs_h264_read_aud()
cbs_h264_read_aud()函数最终调用FUNC(aud)函数。此函数用于解码访问单元定界符 (AUD) NAL 单元。
基本上也查阅了其他的编解码器,大部分是类似的操作,所以给研发小伙伴的建议跳过相关字节不处理。
参考资料
https://zhuanlan.zhihu.com/p/436803728
作者信息:我是一枚爱跑步的程序猿,维护公众号和知乎专栏《MediaStack》,有兴趣可以关注,一起学习音视频知识,时不时分享实战经验。
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。