Allow different header extensions in 1st packet of a video frame
no behavior changes expected.
Different exension for the 1st packet will be added in a follow-up
Bug: webrtc:9680
Change-Id: I8c853b2710d58df579aeb4b029b42210310423cc
Reviewed-on: https://webrtc-review.googlesource.com/98843
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24655}
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc
index 0f1fdca..90ff013 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -47,6 +47,26 @@
memcpy(&red_payload[kRedForFecHeaderLength], media_payload.data(),
media_payload.size());
}
+
+void AddRtpHeaderExtensions(const RTPVideoHeader& video_header,
+ FrameType frame_type,
+ bool set_video_rotation,
+ bool first_packet,
+ bool last_packet,
+ RtpPacketToSend* packet) {
+ if (last_packet && set_video_rotation)
+ packet->SetExtension<VideoOrientation>(video_header.rotation);
+
+ // Report content type only for key frames.
+ if (last_packet && frame_type == kVideoFrameKey &&
+ video_header.content_type != VideoContentType::UNSPECIFIED)
+ packet->SetExtension<VideoContentTypeExtension>(video_header.content_type);
+
+ if (last_packet &&
+ video_header.video_timing.flags != VideoSendTiming::kInvalid)
+ packet->SetExtension<VideoTimingExtension>(video_header.video_timing);
+}
+
} // namespace
RTPSenderVideo::RTPSenderVideo(Clock* clock,
@@ -282,16 +302,10 @@
return false;
RTC_CHECK(video_header);
- // Create header that will be reused in all packets.
- std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket();
- rtp_header->SetPayloadType(payload_type);
- rtp_header->SetTimestamp(rtp_timestamp);
- rtp_header->set_capture_time_ms(capture_time_ms);
- auto last_packet = absl::make_unique<RtpPacketToSend>(*rtp_header);
-
size_t fec_packet_overhead;
bool red_enabled;
int32_t retransmission_settings;
+ bool set_video_rotation;
{
rtc::CritScope cs(&crit_);
// According to
@@ -306,21 +320,10 @@
// value sent.
// Set rotation when key frame or when changed (to follow standard).
// Or when different from 0 (to follow current receiver implementation).
- VideoRotation current_rotation = video_header->rotation;
- if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ ||
- current_rotation != kVideoRotation_0)
- last_packet->SetExtension<VideoOrientation>(current_rotation);
- last_rotation_ = current_rotation;
- // Report content type only for key frames.
- if (frame_type == kVideoFrameKey &&
- video_header->content_type != VideoContentType::UNSPECIFIED) {
- last_packet->SetExtension<VideoContentTypeExtension>(
- video_header->content_type);
- }
- if (video_header->video_timing.flags != VideoSendTiming::kInvalid) {
- last_packet->SetExtension<VideoTimingExtension>(
- video_header->video_timing);
- }
+ set_video_rotation = frame_type == kVideoFrameKey ||
+ video_header->rotation != last_rotation_ ||
+ video_header->rotation != kVideoRotation_0;
+ last_rotation_ = video_header->rotation;
// FEC settings.
const FecProtectionParams& fec_params =
@@ -335,17 +338,45 @@
retransmission_settings = retransmission_settings_;
}
+ // Maximum size of packet including rtp headers.
+ // Extra space left in case packet will be resent using fec or rtx.
int packet_capacity = rtp_sender_->MaxRtpPacketSize() - fec_packet_overhead -
(rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0);
- RTC_DCHECK_LE(packet_capacity, rtp_header->capacity());
- RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size());
+
+ auto create_packet = [&] {
+ std::unique_ptr<RtpPacketToSend> rtp_packet = rtp_sender_->AllocatePacket();
+ RTC_DCHECK_LE(packet_capacity, rtp_packet->capacity());
+
+ rtp_packet->SetPayloadType(payload_type);
+ rtp_packet->SetTimestamp(rtp_timestamp);
+ rtp_packet->set_capture_time_ms(capture_time_ms);
+ return rtp_packet;
+ };
+
+ auto first_packet = create_packet();
+ auto middle_packet = absl::make_unique<RtpPacketToSend>(*first_packet);
+ auto last_packet = absl::make_unique<RtpPacketToSend>(*first_packet);
+ // Simplest way to estimate how much extensions would occupy is to set them.
+ AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ /*first=*/true, /*last=*/false, first_packet.get());
+ AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ /*first=*/false, /*last=*/false, middle_packet.get());
+ AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ /*first=*/false, /*last=*/true, last_packet.get());
+
+ RTC_DCHECK_GT(packet_capacity, first_packet->headers_size());
+ RTC_DCHECK_GT(packet_capacity, middle_packet->headers_size());
RTC_DCHECK_GT(packet_capacity, last_packet->headers_size());
RtpPacketizer::PayloadSizeLimits limits;
- limits.max_payload_len = packet_capacity - rtp_header->headers_size();
+ limits.max_payload_len = packet_capacity - middle_packet->headers_size();
- RTC_DCHECK_GE(last_packet->headers_size(), rtp_header->headers_size());
+ RTC_DCHECK_GE(first_packet->headers_size(), middle_packet->headers_size());
+ limits.first_packet_reduction_len =
+ first_packet->headers_size() - middle_packet->headers_size();
+
+ RTC_DCHECK_GE(last_packet->headers_size(), middle_packet->headers_size());
limits.last_packet_reduction_len =
- last_packet->headers_size() - rtp_header->headers_size();
+ last_packet->headers_size() - middle_packet->headers_size();
std::unique_ptr<RtpPacketizer> packetizer = RtpPacketizer::Create(
video_type, rtc::MakeArrayView(payload_data, payload_size), limits,
@@ -361,15 +392,36 @@
bool first_frame = first_frame_sent_();
for (size_t i = 0; i < num_packets; ++i) {
- bool last = (i + 1) == num_packets;
- auto packet = last ? std::move(last_packet)
- : absl::make_unique<RtpPacketToSend>(*rtp_header);
+ std::unique_ptr<RtpPacketToSend> packet;
+ int expected_payload_capacity;
+ // Choose right packet template:
+ if (num_packets == 1) {
+ // No prepared template, create a new packet.
+ packet = create_packet();
+ AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ /*first=*/true, /*last=*/true, packet.get());
+ // TODO(bugs.webrtc.org/7990): Revisit this case when two byte header
+ // extension are implemented because then single packet might need more
+ // space for extensions than sum of first and last packet reductions.
+ expected_payload_capacity = limits.max_payload_len -
+ limits.first_packet_reduction_len -
+ limits.last_packet_reduction_len;
+ } else if (i == 0) {
+ packet = std::move(first_packet);
+ expected_payload_capacity =
+ limits.max_payload_len - limits.first_packet_reduction_len;
+ } else if (i == num_packets - 1) {
+ packet = std::move(last_packet);
+ expected_payload_capacity =
+ limits.max_payload_len - limits.last_packet_reduction_len;
+ } else {
+ packet = absl::make_unique<RtpPacketToSend>(*middle_packet);
+ expected_payload_capacity = limits.max_payload_len;
+ }
+
if (!packetizer->NextPacket(packet.get()))
return false;
- RTC_DCHECK_LE(
- packet->payload_size(),
- last ? limits.max_payload_len - limits.last_packet_reduction_len
- : limits.max_payload_len);
+ RTC_DCHECK_LE(packet->payload_size(), expected_payload_capacity);
if (!rtp_sender_->AssignSequenceNumber(packet.get()))
return false;
@@ -404,7 +456,7 @@
RTC_LOG(LS_INFO)
<< "Sent first RTP packet of the first video frame (pre-pacer)";
}
- if (last) {
+ if (i == num_packets - 1) {
RTC_LOG(LS_INFO)
<< "Sent last RTP packet of the first video frame (pre-pacer)";
}