ffmpeg 接收rtsp时的pts dts设置

设置pts

Pts的设置是根据timestamp和rtcp的ntp time设置的,在函数finalize_packet()内设置。跟ntp time挂钩是音视频同步的基础。
基本上可以认为timestamp的变化值就是pts的变化值,在没有B frame 时25fps 就是3600递增, 29.97fps 是3003 递增。存在B frame 时 timestamp 值 不是线性增加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* This was the second switch in rtp_parse packet.
* Normalizes time, if required, sets stream_index, etc.
*/

static void finalize_packet(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestamp)
{
if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE)
return; /* Timestamp already set by depacketizer */
if (timestamp == RTP_NOTS_VALUE)
return;
if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE && s->ic->nb_streams > 1) {
int64_t addend;
int delta_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;
return;
}

if (!s->base_timestamp)
s->base_timestamp = timestamp;
/* assume that the difference is INT32_MIN < x < INT32_MAX,
* but allow the first timestamp to exceed INT32_MAX */
if (!s->timestamp)
s->unwrapped_timestamp += timestamp;
else
s->unwrapped_timestamp += (int32_t)(timestamp - s->timestamp);
s->timestamp = timestamp;
pkt->pts = s->unwrapped_timestamp + s->range_start_offset -
s->base_timestamp;

}

其中的s->st->time_base.den = 90000 / 44100 等, s->st->time_base.num = 1。

设置dts

Dts的值是从pts的值里面选择的,在没有B帧时设置成和pts一样;

有B frame存在时,根据B frame num , 缓存相应B frame num个数加1的pts, 缓存的pts按从小到大排列。然后从数组0位置取出来当dts。

1
2
3
4
5
6
7
8
9
10
11
12
13
delay = st->internal->avctx->has_b_frames;

......

if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) {
st->pts_buffer[0] = pkt->pts;

for (i = 0; i<delay && st->pts_buffer[i] > st->pts_buffer[i + 1]; i++)
FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]);

if(has_decode_delay_been_guessed(st))
pkt->dts = select_from_pts_buffer(st, st->pts_buffer, pkt->dts);
}