1 /*
2 * Copyright (c) 2020 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/rtp_seq_num_only_ref_finder.h"
12
13 #include <utility>
14
15 #include "rtc_base/logging.h"
16
17 namespace webrtc {
18
ManageFrame(std::unique_ptr<RtpFrameObject> frame)19 RtpFrameReferenceFinder::ReturnVector RtpSeqNumOnlyRefFinder::ManageFrame(
20 std::unique_ptr<RtpFrameObject> frame) {
21 FrameDecision decision = ManageFrameInternal(frame.get());
22
23 RtpFrameReferenceFinder::ReturnVector res;
24 switch (decision) {
25 case kStash:
26 if (stashed_frames_.size() > kMaxStashedFrames)
27 stashed_frames_.pop_back();
28 stashed_frames_.push_front(std::move(frame));
29 return res;
30 case kHandOff:
31 res.push_back(std::move(frame));
32 RetryStashedFrames(res);
33 return res;
34 case kDrop:
35 return res;
36 }
37
38 return res;
39 }
40
41 RtpSeqNumOnlyRefFinder::FrameDecision
ManageFrameInternal(RtpFrameObject * frame)42 RtpSeqNumOnlyRefFinder::ManageFrameInternal(RtpFrameObject* frame) {
43 if (frame->frame_type() == VideoFrameType::kVideoFrameKey) {
44 last_seq_num_gop_.insert(std::make_pair(
45 frame->last_seq_num(),
46 std::make_pair(frame->last_seq_num(), frame->last_seq_num())));
47 }
48
49 // We have received a frame but not yet a keyframe, stash this frame.
50 if (last_seq_num_gop_.empty())
51 return kStash;
52
53 // Clean up info for old keyframes but make sure to keep info
54 // for the last keyframe.
55 auto clean_to = last_seq_num_gop_.lower_bound(frame->last_seq_num() - 100);
56 for (auto it = last_seq_num_gop_.begin();
57 it != clean_to && last_seq_num_gop_.size() > 1;) {
58 it = last_seq_num_gop_.erase(it);
59 }
60
61 // Find the last sequence number of the last frame for the keyframe
62 // that this frame indirectly references.
63 auto seq_num_it = last_seq_num_gop_.upper_bound(frame->last_seq_num());
64 if (seq_num_it == last_seq_num_gop_.begin()) {
65 RTC_LOG(LS_WARNING) << "Generic frame with packet range ["
66 << frame->first_seq_num() << ", "
67 << frame->last_seq_num()
68 << "] has no GoP, dropping frame.";
69 return kDrop;
70 }
71 seq_num_it--;
72
73 // Make sure the packet sequence numbers are continuous, otherwise stash
74 // this frame.
75 uint16_t last_picture_id_gop = seq_num_it->second.first;
76 uint16_t last_picture_id_with_padding_gop = seq_num_it->second.second;
77 if (frame->frame_type() == VideoFrameType::kVideoFrameDelta) {
78 uint16_t prev_seq_num = frame->first_seq_num() - 1;
79
80 if (prev_seq_num != last_picture_id_with_padding_gop)
81 return kStash;
82 }
83
84 RTC_DCHECK(AheadOrAt(frame->last_seq_num(), seq_num_it->first));
85
86 // Since keyframes can cause reordering we can't simply assign the
87 // picture id according to some incrementing counter.
88 frame->SetId(frame->last_seq_num());
89 frame->num_references =
90 frame->frame_type() == VideoFrameType::kVideoFrameDelta;
91 frame->references[0] = rtp_seq_num_unwrapper_.Unwrap(last_picture_id_gop);
92 if (AheadOf<uint16_t>(frame->Id(), last_picture_id_gop)) {
93 seq_num_it->second.first = frame->Id();
94 seq_num_it->second.second = frame->Id();
95 }
96
97 UpdateLastPictureIdWithPadding(frame->Id());
98 frame->SetSpatialIndex(0);
99 frame->SetId(rtp_seq_num_unwrapper_.Unwrap(frame->Id()));
100 return kHandOff;
101 }
102
RetryStashedFrames(RtpFrameReferenceFinder::ReturnVector & res)103 void RtpSeqNumOnlyRefFinder::RetryStashedFrames(
104 RtpFrameReferenceFinder::ReturnVector& res) {
105 bool complete_frame = false;
106 do {
107 complete_frame = false;
108 for (auto frame_it = stashed_frames_.begin();
109 frame_it != stashed_frames_.end();) {
110 FrameDecision decision = ManageFrameInternal(frame_it->get());
111
112 switch (decision) {
113 case kStash:
114 ++frame_it;
115 break;
116 case kHandOff:
117 complete_frame = true;
118 res.push_back(std::move(*frame_it));
119 [[fallthrough]];
120 case kDrop:
121 frame_it = stashed_frames_.erase(frame_it);
122 }
123 }
124 } while (complete_frame);
125 }
126
UpdateLastPictureIdWithPadding(uint16_t seq_num)127 void RtpSeqNumOnlyRefFinder::UpdateLastPictureIdWithPadding(uint16_t seq_num) {
128 auto gop_seq_num_it = last_seq_num_gop_.upper_bound(seq_num);
129
130 // If this padding packet "belongs" to a group of pictures that we don't track
131 // anymore, do nothing.
132 if (gop_seq_num_it == last_seq_num_gop_.begin())
133 return;
134 --gop_seq_num_it;
135
136 // Calculate the next contiuous sequence number and search for it in
137 // the padding packets we have stashed.
138 uint16_t next_seq_num_with_padding = gop_seq_num_it->second.second + 1;
139 auto padding_seq_num_it =
140 stashed_padding_.lower_bound(next_seq_num_with_padding);
141
142 // While there still are padding packets and those padding packets are
143 // continuous, then advance the "last-picture-id-with-padding" and remove
144 // the stashed padding packet.
145 while (padding_seq_num_it != stashed_padding_.end() &&
146 *padding_seq_num_it == next_seq_num_with_padding) {
147 gop_seq_num_it->second.second = next_seq_num_with_padding;
148 ++next_seq_num_with_padding;
149 padding_seq_num_it = stashed_padding_.erase(padding_seq_num_it);
150 }
151
152 // In the case where the stream has been continuous without any new keyframes
153 // for a while there is a risk that new frames will appear to be older than
154 // the keyframe they belong to due to wrapping sequence number. In order
155 // to prevent this we advance the picture id of the keyframe every so often.
156 if (ForwardDiff(gop_seq_num_it->first, seq_num) > 10000) {
157 auto save = gop_seq_num_it->second;
158 last_seq_num_gop_.clear();
159 last_seq_num_gop_[seq_num] = save;
160 }
161 }
162
PaddingReceived(uint16_t seq_num)163 RtpFrameReferenceFinder::ReturnVector RtpSeqNumOnlyRefFinder::PaddingReceived(
164 uint16_t seq_num) {
165 auto clean_padding_to =
166 stashed_padding_.lower_bound(seq_num - kMaxPaddingAge);
167 stashed_padding_.erase(stashed_padding_.begin(), clean_padding_to);
168 stashed_padding_.insert(seq_num);
169 UpdateLastPictureIdWithPadding(seq_num);
170 RtpFrameReferenceFinder::ReturnVector res;
171 RetryStashedFrames(res);
172 return res;
173 }
174
ClearTo(uint16_t seq_num)175 void RtpSeqNumOnlyRefFinder::ClearTo(uint16_t seq_num) {
176 auto it = stashed_frames_.begin();
177 while (it != stashed_frames_.end()) {
178 if (AheadOf<uint16_t>(seq_num, (*it)->first_seq_num())) {
179 it = stashed_frames_.erase(it);
180 } else {
181 ++it;
182 }
183 }
184 }
185
186 } // namespace webrtc
187