读取H265视频发送RTP包到VLC播放出现花屏问题求助
HEVC RTP封包花屏问题根因与修复方案
现有代码的核心错误
当前封包逻辑仅实现了FU分片起始包的头部构造,缺少完整的分片生命周期处理,核心问题如下:
- FU头标记位处理不全:仅设置了起始分片的S位(bit7),未处理:
- 中间分片S=0、E=0的场景
- 末尾分片E位(bit6)置1的逻辑
VLC无法识别分片边界,无法拼接出完整的NAL单元供解码器解码,直接导致花屏
- 参数集发送逻辑缺失:没有周期性发送VPS、SPS、PPS三个参数集NAL单元,解码器缺少必要的解码参数,只能解析出错误的静止画面
- 同NAL分片属性错误:如果同一个NAL单元的多个分片RTP时间戳不一致、序列号不连续,也会导致拼接失败
修复代码示例
uint8_t nal_type = (buf[0] >> 1) & 0x3F; // 构造HEVC RTP Payload Header(FU-A类型) s->buf[0] = 49 << 1; // F=0, Type=49(FU-A), 低1位为LayerId最高位,LayerId=0所以为0 s->buf[1] = 0x01; // LayerId低6位为0,TID=1(nuh_temporal_id_plus1=1) int offset = 4; // 假设是4字节起始码,跳过起始码从第5位(索引4)开始取数据 int remain_len = buf_len - offset; int fu_payload_size = RTP_PAYLOAD_MAX - 3; // 减去2字节Payload Header +1字节FU头 while(remain_len > 0) { int cur_len = remain_len > fu_payload_size ? fu_payload_size : remain_len; // 构造FU头 uint8_t fu_header = nal_type; if(offset == 4) { // 起始分片 fu_header |= 1 << 7; // S位置1 } if(cur_len == remain_len) { // 末尾分片 fu_header |= 1 << 6; // E位置1 } s->buf[2] = fu_header; // 拷贝payload数据 memcpy(s->buf + 3, buf + offset, cur_len); // 发送RTP包,注意同一个NAL的所有分片时间戳完全相同,序列号连续递增 rtp_send(s->buf, cur_len + 3, timestamp); offset += cur_len; remain_len -= cur_len; }
额外校验点
- 确认SDP配置正确,H265的rtpmap、fmtp参数匹配流属性,最好把VPS/SPS/PPS的base64编码写到sprop-parameter-sets字段
- 确认起始码长度,如果是3字节起始码(0x000001),需要跳过3字节而不是5字节,避免截断NALU头
- 确认参数集NAL(类型32、33、34分别对应VPS、SPS、PPS)不要分片,直接作为单NALU包发送,不需要走FU分片逻辑

内容的提问来源于stack exchange,提问作者dinesh47
相关产品推荐
相关产品推荐

