一、概念
与NACK对应的是ACK,ACK是到达通知技术。以TCP为例,他可靠因为接收方在收到数据后会给发送方返回一个“已收到数据”的消息(ACK),告诉发送方“我已经收到了”,确保消息的可靠。
NACK也是一种通知技术,只是触发通知的条件刚好的ACK相反,在未收到消息时,通知发送方“我未收到消息”,即通知未达。
在rfc4585协议中定义可重传未到达数据的类型有二种:
1)RTPFB:rtp报文丢失重传。
2)PSFB:指定净荷重传,指定净荷重传里面又分如下三种:
1、PLI (Picture Loss Indication) 视频帧丢失重传。
2、SLI (Slice Loss Indication) slice丢失重转。
3、RPSI (Reference Picture Selection Indication)参考帧丢失重传。
在创建视频连接的SDP协议里面,会协商以上述哪种类型进行NACK重转。以webrtc为例,会协商两种NACK,一个rtp报文丢包重传的nack(nack后面不带参数,默认RTPFB)、PLI 视频帧丢失重传的nack。
二、定义
V: 2bit 目前固定为2
P: 1bit padding
FMT:5bit Feedback message type。
RTP FP模式下定义值为:
0:unassigned
1:Generic NACK
2-30:unassigned
31:reserved for future expansion of the identifier number space
PS FP模式下定义值为:
0: unassigned
1: Picture Loss Indication (PLI)
2: Slice Loss Indication (SLI)
3: Reference Picture Selection Indication (RPSI)
4-14: unassigned
15: Application layer FB (AFB) message
16-30: unassigned
31: reserved for future expansion of the sequence number space
PT: 8bit Payload type。
FCI:变长 Feedback Control Information。
1、RTPFB
Packet identifier(PID)即为丢失RTP数据包的序列号,Bitmap of Lost Packets(BLP)指示从PID开始接下来16个RTP数据包的丢失情况。一个NACK报文可以携带多个RTP序列号,NACK接收端对这些序列号逐个处理。如下示例:
Packet identifier(PID)为176。
Bitmap of Lost Packets(BLP):0x6ae1。解析的时候需要按照小模式解析,
0x6ae1对应二进制:110101011100001倒过来看1000 0111 0101 0110。
按照1bit是丢包,0bit是没有丢包解析,丢失报文序列号分别是:
177 182 183 184 186 188 190 191与wireshark解析一致。
2、PSFB
1)PLI FB PT=PSFB FMT=1。
2)SLI FB的PT=PSFB、FMT=2。
First: 13 bits The macroblock (MB) address of the first lost macroblock.
Number: 13 bits The number of lost macroblocks, in scan order as discussed above。
PictureID: 6 bits The six least significant bits of the codec-specific identifier that is used to reference the picture in which the loss of the macroblock(s) has occurred. For many video codecs, the PictureID is identical to the Temporal Reference.
3)RPSI FB的PT=PSFB、FMT=3。
三、实现
webrtc支持RTPFB和PLI FB两种重传方式。
AssignPayloadTypesAndAddAssociatedRtxCodecs->AddDefaultFeedbackParams里面将两种方式都填写到SDP命令行里面。
1)RTPFB实现
RTPFB在JB里面实现。通过RTP报文的序列号和时间戳,判断是否出现丢包异常。参考NackTracker类实现。
发送端调用栈参考如下:
PlatformThread::StartThread
->PlatformThread::Run
->ProcessThreadImpl::Run
->ProcessThreadImpl::Process
->PacedSender::Process
->PacedSender::SendPacket
->PacketRouter::TimeToSendPacket
->ModuleRtpRtcpImpl::TimeToSendPacket
->RTPSender::TimeToSendPacket
->RtpPacketHistory::GetPacketAndSetSendTime
->RtpPacketHistory::GetPacket
接收端有两种方式驱动方式NACK
1、收包驱动
DeliverPacket
->DeliverRtp
->RtpStreamReceiverController::OnRtpPacket
->RtpDemuxer::OnRtpPacket
->RtpVideoStreamReceiver::OnRtpPacket
->RtpVideoStreamReceiver::ReceivePacket
->RtpReceiverImpl::IncomingRtpPacket
->RTPReceiverVideo::ParseRtpPacket
->RtpVideoStreamReceiver::OnReceivedPayloadData
->NackModule::OnReceivedPacket
->VideoReceiveStream::SendNack
->RtpVideoStreamReceiver::RequestPacketRetransmit
->ModuleRtpRtcpImpl::SendNack
2、定时驱动
NackModule::Process
2)PLI FB实现
PLI FB在webrtc里面实现的是请求关键帧。当连续出现解码失败,或者长期没有解码输入,就通过RTCP报文发送请求IDR帧命令。参考VideoReceiveStream::Decode、RequestKeyFrame这两个函数实现。
四、参考
https://tools.ietf.org/html/rfc4585
————————————————
版权声明:本文为CSDN博主「CrystalShaw」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/CrystalShaw/article/details/81218394