vlc-解码一个RTP数据包函数分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vlc-解码一个RTP数据包函数分析相关的知识,希望对你有一定的参考价值。


函数与解析

解码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​


以上是关于vlc-解码一个RTP数据包函数分析的主要内容,如果未能解决你的问题,请参考以下文章

Wireshark Legacy将RTP包导出为视频文件

vlc源码分析之调用live555接收RTSP数据

使用VLC接收RTP流并时时播放(RTP流是pcma包)

vlc的MP4的Demux函数分析

如何指定VLC的RTSP拉流方式(RTP over UDP/TCP)

vlc源码分析 流媒体的音视频同步