使用rtcp实现音视频同步

image

image

正文

一 基础知识

音视频同步是指音视频的rtp时间戳同步. audio/video rtp 时间戳不能自己同步,需要audio/video rtcp同步。

1 RTCP时间戳

发送端以一定的频率发送RTCP SR(Sender Report)这个包,SR分为视频SR和音频SR,SR包内包含一个RTP时间戳和对应的NTP时间戳,可以用<ntp,rtp>对做音视频同步.(同步过程在后面)
Rtcp sr 格式


image.png

2 音频时间戳

例如:一个音频包打包20ms的数据.采样率48k.对应的采样数为 48000 * 20 / 1000 = 960,也就是说每个音频包里携带960个音频采样,因为1个采样对应1个时间戳,那么相邻两个音频RTP包的时间戳之差就是960。


image.png

3 视频时间戳

视频采样率是帧率,视频时间戳的单位为1/90k秒.比如: 25帧,每帧40ms.40ms有多少时间戳的基本单位呢? 40除以1/90k等于3600.
扩展内容:
Single Nalu:如果一个视频帧包含1个NALU,可以单独打包成一个RTP包,那么RTP时间戳就对应这个帧的采集时间;
FU-A:如果一个视频帧的NALU过大(超过MTU)需要拆分成多个包,可以使用FU-A方式来拆分并打到不同的RTP包里,那么这几个包的RTP时间戳是一样的;
STAP-A:如果某帧较大不能单独打包,但是该帧内部单独的NALU比较小,可以使用STAP-A方式合并多个NALU打包发送,但是这些NALU的时间戳必须一致,打包后的RTP时间戳也必须一致

4 ntp时间戳

NTP时间戳是从1900年1月1日00:00:00以来经过的秒数.
rtp是相对时间,ntp是绝对时间.rtp时间戳和ntp时间戳表示的意义是相同的. 可以互相转换,rtp=f(ntp) 类似中文名张三,英文名zhangjohn.

5 播放时间

rtp时间戳如何转换成pts即显示时间的呢? pts= rtp 时间戳 *timebase.
例如:flv封装格式的time_base为{1,1000},ts封装格式的time_base为{1,90000}.
flv: pkt_pts=80,pkt_pts_time=80/1000=0.080000;
pkt_pts=120,pkt_pts_time=0.120000;
pkt_pts=160,pkt_pts_time=0.160000;
pkt_pts=200,pkt_pts_time=0.200000
ts: pkt_pts=7200,pkt_pts_time=7200/90000=0.080000;
pkt_pts=10800,pkt_pts_time=0.120000;
pkt_pts=14400,pkt_pts_time=0.160000;
pkt_pts=18000,pkt_pts_time=0.200000
总结:ntp,rtp,pts表示的是同一帧的时间.ntp是绝对时间,rtp是相对时间,pts是播放时间.rtp是用频率表示,pts是用秒表示.
如果音视频都从0同步开始,rtp等于pts.
如果不是同步开始,pts需要rtp 同步加减一个offer.具体实例看下文. rtp和pts是编解码时间即播放时间,不是传输时间,传输延时与rtp时间戳没关系.

二 音视频同步

音视频时间戳增长rtp增量是不同的,所以需要换算成ntp时间同步.

1 理想情况:

音视频同时编码,而且视频播放频率始终不变. 使用rtp时间戳同步就行.


image.png

因为音视频被映射到同一个时间轴上了,音频和视频帧间的相对关系很清楚.
同时RTP规范要求时间戳的初始值应该是一个随机值,那么假设音频帧时间戳的初始值是随机值1234,视频帧时间戳的初始值是随机值5678,看起来应该是下面这样


image.png

其实道理和上面一样.rtp可以同步,但是这是理想情况并不是实际情况,实际情况需要进一步处理.

2 实际情况

2.1 音视频不是同时产生
RTP规范并没有规定第一个视频帧的时间戳和第一个音频帧的时间戳必须或者应该对应到绝对时间轴的同一个点上 。
也就是说开始的一小段时间内可能只有音频或者视频,比如开始摄像头没有开,只有音频没有视频.也可能的开始网络丢包,同时视频的降低帧率,有可能出现这样的时间戳序列:0,丢包+降帧率,16200,... 第一个视频帧rtp timestamp 是16200,就无法映射到绝对时间轴上.
实际情况如下图:

image.png

