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