RTP完整的协议实现比较复杂,因为要考虑到很多种情况,如果具体到一个简单的应用上,可能就比较简单,因为所有问题都具体化了。比如包的方式,可能具体为单一包和基本的分包,其它情况就不用去考虑了。
前天下载的那个代码的实现,比较简单,基本上看完了,整理一下它的实现思路。
以流方式打开一个文件
查找0x 00 00 01 (或 0x 00 00 00 01)起始码,连续两个起始码之间的内容即为一个H.264的nal,是要用RTP发送的一块内容。这个要考虑一种特殊的情况,即文件尾,处理起来也很简单。
判断nal的长度,分为二种情况:<=1400和>1400
<=1400时,直接单一包往外发送;
>1400时,拆分成1400的几个,最后一个可能不足1400;
对于里面的几个结构体和rtp里的一些基本东西,都看了,但脑子里还是不清晰,比如时间戳在什么情况下如何增长,以及RFC3984里的一些结构体。
FU_INDICATOR
FU_HEADER
NALU_HEADER
RTP_FIXED_HEADER
在代码中,分配了一块发送缓冲区,char sendbuf[1500];和一个存放nalu的内存n = AllocNALU(8000000);
nalu的内容要加上RTP头,也就是说,这个sendbuf在发送前要进行构造,一开始放上rtp头,然后再放nalu
代码的处理是,取到sendbuf[0]的地址,把它强制转换成RTP_FIXED_HEADER类型的指针,实际就是在发送缓冲区开始的那块解释成了一个此类型的结构体,然后去对结构体字段进行赋值,这个结构体就是RFC3550中说的RTP固定头。
nalu_hdr =(NALU_HEADER*)&sendbuf[12];
把发送缓冲区的第12个字节开始的后续字节解释成NALU_HEADER类型,然后对该结构体的各字段赋值。
为什么是第12字节呢,因为RTP固定头长度是12字节。RFC3550中有详细说明。当然是没有CSRC作用源列表的情况下。也没有头扩展。
char* nalu_payload;
nalu_payload=&sendbuf[13];
memcpy(nalu_payload,n->buf+1,n->len-1);
把nalu的内容拷到发送缓冲区中,位置是发送缓冲区第23个字节开始
现在的发送缓冲区是这样的:
RTP头12字节 | NALU头1字节 | 有效负载
现在就可以发送了。
对于>1400的情况
rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0];
while()
{
rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0];
rtp_hdr->.......................
while( ... )//前面的分包
{
if (第1片)
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_hdr =(FU_HEADER*)&sendbuf[13];
nalu_payload=&sendbuf[14];
if (最后一片)
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_hdr =(FU_HEADER*)&sendbuf[13];
nalu_payload=&sendbuf[14];
if (中间那些片)
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_hdr =(FU_HEADER*)&sendbuf[13];
nalu_payload=&sendbuf[14];
}
}
也就是说,对于大于1400需要分片的,结构会与单片发送的有区别,除了RTP固定头12字节外,第13字节是FU_HEADER,
评论