blob: 6389fd0454c90dfb07167072a1d0519a7b24b71d [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
46void LossNotificationController::OnReceivedPacket(const VCMPacket& packet) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020047 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +010048
49 if (!packet.generic_descriptor) {
50 RTC_LOG(LS_WARNING) << "Generic frame descriptor missing. Buggy remote? "
51 "Misconfigured local?";
52 return;
53 }
54
55 // Ignore repeated or reordered packets.
56 // TODO(bugs.webrtc.org/10336): Handle packet reordering.
57 if (last_received_seq_num_ &&
58 !AheadOf(packet.seqNum, *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 packet.seqNum != static_cast<uint16_t>(*last_received_seq_num_ + 1u);
67
68 last_received_seq_num_ = packet.seqNum;
69
70 if (packet.generic_descriptor->FirstPacketInSubFrame()) {
71 const uint16_t frame_id = packet.generic_descriptor->FrameId();
Philip Eliasson1f850a62019-03-19 12:15:00 +000072 const int64_t unwrapped_frame_id = frame_id_unwrapper_.Unwrap(frame_id);
Elad Alon10874b22019-02-21 16:25:40 +010073
74 // Ignore repeated or reordered frames.
75 // TODO(TODO(bugs.webrtc.org/10336): Handle frame reordering.
76 if (last_received_unwrapped_frame_id_ &&
77 unwrapped_frame_id <= *last_received_unwrapped_frame_id_) {
78 RTC_LOG(LS_WARNING) << "Repeated or reordered frame ID (" << frame_id
79 << ").";
80 return;
81 }
82
83 last_received_unwrapped_frame_id_ = unwrapped_frame_id;
84
85 const bool intra_frame =
86 packet.generic_descriptor->FrameDependenciesDiffs().empty();
87 // Generic Frame Descriptor does not current allow us to distinguish
88 // whether an intra frame is a key frame.
89 // We therefore assume all intra frames are key frames.
90 const bool key_frame = intra_frame;
91 if (key_frame) {
92 // Subsequent frames may not rely on frames before the key frame.
Elad Alonb6ef99b2019-04-10 16:37:07 +020093 // Note that upon receiving a key frame, we do not issue a loss
94 // notification on RTP sequence number gap, unless that gap spanned
95 // the key frame itself. This is because any loss which occurred before
96 // the key frame is no longer relevant.
Elad Alon10874b22019-02-21 16:25:40 +010097 decodable_unwrapped_frame_ids_.clear();
98 current_frame_potentially_decodable_ = true;
99 } else {
100 const bool all_dependencies_decodable = AllDependenciesDecodable(
101 unwrapped_frame_id,
102 packet.generic_descriptor->FrameDependenciesDiffs());
103 current_frame_potentially_decodable_ = all_dependencies_decodable;
104 if (seq_num_gap || !current_frame_potentially_decodable_) {
105 HandleLoss(packet.seqNum, current_frame_potentially_decodable_);
106 }
107 }
108 } else if (seq_num_gap || !current_frame_potentially_decodable_) {
109 current_frame_potentially_decodable_ = false;
110 // We allow sending multiple loss notifications for a single frame
111 // even if only one of its packets is lost. We do this because the bigger
112 // the frame, the more likely it is to be non-discardable, and therefore
113 // the more robust we wish to be to loss of the feedback messages.
114 HandleLoss(packet.seqNum, false);
115 }
116}
117
118void LossNotificationController::OnAssembledFrame(
119 uint16_t first_seq_num,
120 uint16_t frame_id,
121 bool discardable,
122 rtc::ArrayView<const uint16_t> frame_dependency_diffs) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200123 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +0100124
125 DiscardOldInformation(); // Prevent memory overconsumption.
126
127 if (discardable) {
128 return;
129 }
130
Philip Eliasson1f850a62019-03-19 12:15:00 +0000131 const int64_t unwrapped_frame_id = frame_id_unwrapper_.Unwrap(frame_id);
Elad Alon10874b22019-02-21 16:25:40 +0100132 if (!AllDependenciesDecodable(unwrapped_frame_id, frame_dependency_diffs)) {
133 return;
134 }
135
136 last_decodable_non_discardable_.emplace(first_seq_num);
137 const auto it = decodable_unwrapped_frame_ids_.insert(unwrapped_frame_id);
138 RTC_DCHECK(it.second);
139}
140
141void LossNotificationController::DiscardOldInformation() {
142 constexpr size_t kExpectedKeyFrameIntervalFrames = 3000;
143 constexpr size_t kMaxSize = 2 * kExpectedKeyFrameIntervalFrames;
144 constexpr size_t kTargetSize = kExpectedKeyFrameIntervalFrames;
145 PareDown(&decodable_unwrapped_frame_ids_, kMaxSize, kTargetSize);
146}
147
148bool LossNotificationController::AllDependenciesDecodable(
Philip Eliasson1f850a62019-03-19 12:15:00 +0000149 int64_t unwrapped_frame_id,
Elad Alon10874b22019-02-21 16:25:40 +0100150 rtc::ArrayView<const uint16_t> frame_dependency_diffs) const {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200151 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +0100152
153 // Due to packet reordering, frame buffering and asynchronous decoders, it is
154 // infeasible to make reliable conclusions on the decodability of a frame
155 // immediately when it arrives. We use the following assumptions:
156 // * Intra frames are decodable.
157 // * Inter frames are decodable if all of their references were decodable.
158 // One possibility that is ignored, is that the packet may be corrupt.
159
160 for (uint16_t frame_dependency_diff : frame_dependency_diffs) {
Philip Eliasson1f850a62019-03-19 12:15:00 +0000161 const int64_t unwrapped_ref_frame_id =
Elad Alon10874b22019-02-21 16:25:40 +0100162 unwrapped_frame_id - frame_dependency_diff;
163
164 const auto ref_frame_it =
165 decodable_unwrapped_frame_ids_.find(unwrapped_ref_frame_id);
166 if (ref_frame_it == decodable_unwrapped_frame_ids_.end()) {
167 // Reference frame not decodable.
168 return false;
169 }
170 }
171
172 return true;
173}
174
175void LossNotificationController::HandleLoss(uint16_t last_received_seq_num,
176 bool decodability_flag) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200177 RTC_DCHECK_RUN_ON(&sequence_checker_);
Elad Alon10874b22019-02-21 16:25:40 +0100178
179 if (last_decodable_non_discardable_) {
180 RTC_DCHECK(AheadOf(last_received_seq_num,
181 last_decodable_non_discardable_->first_seq_num));
182 loss_notification_sender_->SendLossNotification(
183 last_decodable_non_discardable_->first_seq_num, last_received_seq_num,
Elad Alone86af2c2019-06-03 14:37:50 +0200184 decodability_flag, /*buffering_allowed=*/true);
Elad Alon10874b22019-02-21 16:25:40 +0100185 } else {
186 key_frame_request_sender_->RequestKeyFrame();
187 }
188}
189} // namespace webrtc