niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 1 | /* |
pwestin@webrtc.org | f6bb77a | 2012-01-24 17:16:59 | [diff] [blame] | 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
pbos@webrtc.org | a048d7c | 2013-05-29 14:27:38 | [diff] [blame] | 11 | #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 12 | |
pbos@webrtc.org | a048d7c | 2013-05-29 14:27:38 | [diff] [blame] | 13 | #include <stdlib.h> |
| 14 | #include <string.h> |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 15 | |
kwiberg | 84be511 | 2016-04-27 08:19:58 | [diff] [blame] | 16 | #include <memory> |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 17 | #include <vector> |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 18 | #include <utility> |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 19 | |
| 20 | #include "webrtc/base/checks.h" |
Peter Boström | ebc0b4e | 2015-10-28 15:39:33 | [diff] [blame] | 21 | #include "webrtc/base/logging.h" |
tommi | e4f9650 | 2015-10-21 06:00:48 | [diff] [blame] | 22 | #include "webrtc/base/trace_event.h" |
Henrik Kjellander | ff761fb | 2015-11-04 07:31:52 | [diff] [blame] | 23 | #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
sprang@webrtc.org | 779c3d1 | 2015-03-17 16:42:49 | [diff] [blame] | 24 | #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
pbos@webrtc.org | a048d7c | 2013-05-29 14:27:38 | [diff] [blame] | 25 | #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h" |
| 26 | #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" |
asapersson | a9455ab | 2015-07-31 13:10:09 | [diff] [blame] | 27 | #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h" |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 28 | #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" |
| 29 | #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 30 | |
| 31 | namespace webrtc { |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 32 | |
brandtr | 6631e8a | 2016-09-13 10:23:29 | [diff] [blame] | 33 | namespace { |
| 34 | constexpr size_t kRedForFecHeaderLength = 1; |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 35 | |
| 36 | void BuildRedPayload(const RtpPacketToSend& media_packet, |
| 37 | RtpPacketToSend* red_packet) { |
| 38 | uint8_t* red_payload = red_packet->AllocatePayload( |
| 39 | kRedForFecHeaderLength + media_packet.payload_size()); |
| 40 | RTC_DCHECK(red_payload); |
| 41 | red_payload[0] = media_packet.PayloadType(); |
| 42 | memcpy(&red_payload[kRedForFecHeaderLength], media_packet.payload(), |
| 43 | media_packet.payload_size()); |
| 44 | } |
brandtr | 6631e8a | 2016-09-13 10:23:29 | [diff] [blame] | 45 | } // namespace |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 46 | |
brandtr | dbdb3f1 | 2016-11-10 13:04:48 | [diff] [blame^] | 47 | RTPSenderVideo::RTPSenderVideo(Clock* clock, |
| 48 | RTPSender* rtp_sender, |
| 49 | FlexfecSender* flexfec_sender) |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 50 | : rtp_sender_(rtp_sender), |
sprang | cd349d9 | 2016-07-13 16:11:28 | [diff] [blame] | 51 | clock_(clock), |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 52 | video_type_(kRtpVideoGeneric), |
| 53 | retransmission_settings_(kRetransmitBaseLayer), |
| 54 | last_rotation_(kVideoRotation_0), |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 55 | red_payload_type_(-1), |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 56 | ulpfec_payload_type_(-1), |
brandtr | dbdb3f1 | 2016-11-10 13:04:48 | [diff] [blame^] | 57 | flexfec_sender_(flexfec_sender), |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 58 | delta_fec_params_{0, 1, kFecMaskRandom}, |
| 59 | key_fec_params_{0, 1, kFecMaskRandom}, |
sprang | cd349d9 | 2016-07-13 16:11:28 | [diff] [blame] | 60 | fec_bitrate_(1000, RateStatistics::kBpsScale), |
danilchap | c1600c5 | 2016-10-26 10:33:11 | [diff] [blame] | 61 | video_bitrate_(1000, RateStatistics::kBpsScale) { |
| 62 | encoder_checker_.Detach(); |
| 63 | } |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 64 | |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 65 | RTPSenderVideo::~RTPSenderVideo() {} |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 66 | |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 67 | void RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes video_type) { |
| 68 | video_type_ = video_type; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 69 | } |
| 70 | |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 71 | RtpVideoCodecTypes RTPSenderVideo::VideoCodecType() const { |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 72 | return video_type_; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 73 | } |
| 74 | |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 75 | // Static. |
| 76 | RtpUtility::Payload* RTPSenderVideo::CreateVideoPayload( |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 77 | const char payload_name[RTP_PAYLOAD_NAME_SIZE], |
| 78 | int8_t payload_type) { |
| 79 | RtpVideoCodecTypes video_type = kRtpVideoGeneric; |
| 80 | if (RtpUtility::StringCompare(payload_name, "VP8", 3)) { |
| 81 | video_type = kRtpVideoVp8; |
| 82 | } else if (RtpUtility::StringCompare(payload_name, "VP9", 3)) { |
| 83 | video_type = kRtpVideoVp9; |
| 84 | } else if (RtpUtility::StringCompare(payload_name, "H264", 4)) { |
| 85 | video_type = kRtpVideoH264; |
| 86 | } else if (RtpUtility::StringCompare(payload_name, "I420", 4)) { |
| 87 | video_type = kRtpVideoGeneric; |
pwestin@webrtc.org | 95cf479 | 2012-01-20 06:59:06 | [diff] [blame] | 88 | } else { |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 89 | video_type = kRtpVideoGeneric; |
pwestin@webrtc.org | 95cf479 | 2012-01-20 06:59:06 | [diff] [blame] | 90 | } |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 91 | RtpUtility::Payload* payload = new RtpUtility::Payload(); |
pwestin@webrtc.org | f6bb77a | 2012-01-24 17:16:59 | [diff] [blame] | 92 | payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 93 | strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1); |
| 94 | payload->typeSpecific.Video.videoCodecType = video_type; |
pwestin@webrtc.org | 95cf479 | 2012-01-20 06:59:06 | [diff] [blame] | 95 | payload->audio = false; |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 96 | return payload; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 97 | } |
| 98 | |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 99 | void RTPSenderVideo::SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet, |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 100 | StorageType storage) { |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 101 | // Remember some values about the packet before sending it away. |
| 102 | size_t packet_size = packet->size(); |
| 103 | uint16_t seq_num = packet->SequenceNumber(); |
| 104 | uint32_t rtp_timestamp = packet->Timestamp(); |
| 105 | if (!rtp_sender_->SendToNetwork(std::move(packet), storage, |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 106 | RtpPacketSender::kLowPriority)) { |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 107 | LOG(LS_WARNING) << "Failed to send video packet " << seq_num; |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 108 | return; |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 109 | } |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 110 | rtc::CritScope cs(&stats_crit_); |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 111 | video_bitrate_.Update(packet_size, clock_->TimeInMilliseconds()); |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 112 | TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), |
danilchap | e5b4141 | 2016-08-22 10:39:23 | [diff] [blame] | 113 | "Video::PacketNormal", "timestamp", rtp_timestamp, |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 114 | "seqnum", seq_num); |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 115 | } |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 116 | |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 117 | void RTPSenderVideo::SendVideoPacketAsRedMaybeWithUlpfec( |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 118 | std::unique_ptr<RtpPacketToSend> media_packet, |
| 119 | StorageType media_packet_storage, |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 120 | bool protect_media_packet) { |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 121 | uint32_t rtp_timestamp = media_packet->Timestamp(); |
| 122 | uint16_t media_seq_num = media_packet->SequenceNumber(); |
| 123 | |
| 124 | std::unique_ptr<RtpPacketToSend> red_packet( |
| 125 | new RtpPacketToSend(*media_packet)); |
| 126 | BuildRedPayload(*media_packet, red_packet.get()); |
| 127 | |
brandtr | 74811e5 | 2016-08-10 07:51:50 | [diff] [blame] | 128 | std::vector<std::unique_ptr<RedPacket>> fec_packets; |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 129 | StorageType fec_storage = kDontRetransmit; |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 130 | { |
| 131 | // Only protect while creating RED and FEC packets, not when sending. |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 132 | rtc::CritScope cs(&crit_); |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 133 | red_packet->SetPayloadType(red_payload_type_); |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 134 | if (ulpfec_enabled()) { |
| 135 | if (protect_media_packet) { |
| 136 | ulpfec_generator_.AddRtpPacketAndGenerateFec( |
| 137 | media_packet->data(), media_packet->payload_size(), |
| 138 | media_packet->headers_size()); |
| 139 | } |
| 140 | uint16_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets(); |
| 141 | if (num_fec_packets > 0) { |
| 142 | uint16_t first_fec_sequence_number = |
| 143 | rtp_sender_->AllocateSequenceNumber(num_fec_packets); |
| 144 | fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed( |
| 145 | red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number, |
| 146 | media_packet->headers_size()); |
| 147 | RTC_DCHECK_EQ(num_fec_packets, fec_packets.size()); |
| 148 | if (retransmission_settings_ & kRetransmitFECPackets) |
| 149 | fec_storage = kAllowRetransmission; |
| 150 | } |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 151 | } |
| 152 | } |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 153 | // Send |red_packet| instead of |packet| for allocated sequence number. |
| 154 | size_t red_packet_size = red_packet->size(); |
| 155 | if (rtp_sender_->SendToNetwork(std::move(red_packet), media_packet_storage, |
| 156 | RtpPacketSender::kLowPriority)) { |
sprang | cd349d9 | 2016-07-13 16:11:28 | [diff] [blame] | 157 | rtc::CritScope cs(&stats_crit_); |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 158 | video_bitrate_.Update(red_packet_size, clock_->TimeInMilliseconds()); |
sprang@webrtc.org | 0200f70 | 2015-02-16 12:06:00 | [diff] [blame] | 159 | TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), |
danilchap | e5b4141 | 2016-08-22 10:39:23 | [diff] [blame] | 160 | "Video::PacketRed", "timestamp", rtp_timestamp, |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 161 | "seqnum", media_seq_num); |
| 162 | } else { |
| 163 | LOG(LS_WARNING) << "Failed to send RED packet " << media_seq_num; |
| 164 | } |
brandtr | 74811e5 | 2016-08-10 07:51:50 | [diff] [blame] | 165 | for (const auto& fec_packet : fec_packets) { |
brandtr | 869e7cd | 2016-10-31 12:27:07 | [diff] [blame] | 166 | // TODO(danilchap): Make ulpfec_generator_ generate RtpPacketToSend to avoid |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 167 | // reparsing them. |
| 168 | std::unique_ptr<RtpPacketToSend> rtp_packet( |
| 169 | new RtpPacketToSend(*media_packet)); |
| 170 | RTC_CHECK(rtp_packet->Parse(fec_packet->data(), fec_packet->length())); |
| 171 | rtp_packet->set_capture_time_ms(media_packet->capture_time_ms()); |
| 172 | uint16_t fec_sequence_number = rtp_packet->SequenceNumber(); |
| 173 | if (rtp_sender_->SendToNetwork(std::move(rtp_packet), fec_storage, |
| 174 | RtpPacketSender::kLowPriority)) { |
sprang | cd349d9 | 2016-07-13 16:11:28 | [diff] [blame] | 175 | rtc::CritScope cs(&stats_crit_); |
| 176 | fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds()); |
sprang@webrtc.org | 0200f70 | 2015-02-16 12:06:00 | [diff] [blame] | 177 | TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 178 | "Video::PacketUlpfec", "timestamp", rtp_timestamp, |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 179 | "seqnum", fec_sequence_number); |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 180 | } else { |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 181 | LOG(LS_WARNING) << "Failed to send ULPFEC packet " << fec_sequence_number; |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | void RTPSenderVideo::SendVideoPacketWithFlexfec( |
| 187 | std::unique_ptr<RtpPacketToSend> media_packet, |
| 188 | StorageType media_packet_storage, |
| 189 | bool protect_media_packet) { |
| 190 | RTC_DCHECK(flexfec_sender_); |
| 191 | |
| 192 | if (protect_media_packet) |
| 193 | flexfec_sender_->AddRtpPacketAndGenerateFec(*media_packet); |
| 194 | |
| 195 | SendVideoPacket(std::move(media_packet), media_packet_storage); |
| 196 | |
| 197 | if (flexfec_sender_->FecAvailable()) { |
| 198 | std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = |
| 199 | flexfec_sender_->GetFecPackets(); |
| 200 | for (auto& fec_packet : fec_packets) { |
| 201 | uint32_t timestamp = fec_packet->Timestamp(); |
| 202 | uint16_t seq_num = fec_packet->SequenceNumber(); |
| 203 | if (rtp_sender_->SendToNetwork(std::move(fec_packet), kDontRetransmit, |
| 204 | RtpPacketSender::kLowPriority)) { |
| 205 | // TODO(brandtr): Wire up stats here. |
| 206 | TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), |
| 207 | "Video::PacketFlexfec", "timestamp", timestamp, |
| 208 | "seqnum", seq_num); |
| 209 | } else { |
| 210 | LOG(LS_WARNING) << "Failed to send FlexFEC packet " << seq_num; |
| 211 | } |
stefan@webrtc.org | fbea4e5 | 2011-10-27 16:08:29 | [diff] [blame] | 212 | } |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 | [diff] [blame] | 213 | } |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 214 | } |
| 215 | |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 216 | void RTPSenderVideo::SetUlpfecConfig(int red_payload_type, |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 217 | int ulpfec_payload_type) { |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 218 | // Sanity check. Per the definition of UlpfecConfig (see config.h), |
| 219 | // a payload type of -1 means that the corresponding feature is |
| 220 | // turned off. |
| 221 | RTC_DCHECK_GE(red_payload_type, -1); |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 222 | RTC_DCHECK_LE(red_payload_type, 127); |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 223 | RTC_DCHECK_GE(ulpfec_payload_type, -1); |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 224 | RTC_DCHECK_LE(ulpfec_payload_type, 127); |
| 225 | |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 226 | rtc::CritScope cs(&crit_); |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 227 | red_payload_type_ = red_payload_type; |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 228 | ulpfec_payload_type_ = ulpfec_payload_type; |
| 229 | |
| 230 | // Must not enable ULPFEC without RED. |
| 231 | // TODO(brandtr): We currently support enabling RED without ULPFEC. Change |
| 232 | // this when we have removed the RED/RTX send-side workaround, so that we |
| 233 | // ensure that RED and ULPFEC are only enabled together. |
| 234 | RTC_DCHECK(red_enabled() || !ulpfec_enabled()); |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 235 | |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 236 | // Reset FEC parameters. |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 237 | delta_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom}; |
| 238 | key_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom}; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 239 | } |
| 240 | |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 241 | void RTPSenderVideo::GetUlpfecConfig(int* red_payload_type, |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 242 | int* ulpfec_payload_type) const { |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 243 | rtc::CritScope cs(&crit_); |
brandtr | d804895 | 2016-11-07 10:08:51 | [diff] [blame] | 244 | *red_payload_type = red_payload_type_; |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 245 | *ulpfec_payload_type = ulpfec_payload_type_; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 246 | } |
| 247 | |
brandtr | 6631e8a | 2016-09-13 10:23:29 | [diff] [blame] | 248 | size_t RTPSenderVideo::FecPacketOverhead() const { |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 249 | if (flexfec_enabled()) |
| 250 | return flexfec_sender_->MaxPacketOverhead(); |
| 251 | |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 252 | rtc::CritScope cs(&crit_); |
stefan | 8f4c77f | 2016-06-03 07:16:45 | [diff] [blame] | 253 | size_t overhead = 0; |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 254 | if (red_enabled()) { |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 255 | // The RED overhead is due to a small header. |
| 256 | overhead += kRedForFecHeaderLength; |
| 257 | } |
| 258 | if (ulpfec_enabled()) { |
| 259 | // For ULPFEC, the overhead is the FEC headers plus RED for FEC header |
| 260 | // (see above) plus anything in RTP header beyond the 12 bytes base header |
| 261 | // (CSRC list, extensions...) |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 262 | // This reason for the header extensions to be included here is that |
| 263 | // from an FEC viewpoint, they are part of the payload to be protected. |
| 264 | // (The base RTP header is already protected by the FEC header.) |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 265 | overhead += ulpfec_generator_.MaxPacketOverhead() + |
| 266 | (rtp_sender_->RtpHeaderLength() - kRtpHeaderSize); |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 267 | } |
stefan | 8f4c77f | 2016-06-03 07:16:45 | [diff] [blame] | 268 | return overhead; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 269 | } |
| 270 | |
brandtr | 1743a19 | 2016-11-07 11:36:05 | [diff] [blame] | 271 | void RTPSenderVideo::SetFecParameters(const FecProtectionParams& delta_params, |
| 272 | const FecProtectionParams& key_params) { |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 273 | rtc::CritScope cs(&crit_); |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 274 | delta_fec_params_ = delta_params; |
| 275 | key_fec_params_ = key_params; |
marpan@google.com | 80c5d7a | 2011-07-15 21:32:40 | [diff] [blame] | 276 | } |
| 277 | |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 278 | bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type, |
| 279 | FrameType frame_type, |
| 280 | int8_t payload_type, |
danilchap | e5b4141 | 2016-08-22 10:39:23 | [diff] [blame] | 281 | uint32_t rtp_timestamp, |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 282 | int64_t capture_time_ms, |
| 283 | const uint8_t* payload_data, |
| 284 | size_t payload_size, |
| 285 | const RTPFragmentationHeader* fragmentation, |
| 286 | const RTPVideoHeader* video_header) { |
danilchap | c1600c5 | 2016-10-26 10:33:11 | [diff] [blame] | 287 | RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_checker_); |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 288 | if (payload_size == 0) |
| 289 | return false; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 290 | |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 291 | // Create header that will be reused in all packets. |
| 292 | std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket(); |
| 293 | rtp_header->SetPayloadType(payload_type); |
| 294 | rtp_header->SetTimestamp(rtp_timestamp); |
| 295 | rtp_header->set_capture_time_ms(capture_time_ms); |
| 296 | // According to |
| 297 | // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ |
| 298 | // ts_126114v120700p.pdf Section 7.4.5: |
| 299 | // The MTSI client shall add the payload bytes as defined in this clause |
| 300 | // onto the last RTP packet in each group of packets which make up a key |
| 301 | // frame (I-frame or IDR frame in H.264 (AVC), or an IRAP picture in H.265 |
| 302 | // (HEVC)). The MTSI client may also add the payload bytes onto the last RTP |
| 303 | // packet in each group of packets which make up another type of frame |
| 304 | // (e.g. a P-Frame) only if the current value is different from the previous |
| 305 | // value sent. |
danilchap | c1600c5 | 2016-10-26 10:33:11 | [diff] [blame] | 306 | if (video_header) { |
| 307 | // Set rotation when key frame or when changed (to follow standard). |
| 308 | // Or when different from 0 (to follow current receiver implementation). |
| 309 | VideoRotation current_rotation = video_header->rotation; |
| 310 | if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ || |
| 311 | current_rotation != kVideoRotation_0) |
| 312 | rtp_header->SetExtension<VideoOrientation>(current_rotation); |
| 313 | last_rotation_ = current_rotation; |
| 314 | } |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 315 | |
| 316 | size_t packet_capacity = rtp_sender_->MaxPayloadLength() - |
| 317 | FecPacketOverhead() - |
| 318 | (rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0); |
| 319 | RTC_DCHECK_LE(packet_capacity, rtp_header->capacity()); |
| 320 | RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size()); |
| 321 | size_t max_data_payload_length = packet_capacity - rtp_header->headers_size(); |
| 322 | |
kwiberg | 84be511 | 2016-04-27 08:19:58 | [diff] [blame] | 323 | std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create( |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 324 | video_type, max_data_payload_length, |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 325 | video_header ? &(video_header->codecHeader) : nullptr, frame_type)); |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 326 | |
Peter Boström | e23e737 | 2015-10-08 09:44:14 | [diff] [blame] | 327 | StorageType storage; |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 328 | bool red_enabled; |
skvlad | 98bb664 | 2016-04-07 22:36:45 | [diff] [blame] | 329 | bool first_frame = first_frame_sent_(); |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 330 | { |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 331 | rtc::CritScope cs(&crit_); |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 332 | |
| 333 | // Media packet storage. |
| 334 | storage = packetizer->GetStorageType(retransmission_settings_); |
| 335 | |
| 336 | // FEC settings. |
brandtr | 1743a19 | 2016-11-07 11:36:05 | [diff] [blame] | 337 | const FecProtectionParams& fec_params = |
| 338 | frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_; |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 339 | if (flexfec_enabled()) |
| 340 | flexfec_sender_->SetFecParameters(fec_params); |
brandtr | f1bb476 | 2016-11-07 11:05:06 | [diff] [blame] | 341 | red_enabled = this->red_enabled(); |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 342 | if (ulpfec_enabled()) |
| 343 | ulpfec_generator_.SetFecParameters(fec_params); |
stefan@webrtc.org | 2ec5606 | 2014-07-31 14:59:24 | [diff] [blame] | 344 | } |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 | [diff] [blame] | 345 | |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 346 | // TODO(changbin): we currently don't support to configure the codec to |
| 347 | // output multiple partitions for VP8. Should remove below check after the |
| 348 | // issue is fixed. |
| 349 | const RTPFragmentationHeader* frag = |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 350 | (video_type == kRtpVideoVp8) ? NULL : fragmentation; |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 351 | |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 352 | packetizer->SetPayloadData(payload_data, payload_size, frag); |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 353 | |
skvlad | 98bb664 | 2016-04-07 22:36:45 | [diff] [blame] | 354 | bool first = true; |
stefan@webrtc.org | 2ec5606 | 2014-07-31 14:59:24 | [diff] [blame] | 355 | bool last = false; |
stefan@webrtc.org | 2ec5606 | 2014-07-31 14:59:24 | [diff] [blame] | 356 | while (!last) { |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 357 | std::unique_ptr<RtpPacketToSend> packet(new RtpPacketToSend(*rtp_header)); |
| 358 | uint8_t* payload = packet->AllocatePayload(max_data_payload_length); |
| 359 | RTC_DCHECK(payload); |
| 360 | |
stefan@webrtc.org | 2ec5606 | 2014-07-31 14:59:24 | [diff] [blame] | 361 | size_t payload_bytes_in_packet = 0; |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 362 | if (!packetizer->NextPacket(payload, &payload_bytes_in_packet, &last)) |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 363 | return false; |
isheriff | 6b4b5f3 | 2016-06-08 07:24:21 | [diff] [blame] | 364 | |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 365 | packet->SetPayloadSize(payload_bytes_in_packet); |
| 366 | packet->SetMarker(last); |
| 367 | if (!rtp_sender_->AssignSequenceNumber(packet.get())) |
| 368 | return false; |
| 369 | |
brandtr | 131bc49 | 2016-11-10 13:01:11 | [diff] [blame] | 370 | const bool protect_packet = |
| 371 | (packetizer->GetProtectionType() == kProtectedPacket); |
| 372 | if (flexfec_enabled()) { |
| 373 | // TODO(brandtr): Remove the FlexFEC code path when FlexfecSender |
| 374 | // is wired up to PacedSender instead. |
| 375 | SendVideoPacketWithFlexfec(std::move(packet), storage, protect_packet); |
| 376 | } else if (red_enabled) { |
| 377 | SendVideoPacketAsRedMaybeWithUlpfec(std::move(packet), storage, |
| 378 | protect_packet); |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 379 | } else { |
danilchap | 7411061 | 2016-10-02 17:54:29 | [diff] [blame] | 380 | SendVideoPacket(std::move(packet), storage); |
stefan@webrtc.org | 2ec5606 | 2014-07-31 14:59:24 | [diff] [blame] | 381 | } |
skvlad | 98bb664 | 2016-04-07 22:36:45 | [diff] [blame] | 382 | |
| 383 | if (first_frame) { |
| 384 | if (first) { |
| 385 | LOG(LS_INFO) |
| 386 | << "Sent first RTP packet of the first video frame (pre-pacer)"; |
| 387 | } |
| 388 | if (last) { |
| 389 | LOG(LS_INFO) |
| 390 | << "Sent last RTP packet of the first video frame (pre-pacer)"; |
| 391 | } |
| 392 | } |
| 393 | first = false; |
stefan@webrtc.org | 2ec5606 | 2014-07-31 14:59:24 | [diff] [blame] | 394 | } |
pbos@webrtc.org | b5e6bfc | 2014-09-12 11:05:55 | [diff] [blame] | 395 | |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 396 | TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms, "timestamp", |
danilchap | e5b4141 | 2016-08-22 10:39:23 | [diff] [blame] | 397 | rtp_timestamp); |
Sergey Ulanov | 525df3f | 2016-08-03 00:46:41 | [diff] [blame] | 398 | return true; |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 399 | } |
| 400 | |
pbos@webrtc.org | 2f44673 | 2013-04-08 11:08:41 | [diff] [blame] | 401 | uint32_t RTPSenderVideo::VideoBitrateSent() const { |
sprang | cd349d9 | 2016-07-13 16:11:28 | [diff] [blame] | 402 | rtc::CritScope cs(&stats_crit_); |
| 403 | return video_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0); |
stefan@webrtc.org | fbea4e5 | 2011-10-27 16:08:29 | [diff] [blame] | 404 | } |
| 405 | |
pbos@webrtc.org | 2f44673 | 2013-04-08 11:08:41 | [diff] [blame] | 406 | uint32_t RTPSenderVideo::FecOverheadRate() const { |
sprang | cd349d9 | 2016-07-13 16:11:28 | [diff] [blame] | 407 | rtc::CritScope cs(&stats_crit_); |
| 408 | return fec_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0); |
stefan@webrtc.org | d0bdab0 | 2011-10-14 14:24:54 | [diff] [blame] | 409 | } |
| 410 | |
stefan@webrtc.org | 6a4bef4 | 2011-12-22 12:52:41 | [diff] [blame] | 411 | int RTPSenderVideo::SelectiveRetransmissions() const { |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 412 | rtc::CritScope cs(&crit_); |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 413 | return retransmission_settings_; |
stefan@webrtc.org | 6a4bef4 | 2011-12-22 12:52:41 | [diff] [blame] | 414 | } |
| 415 | |
mflodman | fcf54bd | 2015-04-14 19:28:08 | [diff] [blame] | 416 | void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) { |
danilchap | 7c9426c | 2016-04-14 10:05:31 | [diff] [blame] | 417 | rtc::CritScope cs(&crit_); |
Sergey Ulanov | ec4f068 | 2016-07-28 22:19:10 | [diff] [blame] | 418 | retransmission_settings_ = settings; |
stefan@webrtc.org | 6a4bef4 | 2011-12-22 12:52:41 | [diff] [blame] | 419 | } |
| 420 | |
pbos@webrtc.org | d900e8b | 2013-07-03 15:12:26 | [diff] [blame] | 421 | } // namespace webrtc |