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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值