rtp传输实现音视频同步及代码实现

141 阅读3分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

基于UDP传输的rtsp服务器,视频,音频属于不同的源,拥有不同的ssrc,仅仅在发送rtp包之前进行音视频同步是不够的,因为有的客户端(VLC)有rtcp同步机制。

仅仅使用RTP时间戳是无法实现媒体间同步的,根本的原因是音频时间轴和视频时间轴是完全独立的,通过音频帧和视频帧的时间戳,无法确定一个视频帧和一个音频帧的相对时间关系,就是说客户端不确定两个不同的源的相对时间戳是不是基于同一时间轴做的相对。

为能进行流同步,RTCP要求发送方给接收方传送一个唯一的标识数据源的规范名(canonical name),应用层藉此关联音视频流,以便实现同步。

具体实现就是:在固定的频率下发送RTCP的SR包以实现音视频同步, 该频率可以自己定,固定时间,固定帧数都可以。下面具体说下RTCP包协议及实现:

SR包协议:

image.png

每个源都有自己的SR包,例如音频源有音频SR,视频源有视频SR。协议字段如下:

 
P:     填充字段标识,如果此位 被设置为1,那么意味着包尾已经被一个或多个八位字节填充,最后一位八位所填充的 内容表示此包的总数大小。
 
RC:     后面跟的报告块数量。
 
PT:    RTCP包的类型,例如:SR包类型为200.
 
length: 载荷的长度,以32bit为单位,也就是每32bit代表长度是1.
        如上表长度:ssrc+ntp+ntp+rtp_pack+char = 1+1+1+1+1+1 = 6;
 
ssrc:     对应源的ssrc,例如视频的sr包对应的ssrc就是视频的ssrc。
 
NTP:     最高有效位,1900年1月1日0点0分0秒到现在的时间,单位是秒。
 
NTP:     最低有效位,小数部份,单位是微秒数的4294.967296(=232/106)倍。
 
NTP具体的算法参考后面的实例。NTP的作用是同步不同的RTP媒体流
 
RTP:     从0开始的相对时间戳。
 
packet count:     从第一包rtp包开始,到要发送SR包为止,这期间发送的所有RTP 包总数。
 
char count:     从第一包rtp包开始,到要发送SR包为止,这期间发送的所有RTP 数据的字节总数。

在linux中,NTP的具体实现:

 
gettimeofday(&tv, NULL);
 
uint64_t time_usec = tv.tv_sec * 1000000ULL + tv.tv_usec;
 
uint64_t temp = (time_usec / 1000ULL)*1000ULL + (2208988800ULL*1000000ULL);
 
rtcpPacket.ntp_sec = (uint32_t)(temp/1000000ULL);
 
rtcpPacket.ntp_usec = (uint32_t)(((temp%1000000)<<32)/1000000);
 
rtcpPacket.ntp_sec: NTP最高有效位
 
rtcpPacket.ntp_usec: NTP最低有效位
 
rtcpPacket: SR包的结构体。

2208988800数字:NTP是网络协议,和其他网路协议一样,它是从1900年开始的秒数,为gettimeofday是c语言接口,是从1970年开始计时的,而 2208988800就代表1900到1970的秒数。也就是说,c语言算出的当前秒数加上2208988800才符合NTP代表的秒数值。