You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

读取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 22:54:01