loss_notification_controller.cc (6587B)
1 /* 2 * Copyright (c) 2019 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 "modules/video_coding/loss_notification_controller.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 16 #include "api/array_view.h" 17 #include "api/sequence_checker.h" 18 #include "modules/include/module_common_types.h" 19 #include "rtc_base/checks.h" 20 #include "rtc_base/logging.h" 21 #include "rtc_base/numerics/sequence_number_util.h" 22 23 namespace webrtc { 24 namespace { 25 // Keep a container's size no higher than `max_allowed_size`, by paring its size 26 // down to `target_size` whenever it has more than `max_allowed_size` elements. 27 template <typename Container> 28 void PareDown(Container* container, 29 size_t max_allowed_size, 30 size_t target_size) { 31 if (container->size() > max_allowed_size) { 32 const size_t entries_to_delete = container->size() - target_size; 33 auto erase_to = container->begin(); 34 std::advance(erase_to, entries_to_delete); 35 container->erase(container->begin(), erase_to); 36 RTC_DCHECK_EQ(container->size(), target_size); 37 } 38 } 39 } // namespace 40 41 LossNotificationController::LossNotificationController( 42 KeyFrameRequestSender* key_frame_request_sender, 43 LossNotificationSender* loss_notification_sender) 44 : key_frame_request_sender_(key_frame_request_sender), 45 loss_notification_sender_(loss_notification_sender), 46 current_frame_potentially_decodable_(true) { 47 RTC_DCHECK(key_frame_request_sender_); 48 RTC_DCHECK(loss_notification_sender_); 49 } 50 51 LossNotificationController::~LossNotificationController() = default; 52 53 void LossNotificationController::OnReceivedPacket( 54 uint16_t rtp_seq_num, 55 const LossNotificationController::FrameDetails* frame) { 56 RTC_DCHECK_RUN_ON(&sequence_checker_); 57 58 // Ignore repeated or reordered packets. 59 // TODO(bugs.webrtc.org/10336): Handle packet reordering. 60 if (last_received_seq_num_ && 61 !AheadOf(rtp_seq_num, *last_received_seq_num_)) { 62 return; 63 } 64 65 DiscardOldInformation(); // Prevent memory overconsumption. 66 67 const bool seq_num_gap = 68 last_received_seq_num_ && 69 rtp_seq_num != static_cast<uint16_t>(*last_received_seq_num_ + 1u); 70 71 last_received_seq_num_ = rtp_seq_num; 72 73 // `frame` is not nullptr iff the packet is the first packet in the frame. 74 if (frame != nullptr) { 75 // Ignore repeated or reordered frames. 76 // TODO(bugs.webrtc.org/10336): Handle frame reordering. 77 if (last_received_frame_id_.has_value() && 78 frame->frame_id <= last_received_frame_id_.value()) { 79 RTC_LOG(LS_WARNING) << "Repeated or reordered frame ID (" 80 << frame->frame_id << ")."; 81 return; 82 } 83 84 last_received_frame_id_ = frame->frame_id; 85 86 if (frame->is_keyframe) { 87 // Subsequent frames may not rely on frames before the key frame. 88 // Note that upon receiving a key frame, we do not issue a loss 89 // notification on RTP sequence number gap, unless that gap spanned 90 // the key frame itself. This is because any loss which occurred before 91 // the key frame is no longer relevant. 92 decodable_frame_ids_.clear(); 93 current_frame_potentially_decodable_ = true; 94 } else { 95 const bool all_dependencies_decodable = 96 AllDependenciesDecodable(frame->frame_dependencies); 97 current_frame_potentially_decodable_ = all_dependencies_decodable; 98 if (seq_num_gap || !current_frame_potentially_decodable_) { 99 HandleLoss(rtp_seq_num, current_frame_potentially_decodable_); 100 } 101 } 102 } else if (seq_num_gap || !current_frame_potentially_decodable_) { 103 current_frame_potentially_decodable_ = false; 104 // We allow sending multiple loss notifications for a single frame 105 // even if only one of its packets is lost. We do this because the bigger 106 // the frame, the more likely it is to be non-discardable, and therefore 107 // the more robust we wish to be to loss of the feedback messages. 108 HandleLoss(rtp_seq_num, false); 109 } 110 } 111 112 void LossNotificationController::OnAssembledFrame( 113 uint16_t first_seq_num, 114 int64_t frame_id, 115 bool discardable, 116 ArrayView<const int64_t> frame_dependencies) { 117 RTC_DCHECK_RUN_ON(&sequence_checker_); 118 119 DiscardOldInformation(); // Prevent memory overconsumption. 120 121 if (discardable) { 122 return; 123 } 124 125 if (!AllDependenciesDecodable(frame_dependencies)) { 126 return; 127 } 128 129 last_decodable_non_discardable_.emplace(first_seq_num); 130 const auto it = decodable_frame_ids_.insert(frame_id); 131 RTC_DCHECK(it.second); 132 } 133 134 void LossNotificationController::DiscardOldInformation() { 135 constexpr size_t kExpectedKeyFrameIntervalFrames = 3000; 136 constexpr size_t kMaxSize = 2 * kExpectedKeyFrameIntervalFrames; 137 constexpr size_t kTargetSize = kExpectedKeyFrameIntervalFrames; 138 PareDown(&decodable_frame_ids_, kMaxSize, kTargetSize); 139 } 140 141 bool LossNotificationController::AllDependenciesDecodable( 142 ArrayView<const int64_t> frame_dependencies) const { 143 RTC_DCHECK_RUN_ON(&sequence_checker_); 144 145 // Due to packet reordering, frame buffering and asynchronous decoders, it is 146 // infeasible to make reliable conclusions on the decodability of a frame 147 // immediately when it arrives. We use the following assumptions: 148 // * Intra frames are decodable. 149 // * Inter frames are decodable if all of their references were decodable. 150 // One possibility that is ignored, is that the packet may be corrupt. 151 for (int64_t ref_frame_id : frame_dependencies) { 152 const auto ref_frame_it = decodable_frame_ids_.find(ref_frame_id); 153 if (ref_frame_it == decodable_frame_ids_.end()) { 154 // Reference frame not decodable. 155 return false; 156 } 157 } 158 159 return true; 160 } 161 162 void LossNotificationController::HandleLoss(uint16_t last_received_seq_num, 163 bool decodability_flag) { 164 RTC_DCHECK_RUN_ON(&sequence_checker_); 165 166 if (last_decodable_non_discardable_) { 167 RTC_DCHECK(AheadOf(last_received_seq_num, 168 last_decodable_non_discardable_->first_seq_num)); 169 loss_notification_sender_->SendLossNotification( 170 last_decodable_non_discardable_->first_seq_num, last_received_seq_num, 171 decodability_flag, /*buffering_allowed=*/true); 172 } else { 173 key_frame_request_sender_->RequestKeyFrame(); 174 } 175 } 176 } // namespace webrtc