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