rtp基本封包格式

rtp包易于过大,一般每个包不要超过1400,这里设置为1380,即DEFAULT_MTU=1380

这里介绍的媒体格式有视频:H264/H265,音频:AAC

1、如果媒体包小于DEFAULT_MTU时可直接写入rtp包中,示例代码:

unsigned char *pNAL;    //媒体数据包
int nalsize;            //媒体数据包长度
uint32_t timestamp;        //时间戳
// RTPSession rtp_session;
/* H264、H265 */
// 以jrtplib以为发送H264/H265视频数据的rtp包,成功时返回值是0
rtp_session.SendPacket(PacketData,PacketDataSize,96,true,(uint32_t)timestamp);

/* AAC */
uint8 aacHeader[4]={0x00,0x10,0x04,0xb8};
aacHeader[2] = nalsize >> 5;
aacHeader[3] = (nalsize & 0x1F) << 3;
memcpy(PacketData,aacHeader,sizeof(aacHeader));
memcpy(PacketData+sizeof(aacHeader),pNAL,nalsize);
PacketDataSize = nalsize+sizeof(aacHeader);
// 以jrtplib以为发送AAC音频数据的rtp包,成功时返回值是0
rtp_session.SendPacket(PacketData,PacketDataSize,97,true,(uint32_t)timestamp);

2、当媒体数据的包长度超过DEFAULT_MTU时需要采用分片封包模式(FUs),示例代码:

unsigned char *pNAL;    //媒体数据包
int nalsize;            //媒体数据包长度
uint32_t timestamp;        //时间戳
unsigned char PacketData[DEFAULT_MTU];    //rtp数据包
uint32_t PacketDataSize = 0;            //rtp数据包长度
int rtp_head_size = 0;

//计算rtp包头需要的信息
#if H264 || AAC
    const uint8_t fu_indicator = (pNAL[0] & 0xe0) | 28;
    const uint8_t fu_header = pNAL[0] & 0x1f;
    pNAL++;
    nalsize--;
    rtp_head_size = 2;
#else if H265
    const uint8_t payloadhdr[2]={(pNAL[0]&0x81)|(49<<1),pNAL[1]};
    const uint8_t fu_header = (pNAL[0] & 0x7E)>>1; 
    pNAL+=2;
    nalsize-=2;
    rtp_head_size = 3;
#endif

//计算需要拆分的片数
uint32_t FU_size = 0;
if((nalsize % (DEFAULT_MTU-rtp_head_size))!=0)
    FU_size=nalsize / (DEFAULT_MTU-rtp_head_size) +1;
else
    FU_size=nalsize / (DEFAULT_MTU-rtp_head_size);

int start = true;            //第一个分片标记
bool end_mask = false;        //最后一个分片标志
while(nalsize>0){
    const uint32_t fraglen = MIN(DEFAULT_MTU-rtp_head_size, nalsize);
    PacketDataSize = fraglen+rtp_head_size;

    #if H264 || AAC
        PacketData[0]=fu_indicator;        //rtp包第一个字节
        PacketData[1]=fu_header;        //rtp包第二个字节
    #else if H265
        PacketData[0]=payloadhdr[0];    //rtp包第一个字节
        PacketData[1]=payloadhdr[1];    //rtp包第二个字节
        PacketData[2]=fu_header;        //rtp包第三个字节
    #endif

    if (start) {                    //第一个分片需要在最高位需要至1
        PacketData[rtp_head_size-1] |= (1<<7);
        start = false;
    }
    if (fraglen == nalsize) {        //最后一个分片需要在第2高位需要至1
        PacketData[rtp_head_size-1] |= (1<<6);
        end_mask=true;
    }
    memcpy(PacketData+rtp_head_size, pNAL, fraglen);    //剩下的数据接在后面
    // RTPSession rtp_session;
    // 以jrtplib以为发送H264/H265视频数据的rtp包,成功时返回值是0
    rtp_session.SendPacket(PacketData,PacketDataSize,96,end_mask,(uint32_t)timestamp);
    // 以jrtplib以为发送AAC音频数据的rtp包,成功时返回值是0
    rtp_session.SendPacket(PacketData,PacketDataSize,97,true,(uint32_t)timestamp);

    //媒体数据包去掉已经发送的部分
    nalsize -= fraglen;        
    pNAL += fraglen;
}