blob: 341bba90a4a5f47c7a6354d64844171030fa5e0e [file] [log] [blame]
philipel4e702162020-11-27 17:56:37 +01001/*
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_vp8_ref_finder.h"
12
13#include <utility>
14
15#include "rtc_base/logging.h"
16
17namespace webrtc {
18namespace video_coding {
19
20RtpFrameReferenceFinder::ReturnVector RtpVp8RefFinder::ManageFrame(
21 std::unique_ptr<RtpFrameObject> frame) {
22 FrameDecision decision = ManageFrameInternal(frame.get());
23
24 RtpFrameReferenceFinder::ReturnVector res;
25 switch (decision) {
26 case kStash:
27 if (stashed_frames_.size() > kMaxStashedFrames)
28 stashed_frames_.pop_back();
29 stashed_frames_.push_front(std::move(frame));
30 return res;
31 case kHandOff:
32 res.push_back(std::move(frame));
33 RetryStashedFrames(res);
34 return res;
35 case kDrop:
36 return res;
37 }
38
39 return res;
40}
41
42RtpVp8RefFinder::FrameDecision RtpVp8RefFinder::ManageFrameInternal(
43 RtpFrameObject* frame) {
44 const RTPVideoHeader& video_header = frame->GetRtpVideoHeader();
45 const RTPVideoHeaderVP8& codec_header =
46 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
47
48 // Protect against corrupted packets with arbitrary large temporal idx.
49 if (codec_header.temporalIdx >= kMaxTemporalLayers)
50 return kDrop;
51
52 frame->id.picture_id = codec_header.pictureId & 0x7FFF;
53
54 if (last_picture_id_ == -1)
55 last_picture_id_ = frame->id.picture_id;
56
57 // Clean up info about not yet received frames that are too old.
58 uint16_t old_picture_id =
59 Subtract<kFrameIdLength>(frame->id.picture_id, kMaxNotYetReceivedFrames);
60 auto clean_frames_to = not_yet_received_frames_.lower_bound(old_picture_id);
61 not_yet_received_frames_.erase(not_yet_received_frames_.begin(),
62 clean_frames_to);
63 // Avoid re-adding picture ids that were just erased.
64 if (AheadOf<uint16_t, kFrameIdLength>(old_picture_id, last_picture_id_)) {
65 last_picture_id_ = old_picture_id;
66 }
67 // Find if there has been a gap in fully received frames and save the picture
68 // id of those frames in |not_yet_received_frames_|.
69 if (AheadOf<uint16_t, kFrameIdLength>(frame->id.picture_id,
70 last_picture_id_)) {
71 do {
72 last_picture_id_ = Add<kFrameIdLength>(last_picture_id_, 1);
73 not_yet_received_frames_.insert(last_picture_id_);
74 } while (last_picture_id_ != frame->id.picture_id);
75 }
76
77 int64_t unwrapped_tl0 = tl0_unwrapper_.Unwrap(codec_header.tl0PicIdx & 0xFF);
78
79 // Clean up info for base layers that are too old.
80 int64_t old_tl0_pic_idx = unwrapped_tl0 - kMaxLayerInfo;
81 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx);
82 layer_info_.erase(layer_info_.begin(), clean_layer_info_to);
83
84 if (frame->frame_type() == VideoFrameType::kVideoFrameKey) {
85 if (codec_header.temporalIdx != 0) {
86 return kDrop;
87 }
88 frame->num_references = 0;
89 layer_info_[unwrapped_tl0].fill(-1);
90 UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
91 return kHandOff;
92 }
93
94 auto layer_info_it = layer_info_.find(
95 codec_header.temporalIdx == 0 ? unwrapped_tl0 - 1 : unwrapped_tl0);
96
97 // If we don't have the base layer frame yet, stash this frame.
98 if (layer_info_it == layer_info_.end())
99 return kStash;
100
101 // A non keyframe base layer frame has been received, copy the layer info
102 // from the previous base layer frame and set a reference to the previous
103 // base layer frame.
104 if (codec_header.temporalIdx == 0) {
105 layer_info_it =
106 layer_info_.emplace(unwrapped_tl0, layer_info_it->second).first;
107 frame->num_references = 1;
108 int64_t last_pid_on_layer = layer_info_it->second[0];
109
110 // Is this an old frame that has already been used to update the state? If
111 // so, drop it.
112 if (AheadOrAt<uint16_t, kFrameIdLength>(last_pid_on_layer,
113 frame->id.picture_id)) {
114 return kDrop;
115 }
116
117 frame->references[0] = last_pid_on_layer;
118 UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
119 return kHandOff;
120 }
121
122 // Layer sync frame, this frame only references its base layer frame.
123 if (codec_header.layerSync) {
124 frame->num_references = 1;
125 int64_t last_pid_on_layer = layer_info_it->second[codec_header.temporalIdx];
126
127 // Is this an old frame that has already been used to update the state? If
128 // so, drop it.
129 if (last_pid_on_layer != -1 &&
130 AheadOrAt<uint16_t, kFrameIdLength>(last_pid_on_layer,
131 frame->id.picture_id)) {
132 return kDrop;
133 }
134
135 frame->references[0] = layer_info_it->second[0];
136 UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
137 return kHandOff;
138 }
139
140 // Find all references for this frame.
141 frame->num_references = 0;
142 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) {
143 // If we have not yet received a previous frame on this temporal layer,
144 // stash this frame.
145 if (layer_info_it->second[layer] == -1)
146 return kStash;
147
148 // If the last frame on this layer is ahead of this frame it means that
149 // a layer sync frame has been received after this frame for the same
150 // base layer frame, drop this frame.
151 if (AheadOf<uint16_t, kFrameIdLength>(layer_info_it->second[layer],
152 frame->id.picture_id)) {
153 return kDrop;
154 }
155
156 // If we have not yet received a frame between this frame and the referenced
157 // frame then we have to wait for that frame to be completed first.
158 auto not_received_frame_it =
159 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]);
160 if (not_received_frame_it != not_yet_received_frames_.end() &&
161 AheadOf<uint16_t, kFrameIdLength>(frame->id.picture_id,
162 *not_received_frame_it)) {
163 return kStash;
164 }
165
166 if (!(AheadOf<uint16_t, kFrameIdLength>(frame->id.picture_id,
167 layer_info_it->second[layer]))) {
168 RTC_LOG(LS_WARNING) << "Frame with picture id " << frame->id.picture_id
169 << " and packet range [" << frame->first_seq_num()
170 << ", " << frame->last_seq_num()
171 << "] already received, "
172 " dropping frame.";
173 return kDrop;
174 }
175
176 ++frame->num_references;
177 frame->references[layer] = layer_info_it->second[layer];
178 }
179
180 UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
181 return kHandOff;
182}
183
184void RtpVp8RefFinder::UpdateLayerInfoVp8(RtpFrameObject* frame,
185 int64_t unwrapped_tl0,
186 uint8_t temporal_idx) {
187 auto layer_info_it = layer_info_.find(unwrapped_tl0);
188
189 // Update this layer info and newer.
190 while (layer_info_it != layer_info_.end()) {
191 if (layer_info_it->second[temporal_idx] != -1 &&
192 AheadOf<uint16_t, kFrameIdLength>(layer_info_it->second[temporal_idx],
193 frame->id.picture_id)) {
194 // The frame was not newer, then no subsequent layer info have to be
195 // update.
196 break;
197 }
198
199 layer_info_it->second[temporal_idx] = frame->id.picture_id;
200 ++unwrapped_tl0;
201 layer_info_it = layer_info_.find(unwrapped_tl0);
202 }
203 not_yet_received_frames_.erase(frame->id.picture_id);
204
205 UnwrapPictureIds(frame);
206}
207
208void RtpVp8RefFinder::RetryStashedFrames(
209 RtpFrameReferenceFinder::ReturnVector& res) {
210 bool complete_frame = false;
211 do {
212 complete_frame = false;
213 for (auto frame_it = stashed_frames_.begin();
214 frame_it != stashed_frames_.end();) {
215 FrameDecision decision = ManageFrameInternal(frame_it->get());
216
217 switch (decision) {
218 case kStash:
219 ++frame_it;
220 break;
221 case kHandOff:
222 complete_frame = true;
223 res.push_back(std::move(*frame_it));
224 ABSL_FALLTHROUGH_INTENDED;
225 case kDrop:
226 frame_it = stashed_frames_.erase(frame_it);
227 }
228 }
229 } while (complete_frame);
230}
231
232void RtpVp8RefFinder::UnwrapPictureIds(RtpFrameObject* frame) {
233 for (size_t i = 0; i < frame->num_references; ++i)
234 frame->references[i] = unwrapper_.Unwrap(frame->references[i]);
235 frame->id.picture_id = unwrapper_.Unwrap(frame->id.picture_id);
236}
237
238void RtpVp8RefFinder::ClearTo(uint16_t seq_num) {
239 auto it = stashed_frames_.begin();
240 while (it != stashed_frames_.end()) {
241 if (AheadOf<uint16_t>(seq_num, (*it)->first_seq_num())) {
242 it = stashed_frames_.erase(it);
243 } else {
244 ++it;
245 }
246 }
247}
248
249} // namespace video_coding
250} // namespace webrtc