本文系微信公众号和知乎专栏《MediaStack》原创文章,欢迎大家关注,随时进行交流。
问题背景
昨天小伙伴反馈一个问题,说我们的app和第三方客户IPC进行通信时候出现崩溃了,急需支援。
所以临危受命,3个小时完成突击,找到问题,紧急压测上线。在此记录一下该问题的排查过程。
后来拿到客户的IPC时候,进行本地验证,也是常用的三段论逐一排查:
  • 如果是生产端或发送端的问题,则在发送端送数据之时抓包;
  • 如果是消费端或接收端的问题,则在接收端收数据之时抓包;
  • 如果是传输段问题,则通过PC或者更换设备验证;
所以从发送端,接收端分别抓包,依次验证SPS,PPS参数,视频流分析,最后发现和抓包没有关系,属于app兼容性问题。
问题分析
然后通过抓取本地app的log,逐步分析,最初排查问题是线程崩溃
然后通过log,往回倒退,依次排查设置的参数,发现在其中一次设置时出现分辨率有明显的变化
最初怀疑对方发包异常,但是经过一通排查,然并不是。
所以重新开始从数据接收,解封包,解码以及排查,最后发现原来是H264 SPS解析时候异常了。
其中“祖传”代码中该值frame_cropping_flag采用了ue(payload_data, data_len, start_bit),这样正好IPC这边设置了chroma_format_idc,就会导致计算frame_crop_top_offset和frame_crop_bottom_offset错误。
找到问题很快就处理掉了,但是之前为啥没有出现问题呢?
分析了之前保存的抓包:大部分chroma_format_idc没有设置,所以crop都没有真正生效,所以隐藏bug一直没有暴雷。
补充知识
chroma_format_idc和frame_cropping_flag
依据H264 SPEC,可以看出chroma_format_idc读取方式是ue(v)和而frame_cropping_flag读取方式是u(1)
其中chroma_format_idc 指定亮度采样的色度采样。 chroma_format_idc 的值应在 0 到 3 的范围内(包括 0 和 3)。 当 chroma_format_idc 不存在时,应推断其等于 1(4:2:0 色度格式)。
frame_cropping_flag 等于 1 指定序列参数集中的下一个是帧裁剪偏移参数。frame_cropping_flag 等于 0 指定帧裁剪偏移参数不存在。而且只有High Profile及其以上时候才会设置为1,其他格式建议不进行设置,所以之前的坑没有爆。
u(1) VS ue(v)
H264的spec中指定了每个语法元素的解析过程。对于某些语法元素,使用由竖线分隔的两个描述符。在这些情况下,当 entropy_coding_mode_flag 等于 0 时应用左侧描述符,当 entropy_coding_mode_flag 等于 1 时应用右侧描述符。
其中u(n)表示使用 n 位的无符号整数。当语法表中n为“v”时,比特数以依赖于其他语法元素的值的方式变化。该描述符的解析过程由函数 read_bits( n ) 的返回值指定,该函数解释为无符号整数的二进制表示形式,并且首先写入最高有效位。
ue(v)无符号整数 Exp-Golomb 编码语法元素,左位在前。
关于u(1)和ue(v)的描述,在标准的第9章节有做详细介绍
如果感觉Spec理解困难,悄咪咪的告诉一个详细介绍指数哥伦布熵编码的地址,一般人我不告诉他:
https://www.zzsin.com/article/golomb.html
关于u(n)和ue(v)在FFMPEG中的实现,可以参考如下代码:
ff_cbs_read_unsigned()
ff_cbs_read_unsigned()函数用于从比特流中读取无符号整数。
ff_cbs_trace_syntax_element() 
ff_cbs_trace_syntax_element() 函数用于跟踪从比特流读取语法元素或向比特流写入语法元素
cbs_read_ue_golomb()
cbs_read_ue_golomb()函数用于使用一元指数 (UE) 哥伦布码从比特流中读取无符号整数。
同时也参考了最新版本的webrtc,其实现过程是另外一种,不过基本类似:
我是一枚爱跑步的程序猿,维护公众号和知乎专栏《MediaStack》,有兴趣可以关注,一起学习音视频知识,时不时分享实战经验。
继续阅读
阅读原文