对于从事于流媒体开发的朋友来说,经常需要对接各种协议的处理。下面我们主要讲一下rtp解包成aac时,对应的重复包,乱序,丢包是如何处理的。
一 C语言的思路
并不是说这个思路不能用于C++,只不过C++有其它更好的方法,而这种思路更适合更方便C语言进行处理。
1 本项目对应的重复包,乱序,丢包的思路是如何处理的:
- 1)重复包:unpack文件中解rtp包时看到,只要有seq不相等,那么就会为该帧记录丢包的标志,把该帧丢弃,即使后面可能收到完整的一帧,实际上是不可能的,因为udp是不会重传的。
- 2)乱序:unpack解rtp包时看到,只要有seq不相等,那么就会为该帧记录丢包的标志,把该帧丢弃,乱序是仍可能收到完整一帧的,不过这里忽略这种情况进行处理了。
- 3)丢包:直接记录该帧丢包,丢弃该帧即可。
2 代码解释: 每一次从网络中拿到数据并且反序列化(大端转小端)后,都会调rtp_payload_check对重复包,乱序,丢包进行检查。
int rtp_payload_check(struct rtp_payload_helper_t* helper, const struct rtp_packet_t* pkt)
{
if (-1 == helper->__flags)
{
helper->__flags = 0;
helper->seq = (uint16_t)(pkt->rtp.seq - 1);
helper->timestamp = pkt->rtp.timestamp + 1;
}
int lost = 0;
if ((uint16_t)pkt->rtp.seq != (uint16_t)(helper->seq + 1))
{
lost = 1;
helper->lost = 1;
}
helper->seq = (uint16_t)pkt->rtp.seq;
if (pkt->rtp.timestamp != helper->timestamp)
{
rtp_payload_onframe(helper);
if(0 != lost)
helper->lost = lost;
}
helper->timestamp = pkt->rtp.timestamp;
return 0;
}
rtp_payload_onframe函数实际不用看都行,只要理解上面就基本懂得如何处理重复包,乱序,丢包的了,这里给出是为了方便大家更容易理解。
int rtp_payload_onframe(struct rtp_payload_helper_t *helper)
{
int r;
r = 0;
if (helper->size > 0
#if !defined(RTP_ENABLE_COURRUPT_PACKET)
&& 0 == helper->lost
#endif
)
{
r = helper->handler.packet(helper->cbparam, helper->ptr, helper->size,
helper->timestamp,
helper->__flags | (helper->lost ? RTP_PAYLOAD_FLAG_PACKET_CORRUPT : 0));
helper->__flags &= ~RTP_PAYLOAD_FLAG_PACKET_LOST;
}
if(helper->lost)
helper->__flags |= RTP_PAYLOAD_FLAG_PACKET_LOST;
helper->lost = 0;
helper->size = 0;
return r;
}
二 C++的思路
1 C++可以有更简单方便的思路实现,因为C++有map这种容器给我们调用。
-
1)重复包:通过本次传进来的包的seq与本帧已经保存的全部seq进行比较(所以C++的map.find合适),若存在说明重复,丢弃即可。 -
2)乱序:由于map可以根据first自动排序,所以可以通过遇到marker收完一帧的时候,用for进行遍历是否是按序即可,实际上这一步和下面的3)是一模一样的,所以这一步在C++不需要考虑。 -
3)丢包:同样通过rtp包的marker标志(或者rtp包时间戳,这个不熟),当为1说明该帧结束,然后for循环进行判断,seq末是本末尾包的seq,起始一般是1.然后依次与之前保存的seq比较(例如C++的map的first),seq个个存在说明没丢包。 -
注意:重复包、乱序与丢包的判断都是对一帧数据进行判断,判断完毕就清除本帧的内存,进行下一帧的判断。
代码实例参考这里即可:rtp协议丢包以及包重复判断。
|