一、编码到发包函数调用图
二、编码函数代码走读
encoded_image_缓存的是编码后的数据。frag_header是NALS组信息。
encoded_image_缓存数据格式为:4个字节起始码+NALHead+date+4个字节起始码+NALHead+date.......
RTPFragmentationHeader* frag_header参数fragmentationOffset和fragmentationLength含义如下:
三、发包函数代码走读
RTPSenderVideo::SendVideo函数四个变量比较绕,整理含义如下(该图没有包含FEC_head):
rtp_sender_->MaxRtpPacketSize()=kVideoMtu:报文最大长度。
packet_capacity:报文去掉RtxHeader后的长度。
max_data_payload_length:名称虽然是总净荷长度,但是实际上这个长度中包含了extension字段。
last_packet_reduction_len:新增extension字段组总长度。如下三个extension长度。
关于extension字段介绍连接如下:webrtc代码走读七(rtp包格式)_CrystalShaw的博客-CSDN博客_webrtc 代码走读
备注说明:
last_packet_reduction_len通过last_packet->headers_size() - rtp_header->headers_size()计算得出。
rtp_header->headers_size()的计算流程是:
->rtp_sender_->AllocatePacket()
->packet->SetCsrcs
->payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
和
->rtp_sender_->AllocatePacket()
->packet->ReserveExtension()
->packet->AllocateExtension()
->packet->AllocateRawExtension()
->payload_offset_ = extensions_offset + 4 * extensions_words;
last_packet->headers_size()的计算流程是:
->packet->SetExtension()
->packet->AllocateExtension()
->packet->AllocateRawExtension()
->payload_offset_ = extensions_offset + 4 * extensions_words;
四、备注说明
1、RTX格式定义
根据RFC4588格式定义:RFC 4588 - RTP Retransmission Payload Format
const size_t kRtxHeaderSize = 2;
kRtxHeaderSize是两个字节的OSN。封装RTX代码函数为:std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket
std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
const RtpPacketToSend& packet) {
std::unique_ptr<RtpPacketToSend> rtx_packet;
// Add original RTP header.
{
MutexLock lock(&send_mutex_);
if (!sending_media_)
return nullptr;
RTC_DCHECK(rtx_ssrc_);
// Replace payload type.
auto kv = rtx_payload_type_map_.find(packet.PayloadType());
if (kv == rtx_payload_type_map_.end())
return nullptr;
rtx_packet = std::make_unique<RtpPacketToSend>(&rtp_header_extension_map_,
max_packet_size_);
rtx_packet->SetPayloadType(kv->second);
// Replace sequence number.
rtx_packet->SetSequenceNumber(sequence_number_rtx_++);
// Replace SSRC.
rtx_packet->SetSsrc(*rtx_ssrc_);
CopyHeaderAndExtensionsToRtxPacket(packet, rtx_packet.get());
// RTX packets are sent on an SSRC different from the main media, so the
// decision to attach MID and/or RRID header extensions is completely
// separate from that of the main media SSRC.
//
// Note that RTX packets must used the RepairedRtpStreamId (RRID) header
// extension instead of the RtpStreamId (RID) header extension even though
// the payload is identical.
if (always_send_mid_and_rid_ || !rtx_ssrc_has_acked_) {
// These are no-ops if the corresponding header extension is not
// registered.
if (!mid_.empty()) {
rtx_packet->SetExtension<RtpMid>(mid_);
}
if (!rid_.empty()) {
rtx_packet->SetExtension<RepairedRtpStreamId>(rid_);
}
}
}
RTC_DCHECK(rtx_packet);
uint8_t* rtx_payload =
rtx_packet->AllocatePayload(packet.payload_size() + kRtxHeaderSize);
if (rtx_payload == nullptr)
return nullptr;
// Add OSN (original sequence number).
ByteWriter<uint16_t>::WriteBigEndian(rtx_payload, packet.SequenceNumber());
// Add original payload data.
auto payload = packet.payload();
memcpy(rtx_payload + kRtxHeaderSize, payload.data(), payload.size());
// Add original application data.
rtx_packet->set_application_data(packet.application_data());
rtx_packet->set_additional_data(packet.additional_data());
// Copy capture time so e.g. TransmissionOffset is correctly set.
rtx_packet->set_capture_time_ms(packet.capture_time_ms());
return rtx_packet;
}
打上一个新的RTX头,然后把原始报文的序列号填写在OSN这里,附在载荷前面。但是载荷会加密,所以我们在wireshark抓包这里,可能看不到恢复后的原始报文序列号。
webrtc的RTX目前音频和视频使用的是同一个SSRC,音视频混用一套SequenceNum。只是PT值有区分。