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