MediaCodec解码H264 RTP视频流画面损坏,疑与SPS/PPS相关
解决MediaCodec解码H264 RTP流画面损坏的问题
这问题我之前帮不少开发者排查过,结合你说的“数据包完整有序、RTP头解析正确”的前提,大概率是SPS/PPS的处理逻辑或者MediaCodec的初始化/喂帧环节出了问题,咱们一步步拆解排查:
1. 优先确认SPS/PPS的正确处理
H264解码器必须先拿到SPS(序列参数集)和PPS(图像参数集)才能正确初始化解码上下文,这一步错了直接会导致全画面损坏:
- 从RTP流中提取SPS/PPS包后,先剥离RTP头,然后给原始NALU数据前加上
0x00000001起始码。 - 不要把SPS/PPS和普通帧一起塞输入缓冲区!你需要在
MediaCodec.configure()时,把SPS/PPS放进MediaFormat的KEY_SPS和KEY_PPS字段(用字节数组形式传入);如果流里周期性发送新的SPS/PPS,每次收到后要调用MediaCodec.setParameters()更新解码器参数。 - 注意:有些RTP流会把SPS和PPS打包在同一个NALU里(比如FU-A分片的情况),你要正确拆分出单独的SPS和PPS数据。
2. 普通NALU帧的拼接与起始码添加
除了SPS/PPS,普通I/P帧的处理也容易踩坑:
- 处理分片NALU(RTP头中
F字段为1,即分片单元):必须把属于同一个NALU的所有RTP分片拼接成完整的NALU,再添加0x00000001起始码。判断分片结束的标志是RTP头的M标记(最后一个分片的M位为1),不要单独喂单个分片给解码器。 - 非分片NALU:直接剥离RTP头后添加起始码即可,确保起始码是4字节的
0x00000001,不要用3字节的0x000001(虽然有些解码器兼容,但MediaCodec更推荐4字节起始码)。
3. MediaCodec的配置与喂帧细节
- MediaFormat配置:确保
KEY_MIME设为video/avc,KEY_WIDTH和KEY_HEIGHT和流的实际分辨率完全匹配;如果不确定分辨率,可以从SPS中解析出宽高(解析SPS的宽高是H264的标准操作,网上有现成的工具类)。 - 时间戳处理:喂给输入缓冲区的时间戳必须是微秒级,而RTP的时间戳一般是90kHz的,所以要转换:
rtpTimestamp * 1000000 / 90000。时间戳错误会导致解码器时序混乱,出现花屏或跳帧。 - 关键帧标记:当喂IDR帧时,在调用
queueInputBuffer时要加上BUFFER_FLAG_KEY_FRAME标记,告诉解码器这是关键帧,需要重置解码状态。
4. 调试验证技巧
- 把你处理后的所有NALU数据(加了起始码的)保存成
.264文件,用ffplay播放看看。如果文件能正常播放,说明RTP处理逻辑没问题,问题出在MediaCodec的配置或喂帧上;如果文件也花屏,那就是NALU拼接/起始码添加环节出错了。 - 解码过程中可以调用
MediaCodec.getOutputFormat(),检查输出的宽高是否正确,确认解码器是否成功初始化。
内容的提问来源于stack exchange,提问作者Brendan Cordingley
相关产品推荐
相关产品推荐