发送端的音视频流并没有对齐,但是周期地发送SR包,接收端得到音视频SR包的RTP时间戳、NTP时间戳后通过线性回归得到NTP时间戳Tntp和RTP时间戳Trtp时间戳的对应关系:

  • Tntp_audio = f(Trtp_audio)
  • Tntp_video = f(Trtp_video)
    其中Tntp = f(Trtp) = kTrtp + b 为线性函数,这样接收端每收到一个RTP包,都可以将RTP时间戳换算成NTP时间戳,从而在同一时间基准下进行音视频同步。
    notes:rtp和ntp转换是线性关系:以最简单的情况为例:绝对时间ntp=x+80ms,rtp=8090=7200;
    则rtp=(ntp-x)
    90,所以是线性关系.
    2.2 使用rtcp同步.(这节是重点)
    分成两种情况,a) 视频同步到音频; b) 音频同步到视频. 通常使用前者.
    同步原理:将audio/video第一帧时间戳同步到同一个绝对时间上.
    实例分析:
    问:音频采样率8k,视频帧率25. Audio从头开始,音频时间戳320会在多少ms播放呢?
    答:320/8=40ms.
    问:那么收到的视频帧rtp时间戳是7200应该在多少ms播放呢?
    答:7200/90=80ms播放。答案是错误的.
    因为第一个音频是从0开始播放的,但是第一个视频帧可能是在第1ms开始的,而不是从0ms开始的.
    如果视频从1ms开始,rtcp第一个音视频帧 video rtp 是3600,它表示41ms。而audio rtp 是160表示40ms.所以先要计算audio,video的绝对时间差,倒退开始的时间差.
    视频同步到音频为例:
    diff=(video ntp time)-(audio ntp time)=1ms (rtcp中NTP时间相减).
    对应的rtp时间相减,3600-90=3510.3510就是视频ntp对应的40ms绝对时间(time base).
    后面rtp 7200是多少ms呢?
    7200-3510=7200-(3600-90)=3600+90=40ms+1=41ms;即在播放base 40ms之后的41ms播放,等于81ms的地方播放.
    后续的每个audio/video rtp timestamp减去这个base就是播放时间.实现同步.
    音频同步到视频原理一样.
    如果不能理解上面的实例,可以画图将音视频ntp时间,rtp时间画到同一个时间轴上即可.

三 音视频同步的应用场景

音视频同步应用分成两种:一种是用于传输,一种是用于播放器.
1 用于传输
传输本来可以不用同步直接转给播放器处理,但是给第三方库的时候需要同步,比如将流转给ffmpeg。ffmpeg 要求转入的流的第一帧,必须audio,video 是同步的. 不能audio从0ms开始,video从1ms开始,那样送流给ffmpeg一定音视频不同步.所以给ffmpeg之前,需要做音视频同步.根据上面的方法就可以实现。
notes: ffmpeg源码要求第一帧同步开始:https://www.jianshu.com/p/67d3e6a1d72e
2 播放器的同步播放
播放器在上面同步的基础上,还需要增加缓存. 缓存设计分成两种情况,视频快于音频和音频快于视频.
i) 视频快于音频那么扩大视频缓冲区,缩短音频缓冲区,让视频帧等一等音频帧。
ii) 音频快于视频那么扩大音频缓冲区,缩短视频缓冲区,让音频帧等一等音频帧

四 QA

QA1:什么情况会出现不同步,为什么要同步?
比如视频第1ms才有数据,但是在第0ms播放,其他帧都是提前1ms,变成音视频不同步.
QA2:什么时候同步,需要多少次同步?
第一帧开始同步。根据上面的算法,第几个rtcp包都能同步,从哪里开始同步后面就跟着全同步了.
播放当然需要从开始同步哈,所以都是从第一帧同步。
只需要同步一次,后面就是对于基准0的播放时间了。
QA3: 音视频同步与帧率的关系?
动态帧率与时间戳同步没关系,播放器会根据fps读取正确的ts。帧率不同只是视频包多少不同,每个包的time stamp和ntp时间都是一一对应的.
QA4: 传输延时与rtp时间戳有没有关系?
ats:20,40,60,...
vts: 41,82,123....
会不会出现这种时间序列,累计造成时间戳不同步。
这个数列是不对.
40ms肯定能编解码完成,不是编解码要41ms。而是开始第一帧发送的晚造成41ms.
数列应该是41,81,121...
QA5: 两个不同的主播合流,如果有一个主播的时间戳不准确如何同步?
比如:第一个13:00:00: 编码:40ms第一帧
第二个在13:00:00:30ms开始编码,但是它的时间有问题,显示0:0:0:0开始
如何将13:00:00:30ms map 0:0:0:0.
没有实际经验。原理应该和音视频同步类似,同步到其中一个主播时间轴即可。
哪位网友有经验欢迎补充

五 实现

uint32_t ntp_compact_audio = get_compact_ntp_time( ntp_audio );
uint32_t ntp_compact_video = get_compact_ntp_time( ntp_video );
gint64 diff_ms;
if( ntp_compact_video > ntp_compact_audio ) //audio_ts be ahead of video_ts
{
    diff_ms = ntp_compact_video - ntp_compact_audio;
    diff_ms = ( diff_ms * 1000 + ( 1 << 16 ) / 2 ) / ( 1 << 16 );
    diff_ms = diff_ms > 1 ? diff_ms : 1;
    uint32_t diff_ts = diff_ms * 90;
    //v_sr_ts is rtp ts
    base_timestamp_video = v_sr_ts - diff_ts;
    base_timestamp_audio = a_sr_ts;
}
### 代码解析:
1) 获取音视频时间

uint32_t ntp_compact_audio = get_compact_ntp_time( ntp_audio );
uint32_t ntp_compact_video = get_compact_ntp_time( ntp_video );

2)音频快于视频分支
获取时间差
diff_ms = ntp_compact_video - ntp_compact_audio;
diff_ms = ( diff_ms * 1000 + ( 1 << 16 ) / 2 ) / ( 1 << 16 );
diff_ms = diff_ms > 1 ? diff_ms : 1;
uint32_t diff_ts = diff_ms * 90;
3)   音频时间基直接设置
base_timestamp_audio = a_sr_ts;
4) 视频向音频同步

//v_sr_ts is rtp ts
base_timestamp_video = v_sr_ts - diff_ts

部分引用:https://blog.csdn.net/sonysuqin/article/details/107297157

#### 本文如对您有帮助,请随手点个赞,谢谢
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容