結(jié)構(gòu)體struct RTPDemuxContext中有若干時(shí)間戳相關(guān)的成員,含義如下
timestamp:上一個(gè)接收到的RTP時(shí)間戳
base_timestamp:第一個(gè)接收到的RTP時(shí)間戳
cur_timestamp:未知
unwrapped_timestamp:假如rtp時(shí)間沒有32位溢出的話,當(dāng)前的rtp時(shí)間應(yīng)該是多少
range_start_offset:RTSP Range頭部指定的開始時(shí)間
last_rtcp_ntp_time:上一次收到RTCP SR報(bào)告中的ntp時(shí)間
last_rtcp_timestamp:上一次收到RTCP SR報(bào)告中的rtp時(shí)間
first_rtcp_ntp_time:第一次收到的RTCP SR報(bào)告中的ntp時(shí)間
rtcp_ts_offset:第一次接收到RTCP SR報(bào)告中的RTP時(shí)間與第一個(gè)收到的RTP時(shí)間差
每一幀的時(shí)間戳是這樣計(jì)算的,在libavformat/rtpdec.c finalize_packet()
如果rtp只有一個(gè)音頻流或者一個(gè)視頻流,或者沒有RTCP的SR報(bào)告,則
pkt->pts = s->unwrapped_timestamp + s->range_start_offset -
s->base_timestamp;
表達(dá)式右邊的順序換一下,含義就清晰了 s->unwrapped_timestamp - s->base_timestamp 代表當(dāng)前自運(yùn)行以來的相對時(shí)間,然后再加上s->range_start_offset,變成一個(gè)絕對時(shí)間。
如果有音視頻兩個(gè)流,且收到了RTCP的SR報(bào)告,計(jì)算是這樣的
if (s->first_rtcp_ntp_time == AV_NOPTS_VALUE) {
s->first_rtcp_ntp_time = s->last_rtcp_ntp_time;
if (!s->base_timestamp)
s->base_timestamp = s->last_rtcp_timestamp;
s->rtcp_ts_offset = (int32_t)(s->last_rtcp_timestamp - s->base_timestamp);
}
/* compute pts from timestamp with received ntp_time */
delta_timestamp = timestamp - s->last_rtcp_timestamp;
/* convert to the PTS timebase */
addend = av_rescale(s->last_rtcp_ntp_time - s->first_rtcp_ntp_time,
s->st->time_base.den,
(uint64_t) s->st->time_base.num << 32);
pkt->pts = s->range_start_offset + s->rtcp_ts_offset + addend +
delta_timestamp;
有點(diǎn)不好懂的是addend這個(gè)變量。根據(jù)rfc 3550,RTCP SR報(bào)告中的ntp時(shí)間定義為
http://www.ietf.org/rfc/rfc3550.txt
Wallclock time (absolute date and time) is represented using the timestamp format of the Network Time Protocol (NTP), which is in seconds relative to 0h UTC on 1 January 1900 [4]. The full resolution NTP timestamp is a 64-bit unsigned fixed-point number with the integer part in the first 32 bits and the fractional part in the last 32 bits.
由于讀進(jìn)來的rtcp_ntp_time是32位的定點(diǎn)小數(shù),因此在做時(shí)間戳單位轉(zhuǎn)換的時(shí)候做了一個(gè)32位的左移。因此addend代表最后一個(gè)收到的ntp時(shí)間距離第一個(gè)收到的ntp時(shí)間相隔多久。
回到pkt->pts的計(jì)算,s->rtcp_ts_offset這部分代表第一次收到的RTCP SR包距離流開始時(shí)的時(shí)間差,addend代表最后一次收到RTCP SR包距離第一次收到的RTCP SR包的時(shí)間差,delta_timestamp代表當(dāng)前距離最后一次收到RTCP SR包的時(shí)間差,這三部分一求和就代表當(dāng)前距離流開始時(shí)的時(shí)間差。
ffmpeg這種計(jì)算方式用于音視頻流同步是有問題的,它會(huì)默認(rèn)音視頻流時(shí)間戳都從0開始。假如兩者的開始時(shí)間不一致,會(huì)導(dǎo)致音視頻不同步。而且顯然,它這種計(jì)算方式浪費(fèi)了RTCP SR報(bào)告中的ntp與rtp時(shí)間對應(yīng)關(guān)系