blob: 20752f8a0770d4b7410c9fd5cead80b84ebf6949 [file] [log] [blame]
Elad Alon10874b22019-02-21 16:25:40 +01001/*
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 "rtc_base/checks.h"
14#include "rtc_base/logging.h"
15
16namespace webrtc {
17namespace {
18// Keep a container's size no higher than |max_allowed_size|, by paring its size
19// down to |target_size| whenever it has more than |max_allowed_size| elements.
20template <typename Container>
21void PareDown(Container* container,
22 size_t max_allowed_size,
23 size_t target_size) {
24 if (container->size() > max_allowed_size) {
25 const size_t entries_to_delete = container->size() - target_size;
26 auto erase_to = container->begin();
27 std::advance(erase_to, entries_to_delete);
28 container->erase(container->begin(), erase_to);
29 RTC_DCHECK_EQ(container->size(), target_size);
30 }
31}
32} // namespace
33
34LossNotificationController::LossNotificationController(
35 KeyFrameRequestSender* key_frame_request_sender,
36 LossNotificationSender* loss_notification_sender)
37 : key_frame_request_sender_(key_frame_request_sender),
38 loss_notification_sender_(loss_notification_sender),
39 current_frame_potentially_decodable_(true) {
40 RTC_DCHECK(key_frame_request_sender_);
41 RTC_DCHECK(loss_notification_sender_);
42}
43
44LossNotificationController::~LossNotificationController() = default;
45
Niels Möllera7401422019-09-13 14:18:58 +020046void LossNotificationController::OnReceivedPacket(
47 uint16_t rtp_seq_num,
48 const RtpGenericFrameDescriptor& generic_descriptor) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020049 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +010050
Elad Alon10874b22019-02-21 16:25:40 +010051 // Ignore repeated or reordered packets.
52 // TODO(bugs.webrtc.org/10336): Handle packet reordering.
53 if (last_received_seq_num_ &&
Niels Möllera7401422019-09-13 14:18:58 +020054 !AheadOf(rtp_seq_num, *last_received_seq_num_)) {
Elad Alon10874b22019-02-21 16:25:40 +010055 return;
56 }
57
58 DiscardOldInformation(); // Prevent memory overconsumption.
59
60 const bool seq_num_gap =
61 last_received_seq_num_ &&
Niels Möllera7401422019-09-13 14:18:58 +020062 rtp_seq_num != static_cast<uint16_t>(*last_received_seq_num_ + 1u);
Elad Alon10874b22019-02-21 16:25:40 +010063
Niels Möllera7401422019-09-13 14:18:58 +020064 last_received_seq_num_ = rtp_seq_num;
Elad Alon10874b22019-02-21 16:25:40 +010065
Niels Möllera7401422019-09-13 14:18:58 +020066 if (generic_descriptor.FirstPacketInSubFrame()) {
67 const uint16_t frame_id = generic_descriptor.FrameId();
Philip Eliasson1f850a62019-03-19 12:15:00 +000068 const int64_t unwrapped_frame_id = frame_id_unwrapper_.Unwrap(frame_id);
Elad Alon10874b22019-02-21 16:25:40 +010069
70 // Ignore repeated or reordered frames.
71 // TODO(TODO(bugs.webrtc.org/10336): Handle frame reordering.
72 if (last_received_unwrapped_frame_id_ &&
73 unwrapped_frame_id <= *last_received_unwrapped_frame_id_) {
74 RTC_LOG(LS_WARNING) << "Repeated or reordered frame ID (" << frame_id
75 << ").";
76 return;
77 }
78
79 last_received_unwrapped_frame_id_ = unwrapped_frame_id;
80
81 const bool intra_frame =
Niels Möllera7401422019-09-13 14:18:58 +020082 generic_descriptor.FrameDependenciesDiffs().empty();
Elad Alon10874b22019-02-21 16:25:40 +010083 // Generic Frame Descriptor does not current allow us to distinguish
84 // whether an intra frame is a key frame.
85 // We therefore assume all intra frames are key frames.
86 const bool key_frame = intra_frame;
87 if (key_frame) {
88 // Subsequent frames may not rely on frames before the key frame.
Elad Alonb6ef99b2019-04-10 16:37:07 +020089 // Note that upon receiving a key frame, we do not issue a loss
90 // notification on RTP sequence number gap, unless that gap spanned
91 // the key frame itself. This is because any loss which occurred before
92 // the key frame is no longer relevant.
Elad Alon10874b22019-02-21 16:25:40 +010093 decodable_unwrapped_frame_ids_.clear();
94 current_frame_potentially_decodable_ = true;
95 } else {
96 const bool all_dependencies_decodable = AllDependenciesDecodable(
Niels Möllera7401422019-09-13 14:18:58 +020097 unwrapped_frame_id, generic_descriptor.FrameDependenciesDiffs());
Elad Alon10874b22019-02-21 16:25:40 +010098 current_frame_potentially_decodable_ = all_dependencies_decodable;
99 if (seq_num_gap || !current_frame_potentially_decodable_) {
Niels Möllera7401422019-09-13 14:18:58 +0200100 HandleLoss(rtp_seq_num, current_frame_potentially_decodable_);
Elad Alon10874b22019-02-21 16:25:40 +0100101 }
102 }
103 } else if (seq_num_gap || !current_frame_potentially_decodable_) {
104 current_frame_potentially_decodable_ = false;
105 // We allow sending multiple loss notifications for a single frame
106 // even if only one of its packets is lost. We do this because the bigger
107 // the frame, the more likely it is to be non-discardable, and therefore
108 // the more robust we wish to be to loss of the feedback messages.
Niels Möllera7401422019-09-13 14:18:58 +0200109 HandleLoss(rtp_seq_num, false);
Elad Alon10874b22019-02-21 16:25:40 +0100110 }
111}
112
113void LossNotificationController::OnAssembledFrame(
114 uint16_t first_seq_num,
115 uint16_t frame_id,
116 bool discardable,
117 rtc::ArrayView<const uint16_t> frame_dependency_diffs) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200118 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +0100119
120 DiscardOldInformation(); // Prevent memory overconsumption.
121
122 if (discardable) {
123 return;
124 }
125
Philip Eliasson1f850a62019-03-19 12:15:00 +0000126 const int64_t unwrapped_frame_id = frame_id_unwrapper_.Unwrap(frame_id);
Elad Alon10874b22019-02-21 16:25:40 +0100127 if (!AllDependenciesDecodable(unwrapped_frame_id, frame_dependency_diffs)) {
128 return;
129 }
130
131 last_decodable_non_discardable_.emplace(first_seq_num);
132 const auto it = decodable_unwrapped_frame_ids_.insert(unwrapped_frame_id);
133 RTC_DCHECK(it.second);
134}
135
136void LossNotificationController::DiscardOldInformation() {
137 constexpr size_t kExpectedKeyFrameIntervalFrames = 3000;
138 constexpr size_t kMaxSize = 2 * kExpectedKeyFrameIntervalFrames;
139 constexpr size_t kTargetSize = kExpectedKeyFrameIntervalFrames;
140 PareDown(&decodable_unwrapped_frame_ids_, kMaxSize, kTargetSize);
141}
142
143bool LossNotificationController::AllDependenciesDecodable(
Philip Eliasson1f850a62019-03-19 12:15:00 +0000144 int64_t unwrapped_frame_id,
Elad Alon10874b22019-02-21 16:25:40 +0100145 rtc::ArrayView<const uint16_t> frame_dependency_diffs) const {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200146 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +0100147
148 // Due to packet reordering, frame buffering and asynchronous decoders, it is
149 // infeasible to make reliable conclusions on the decodability of a frame
150 // immediately when it arrives. We use the following assumptions:
151 // * Intra frames are decodable.
152 // * Inter frames are decodable if all of their references were decodable.
153 // One possibility that is ignored, is that the packet may be corrupt.
154
155 for (uint16_t frame_dependency_diff : frame_dependency_diffs) {
Philip Eliasson1f850a62019-03-19 12:15:00 +0000156 const int64_t unwrapped_ref_frame_id =
Elad Alon10874b22019-02-21 16:25:40 +0100157 unwrapped_frame_id - frame_dependency_diff;
158
159 const auto ref_frame_it =
160 decodable_unwrapped_frame_ids_.find(unwrapped_ref_frame_id);
161 if (ref_frame_it == decodable_unwrapped_frame_ids_.end()) {
162 // Reference frame not decodable.
163 return false;
164 }
165 }
166
167 return true;
168}
169
170void LossNotificationController::HandleLoss(uint16_t last_received_seq_num,
171 bool decodability_flag) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200172 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +0100173
174 if (last_decodable_non_discardable_) {
175 RTC_DCHECK(AheadOf(last_received_seq_num,
176 last_decodable_non_discardable_->first_seq_num));
177 loss_notification_sender_->SendLossNotification(
178 last_decodable_non_discardable_->first_seq_num, last_received_seq_num,
Elad Alone86af2c2019-06-03 14:37:50 +0200179 decodability_flag, /*buffering_allowed=*/true);
Elad Alon10874b22019-02-21 16:25:40 +0100180 } else {
181 key_frame_request_sender_->RequestKeyFrame();
182 }
183}
184} // namespace webrtc