函数与解析
解码RTP包主要完成的是从RTP包队列中取走一个RTP包,解析是否丢弃,并初始化时间戳,显示时间戳,负载类型,忽略字节等信息,更新包队列信息,并把解析后的该包传递给负载类型指定的解码器。
access/rtp/session.c 中
/**
* Decodes one RTP packet.
*/
static void
rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
{
block_t *block = src->blocks;
assert (block);//其作用是如果它的条件返回错误,则终止程序执行
src->blocks = block->p_next;
block->p_next = NULL;
//上面这段代码从链表blocks中取出一个block,并把其从链表中去掉。下面开始解码这个block
//blocks会记录这个block的序列号
//如果序列号差值大于0x8000,丢弃。
//如果找不到负载类型,丢弃。
//扩展头部目前忽略。
/* Discontinuity detection */
uint16_t delta_seq = rtp_seq (block) - (src->last_seq + 1);
//获取序列号,头部2字节后的2字节就是序列号。这里用序列号判断是否连续。
//不连续情况下,如果序列号差值大于0x8000,就丢弃,否则标记为不连续。
if (delta_seq != 0)
{
if (delta_seq >= 0x8000)
{ /* Trash too late packets (and PIM Assert duplicates) */
msg_Dbg (demux, "ignoring late packet (sequence: %"PRIu16")",
rtp_seq (block));
goto drop;
}
msg_Warn (demux, "%"PRIu16" packet(s) lost", delta_seq);
//以%u格式打印
block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
}
//回填序列号
src->last_seq = rtp_seq (block);
/* Match the payload type */
void *pt_data;
const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data);
if (pt == NULL)
{
msg_Dbg (demux, "unknown payload (%"PRIu8")",
rtp_ptype (block));
goto drop;
}
//貌似为NULL。再补充吧。
if(pt->header)
pt->header(demux, pt_data, block);
/* Computes the PTS from the RTP timestamp and payload RTP frequency.
* DTS is unknown. Also, while the clock frequency depends on the payload
* format, a single source MUST only use payloads of a chosen frequency.
* Otherwise it would be impossible to compute consistent timestamps. */
//获取时间戳
const uint32_t timestamp = rtp_timestamp (block);
//计算显示时间戳,回填ntp和rtp。在这里可以看到显示时间戳是怎么计算出来的。
block->i_pts = src->ref_ntp
+ CLOCK_FREQ * (int32_t)(timestamp - src->ref_rtp) / pt->frequency;
/* TODO: proper inter-medias/sessions sync (using RTCP-SR) */
src->ref_ntp = block->i_pts;
src->ref_rtp = timestamp;
//计算同步信源的个数,一个信源占4个字节
//这里是要忽略掉,扩展头部也不处理。
/* CSRC count */
size_t skip = 12u + (block->p_buffer[0] & 0x0F) * 4;
//扩展标识,需特殊处理
/* Extension header (ignored for now) */
if (block->p_buffer[0] & 0x10)
{
skip += 4;
if (block->i_buffer < skip)
goto drop;
skip += 4 * GetWBE (block->p_buffer + skip - 2);
}
if (block->i_buffer < skip)
goto drop;
//更新这个包的buffer指针和buffer长度,然后把数据交给解码器处理
block->p_buffer += skip;
block->i_buffer -= skip;
pt->decode (demux, pt_data, block);
return;
drop:
block_Release (block);
}
//相关函数
//获取序列号
static inline uint16_t rtp_seq (const block_t *block)
{
assert (block->i_buffer >= 4);
return GetWBE (block->p_buffer + 2);
}
//获取时间戳,占32位,必须使用90 kHz 时钟频率。时戳反映了该RTP报文的第一个八位组的采样时刻。
//接收者使用时戳来计算延迟和延迟抖动,并进行同步控制
static inline uint32_t rtp_timestamp (const block_t *block)
{
assert (block->i_buffer >= 12);
return GetDWBE (block->p_buffer + 4);
}
//获取负载类型
static const struct rtp_pt_t *
rtp_find_ptype (const rtp_session_t *session, rtp_source_t *source,
const block_t *block, void **pt_data)
{
uint8_t ptype = rtp_ptype (block);
for (unsigned i = 0; i < session->ptc; i++)
{
if (session->ptv[i].number == ptype)
{
if (pt_data != NULL)
*pt_data = source->opaque[i];
return &session->ptv[i];
}
}
return NULL;
}
//Reads 16 bits in network byte order.
#define GetWBE ( p ) U16_AT(p)
//定义格式输出
#define PRIu16 "u"
//rtp.h
/** @section RTP payload format */
struct rtp_pt_t
{
void *(*init) (demux_t *);
void (*destroy) (demux_t *, void *);
void (*header) (demux_t *, void *, block_t *);
void (*decode) (demux_t *, void *, block_t *);
uint32_t frequency; /* RTP clock rate (Hz) */
uint8_t number;
};
//一个RTP源的信息
/** State for an RTP source */
struct rtp_source_t
{
uint32_t ssrc;
uint32_t jitter; /* interarrival delay jitter estimate */
mtime_t last_rx; /* last received packet local timestamp */
uint32_t last_ts; /* last received packet RTP timestamp */
uint32_t ref_rtp; /* sender RTP timestamp reference */
mtime_t ref_ntp; /* sender NTP timestamp reference */
uint16_t bad_seq; /* tentatively next expected sequence for resync */
uint16_t max_seq; /* next expected sequence */
uint16_t last_seq; /* sequence of the next dequeued packet */
block_t *blocks; /* re-ordered blocks queue */
void *opaque[]; /* Per-source private payload data */
};
参考文章
RTP 时间戳的处理
http://blog.51cto.com/general/328220