一、RTP包解析流程
sequenceDiagram
participant Receiver as 接收端
participant Parser as RTP解析器
participant PSParser as PS解析器
participant Decoder as H264解码器
Receiver->>Parser: 接收RTP包
Parser->>Parser: 解析RTP头部
Parser->>Parser: 检查负载类型(PT=96/98)
Parser->>PSParser: 提取RTP负载(PS数据)
PSParser->>PSParser: 解析PS包头
PSParser->>PSParser: 解析系统头
PSParser->>PSParser: 解析节目映射表
PSParser->>PSParser: 提取PES包
PSParser->>Decoder: 重组H264 NALU
二、关键数据结构定义
1. RTP头部结构
typedef struct {
uint8_t version_p_x_cc; // V=2,P=0,X=0,CC=0
uint8_t m_payload_type; // M=0, PT=96(PS)/98(H264)
uint16_t sequence_number; // 16位序列号
uint32_t timestamp; // 32位时间戳(90kHz)
uint32_t ssrc; // 同步源标识
} RtpHeader;
2. PS包头结构
typedef struct {
uint8_t start_code[4]; // 0x000001BA
uint16_t system_clock_ref_base; // 系统时钟基准
uint8_t stuffing_length; // 填充长度(3位)
// 其他字段省略
} PsHeader;
三、核心处理流程
1. RTP包接收与解析
void process_rtp_packet(uint8_t *buffer, int len) {
RtpHeader *rtp_hdr = (RtpHeader*)buffer;
// 验证RTP头部
if(rtp_hdr->version_p_x_cc != 0x80) return; // 非标准RTP
// 提取PS负载
uint8_t *ps_payload = buffer + 12; // 跳过12字节RTP头
int ps_len = len - 12;
// 处理PS数据
parse_ps_stream(ps_payload, ps_len);
}
2. PS流解析与重组
void parse_ps_stream(uint8_t *data, int len) {
while(len >= 4) {
if(memcmp(data, "\x00\x00\x01\xBA", 4) == 0) {
// 解析PS头
PsHeader *ps_hdr = (PsHeader*)data;
data += sizeof(PsHeader);
len -= sizeof(PesHeader);
// 处理系统头
parse_system_header(data);
// 处理节目映射表
parse_program_map_table(data);
} else if(memcmp(data, "\x00\x00\x01\xBB", 4) == 0) {
// 跳过系统标题
data += 12;
len -= 12;
} else {
// 处理PES包
process_pes_packet(data, len);
break;
}
}
}
3. H264 NALU重组
void process_pes_packet(uint8_t *data, int len) {
PESHeader *pes_hdr = (PESHeader*)data;
if(pes_hdr->stream_id == 0xE0) { // 视频流
uint8_t *nal_data = data + sizeof(PESHeader);
int nal_len = len - sizeof(PESHeader);
// 处理H264 NALU
while(nal_len > 4) {
if(memcmp(nal_data, "\x00\x00\x00\x01", 4) == 0) {
// 提取NALU头
uint8_t nalu_hdr = nal_data[4];
uint8_t nalu_type = nalu_hdr & 0x1F;
// 处理分片
if(nalu_type == 28) { // FU-A
handle_fu_a_fragment(nal_data);
} else {
// 完整NALU处理
process_nalu(nal_data + 5, nal_len - 5);
}
}
nal_data++;
nal_len--;
}
}
}
四、关键算法实现
1. FU-A分片重组
typedef struct {
uint8_t nalu_type;
uint8_t nri;
bool start_bit;
bool end_bit;
std::vector<uint8_t> payload;
} FuFragment;
void handle_fu_a_fragment(uint8_t *data) {
FuFragment frag;
frag.nalu_type = (data[0] >> 3) & 0x1F;
frag.nri = (data[0] >> 1) & 0x03;
frag.start_bit = (data[1] & 0x80) ? true : false;
frag.end_bit = (data[1] & 0x40) ? true : false;
if(frag.start_bit) {
current_nalu = frag;
} else {
current_nalu.payload.insert(current_nalu.payload.end(), data+2, data+1400);
}
if(frag.end_bit) {
// 完成重组
process_nalu(current_nalu.payload.data(), current_nalu.payload.size());
current_nalu = {};
}
}
2. NALU头解析
void parse_nalu_header(uint8_t hdr) {
uint8_t forbidden_zero_bit = (hdr >> 7) & 0x01;
uint8_t nri = (hdr >> 5) & 0x03;
uint8_t nalu_type = hdr & 0x1F;
// 类型判断
switch(nalu_type) {
case 7: // SPS
case 8: // PPS
case 5: // IDR
case 1: // 非IDR
process_nalu_data(hdr, ...);
break;
default:
// 处理其他类型
break;
}
}
五、时间戳同步机制
uint32_t last_video_ts = 0;
uint32_t audio_ts = 0;
void sync_timestamps(uint32_t rtp_ts) {
static uint32_t base_ts = 0;
if(base_ts == 0) {
base_ts = rtp_ts;
}
current_ts = base_ts + (rtp_ts - base_ts) * 1000 / 90; // 转换为毫秒
// 音视频同步
if(abs(current_ts - audio_ts) > 100) {
adjust_audio_clock(current_ts);
}
}
参考代码 接收解析封装H264为PS数据的RTP包 www.youwenfan.com/contentcsn/72715.html
六、错误恢复
-
丢包检测:
if(rtp_hdr->sequence_number != expected_sn) { handle_packet_loss(expected_sn, rtp_hdr->sequence_number); expected_sn = rtp_hdr->sequence_number + 1; } -
关键帧请求:
void on_packet_loss(int lost_count) { if(lost_count > 5) { send_rtcp_pli(); // 请求PLI } }
七、性能优化
-
零拷贝技术:
// 使用内存池管理NALU缓冲区 std::vector<uint8_t> nal_buffer(MTU_SIZE); -
SIMD加速:
#pragma unroll(4) for(int i=0; i<16; i++) { __m128i data = _mm_loadu_si128((__m128i*)(buffer+i)); // SIMD处理 } -
多线程处理:
// 分离接收线程与解析线程 std::thread receiver_thread(receive_rtp); std::thread parser_thread(parse_ps_stream);
八、完整代码结构
h264_rtp_demuxer/
├── src/
│ ├── rtp_parser.cpp # RTP包解析
│ ├── ps_demuxer.cpp # PS流解析
│ ├── h264_processor.cpp # H264数据处理
│ └── sync_engine.cpp # 时间戳同步
├── include/
│ ├── rtp_header.h
│ ├── ps_header.h
│ └── h264_types.h
└── tests/
└── test_demuxer.cpp # 单元测试
九、调试工具推荐
-
Wireshark:抓包分析RTP负载类型和PS结构
-
FFmpeg:验证解码结果
ffplay -protocol_whitelist "file,udp,rtp" -i input.ps -
H264 Analyzer:查看NALU类型分布
该方案通过严格遵循RFC3984和GB28181标准,实现了H264在RTP/PS封装下的可靠传输。实际部署时需根据网络环境调整MTU大小(通常1400-1500字节)和缓冲区策略。
H264 over RTP/PS封装解析实现
1037

被折叠的 条评论
为什么被折叠?



