OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/video_coding/packet_buffer.h" | 11 #include "webrtc/modules/video_coding/packet_buffer.h" |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <limits> | 14 #include <limits> |
15 | 15 |
16 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
17 #include "webrtc/modules/video_coding/frame_object.h" | 17 #include "webrtc/modules/video_coding/frame_object.h" |
18 #include "webrtc/modules/video_coding/sequence_number_util.h" | |
19 | 18 |
20 namespace webrtc { | 19 namespace webrtc { |
21 namespace video_coding { | 20 namespace video_coding { |
22 | 21 |
23 PacketBuffer::PacketBuffer(size_t start_buffer_size, | 22 PacketBuffer::PacketBuffer(size_t start_buffer_size, |
24 size_t max_buffer_size, | 23 size_t max_buffer_size, |
25 OnCompleteFrameCallback* frame_callback) | 24 OnCompleteFrameCallback* frame_callback) |
26 : size_(start_buffer_size), | 25 : size_(start_buffer_size), |
27 max_size_(max_buffer_size), | 26 max_size_(max_buffer_size), |
27 first_seq_num_(0), | |
28 last_seq_num_(0), | 28 last_seq_num_(0), |
29 first_seq_num_(0), | |
30 initialized_(false), | |
31 data_buffer_(start_buffer_size), | 29 data_buffer_(start_buffer_size), |
32 sequence_buffer_(start_buffer_size), | 30 sequence_buffer_(start_buffer_size), |
33 frame_callback_(frame_callback) { | 31 frame_callback_(frame_callback), |
32 last_picture_id_(-1), | |
33 last_unwrap_(-1), | |
34 initialized_(false) { | |
34 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); | 35 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); |
35 // Buffer size must always be a power of 2. | 36 // Buffer size must always be a power of 2. |
36 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0); | 37 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0); |
37 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0); | 38 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0); |
38 } | 39 } |
39 | 40 |
40 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { | 41 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { |
41 rtc::CritScope lock(&crit_); | 42 rtc::CritScope lock(&crit_); |
42 uint16_t seq_num = packet.seqNum; | 43 uint16_t seq_num = packet.seqNum; |
43 int index = seq_num % size_; | 44 int index = seq_num % size_; |
(...skipping 19 matching lines...) Expand all Loading... | |
63 return false; | 64 return false; |
64 } | 65 } |
65 | 66 |
66 if (AheadOf(seq_num, last_seq_num_)) | 67 if (AheadOf(seq_num, last_seq_num_)) |
67 last_seq_num_ = seq_num; | 68 last_seq_num_ = seq_num; |
68 | 69 |
69 sequence_buffer_[index].frame_begin = packet.isFirstPacket; | 70 sequence_buffer_[index].frame_begin = packet.isFirstPacket; |
70 sequence_buffer_[index].frame_end = packet.markerBit; | 71 sequence_buffer_[index].frame_end = packet.markerBit; |
71 sequence_buffer_[index].seq_num = packet.seqNum; | 72 sequence_buffer_[index].seq_num = packet.seqNum; |
72 sequence_buffer_[index].continuous = false; | 73 sequence_buffer_[index].continuous = false; |
74 sequence_buffer_[index].frame_created = false; | |
73 sequence_buffer_[index].used = true; | 75 sequence_buffer_[index].used = true; |
74 data_buffer_[index] = packet; | 76 data_buffer_[index] = packet; |
75 | 77 |
76 FindCompleteFrames(seq_num); | 78 FindFrames(seq_num); |
77 return true; | 79 return true; |
78 } | 80 } |
79 | 81 |
80 void PacketBuffer::ClearTo(uint16_t seq_num) { | 82 void PacketBuffer::ClearTo(uint16_t seq_num) { |
81 rtc::CritScope lock(&crit_); | 83 rtc::CritScope lock(&crit_); |
82 int index = first_seq_num_ % size_; | 84 int index = first_seq_num_ % size_; |
83 while (AheadOf<uint16_t>(seq_num, first_seq_num_ + 1)) { | 85 while (AheadOf<uint16_t>(seq_num, first_seq_num_ + 1)) { |
84 index = (index + 1) % size_; | 86 index = (index + 1) % size_; |
85 first_seq_num_ = Add<1 << 16>(first_seq_num_, 1); | 87 first_seq_num_ = Add<1 << 16>(first_seq_num_, 1); |
86 sequence_buffer_[index].used = false; | 88 sequence_buffer_[index].used = false; |
(...skipping 16 matching lines...) Expand all Loading... | |
103 } | 105 } |
104 size_ = new_size; | 106 size_ = new_size; |
105 sequence_buffer_ = std::move(new_sequence_buffer); | 107 sequence_buffer_ = std::move(new_sequence_buffer); |
106 data_buffer_ = std::move(new_data_buffer); | 108 data_buffer_ = std::move(new_data_buffer); |
107 return true; | 109 return true; |
108 } | 110 } |
109 | 111 |
110 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { | 112 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { |
111 int index = seq_num % size_; | 113 int index = seq_num % size_; |
112 int prev_index = index > 0 ? index - 1 : size_ - 1; | 114 int prev_index = index > 0 ? index - 1 : size_ - 1; |
115 | |
113 if (!sequence_buffer_[index].used) | 116 if (!sequence_buffer_[index].used) |
114 return false; | 117 return false; |
118 if (sequence_buffer_[index].frame_created) | |
119 return false; | |
115 if (sequence_buffer_[index].frame_begin) | 120 if (sequence_buffer_[index].frame_begin) |
116 return true; | 121 return true; |
117 if (!sequence_buffer_[prev_index].used) | 122 if (!sequence_buffer_[prev_index].used) |
118 return false; | 123 return false; |
119 if (sequence_buffer_[prev_index].continuous) | 124 if (sequence_buffer_[prev_index].continuous) |
120 return true; | 125 return true; |
121 | 126 |
122 return false; | 127 return false; |
123 } | 128 } |
124 | 129 |
125 void PacketBuffer::FindCompleteFrames(uint16_t seq_num) { | 130 void PacketBuffer::FindFrames(uint16_t seq_num) { |
126 int index = seq_num % size_; | 131 int index = seq_num % size_; |
127 while (IsContinuous(seq_num)) { | 132 while (IsContinuous(seq_num)) { |
128 sequence_buffer_[index].continuous = true; | 133 sequence_buffer_[index].continuous = true; |
129 | 134 |
130 // If the frame is complete, find the first packet of the frame and | 135 // If all packets of the frame is contiuous, find the first packet of the |
pbos-webrtc
2016/04/01 14:24:44
continuous
| |
131 // create a FrameObject. | 136 // frame and create an RtpFrameObject. |
132 if (sequence_buffer_[index].frame_end) { | 137 if (sequence_buffer_[index].frame_end) { |
133 int rindex = index; | 138 int rindex = index; |
pbos-webrtc
2016/04/01 14:24:44
can you rename rindex to something I can understan
philipel
2016/04/05 12:40:49
Renamed it to |start_index|.
| |
134 uint16_t start_seq_num = seq_num; | 139 uint16_t start_seq_num = seq_num; |
140 | |
135 while (!sequence_buffer_[rindex].frame_begin) { | 141 while (!sequence_buffer_[rindex].frame_begin) { |
142 sequence_buffer_[rindex].frame_created = true; | |
136 rindex = rindex > 0 ? rindex - 1 : size_ - 1; | 143 rindex = rindex > 0 ? rindex - 1 : size_ - 1; |
137 start_seq_num--; | 144 start_seq_num--; |
138 } | 145 } |
146 sequence_buffer_[rindex].frame_created = true; | |
139 | 147 |
140 std::unique_ptr<FrameObject> frame( | 148 std::unique_ptr<RtpFrameObject> frame( |
pbos-webrtc
2016/04/01 14:24:44
Follow-up maybe, but can these be reused so we don
philipel
2016/04/05 12:40:49
I think if we do that we add a lot of complexity f
| |
141 new RtpFrameObject(this, 1, start_seq_num, seq_num)); | 149 new RtpFrameObject(this, start_seq_num, seq_num)); |
142 frame_callback_->OnCompleteFrame(std::move(frame)); | 150 FindReferences(std::move(frame)); |
143 } | 151 } |
144 | 152 |
145 index = (index + 1) % size_; | 153 index = (index + 1) % size_; |
146 ++seq_num; | 154 ++seq_num; |
147 } | 155 } |
148 } | 156 } |
149 | 157 |
150 void PacketBuffer::ReturnFrame(RtpFrameObject* frame) { | 158 void PacketBuffer::ReturnFrame(RtpFrameObject* frame) { |
151 rtc::CritScope lock(&crit_); | 159 rtc::CritScope lock(&crit_); |
152 int index = frame->first_packet() % size_; | 160 int index = frame->first_packet() % size_; |
153 int end = (frame->last_packet() + 1) % size_; | 161 int end = (frame->last_packet() + 1) % size_; |
154 uint16_t seq_num = frame->first_packet(); | 162 uint16_t seq_num = frame->first_packet(); |
155 while (index != end) { | 163 while (index != end) { |
156 if (sequence_buffer_[index].seq_num == seq_num) { | 164 if (sequence_buffer_[index].seq_num == seq_num) |
157 sequence_buffer_[index].used = false; | 165 sequence_buffer_[index].used = false; |
158 sequence_buffer_[index].continuous = false; | 166 |
159 } | |
160 index = (index + 1) % size_; | 167 index = (index + 1) % size_; |
161 ++seq_num; | 168 ++seq_num; |
162 } | 169 } |
163 | 170 |
164 index = first_seq_num_ % size_; | 171 index = first_seq_num_ % size_; |
165 while (AheadOf<uint16_t>(last_seq_num_, first_seq_num_) && | 172 while (AheadOf<uint16_t>(last_seq_num_, first_seq_num_) && |
166 !sequence_buffer_[index].used) { | 173 !sequence_buffer_[index].used) { |
167 ++first_seq_num_; | 174 ++first_seq_num_; |
168 index = (index + 1) % size_; | 175 index = (index + 1) % size_; |
169 } | 176 } |
(...skipping 15 matching lines...) Expand all Loading... | |
185 const uint8_t* source = data_buffer_[index].dataPtr; | 192 const uint8_t* source = data_buffer_[index].dataPtr; |
186 size_t length = data_buffer_[index].sizeBytes; | 193 size_t length = data_buffer_[index].sizeBytes; |
187 memcpy(destination, source, length); | 194 memcpy(destination, source, length); |
188 destination += length; | 195 destination += length; |
189 index = (index + 1) % size_; | 196 index = (index + 1) % size_; |
190 ++seq_num; | 197 ++seq_num; |
191 } | 198 } |
192 return true; | 199 return true; |
193 } | 200 } |
194 | 201 |
202 void PacketBuffer::FindReferences(std::unique_ptr<RtpFrameObject> frame) { | |
203 int start_index = frame->first_packet() % size_; | |
pbos-webrtc
2016/04/01 14:24:44
size_t
philipel
2016/04/05 12:40:49
Done.
| |
204 VideoCodecType codec_type = data_buffer_[start_index].codec; | |
205 | |
206 if (codec_type == kVideoCodecVP8) { | |
207 FindReferencesVp8(std::move(frame)); | |
208 } else if (codec_type == kVideoCodecVP9) { | |
209 // TODO(philipel): FindReferencesVp9(std::move(frame)); | |
210 } else { | |
211 FindReferencesGeneric(std::move(frame)); | |
212 } | |
213 } | |
214 | |
215 void PacketBuffer::RetryStashedFrames() { | |
216 int num_stashed_frames = stashed_frames_.size(); | |
pbos-webrtc
2016/04/01 14:24:44
size_t for indexes and sizes
philipel
2016/04/05 12:40:49
Done.
| |
217 | |
218 for (int f = 0; f < num_stashed_frames && !stashed_frames_.empty(); ++f) { | |
pbos-webrtc
2016/04/01 14:24:44
size_t
pbos-webrtc
2016/04/01 14:24:44
Comment on why this is not the same as
while(!st
philipel
2016/04/05 12:40:49
Done.
philipel
2016/04/05 12:40:49
Done.
| |
219 // Pop ever frame from the queue, and if the references could still not | |
220 // be determined then they will be put in the queue again. | |
221 std::unique_ptr<RtpFrameObject> frame = std::move(stashed_frames_.front()); | |
222 stashed_frames_.pop(); | |
223 FindReferences(std::move(frame)); | |
224 } | |
225 } | |
226 | |
227 void PacketBuffer::FindReferencesGeneric( | |
228 std::unique_ptr<RtpFrameObject> frame) { | |
229 int index = frame->first_packet() % size_; | |
pbos-webrtc
2016/04/01 14:24:44
size_t
philipel
2016/04/05 12:40:49
Done.
| |
230 const VCMPacket& packet = data_buffer_[index]; | |
231 | |
232 if (packet.frameType == kVideoFrameKey) { | |
233 // Clean up keyframes if we have to many or if they are to old. | |
234 if (!last_seq_num_for_kf_.empty()) { | |
235 if (last_seq_num_for_kf_.size() > 5 || | |
pbos-webrtc
2016/04/01 14:24:44
s/5/kSomeConstantName
philipel
2016/04/05 12:40:49
Done.
| |
236 (MinDiff<uint16_t>(last_seq_num_for_kf_.begin()->second, | |
237 frame->last_packet()) > 10000 && | |
238 AheadOf<uint16_t>(last_seq_num_for_kf_.begin()->second, | |
239 frame->last_packet()))) { | |
240 last_seq_num_for_kf_.erase(last_seq_num_for_kf_.begin()->second); | |
241 } | |
242 } | |
243 | |
244 last_seq_num_for_kf_[frame->last_packet()] = frame->last_packet(); | |
245 } | |
246 | |
247 // Find the last sequence number of the last frame for the keyframe | |
248 // that this frame indirectly references. | |
249 auto seq_num_it = last_seq_num_for_kf_.upper_bound(frame->last_packet()); | |
250 seq_num_it--; | |
251 | |
252 // Make sure the packet sequence numbers are continuous, otherwise stash | |
253 // this frame. | |
254 if (packet.frameType == kVideoFrameDelta) { | |
255 if (seq_num_it->second != | |
256 static_cast<uint16_t>(frame->first_packet() - 1)) { | |
257 stashed_frames_.emplace(std::move(frame)); | |
258 return; | |
259 } | |
260 } | |
261 | |
262 RTC_DCHECK(AheadOrAt(frame->last_packet(), seq_num_it->first)); | |
263 | |
264 frame->picture_id = frame->last_packet(); | |
265 frame->num_references = packet.frameType == kVideoFrameDelta; | |
266 frame->references[0] = seq_num_it->second; | |
267 seq_num_it->second = frame->last_packet(); | |
268 | |
269 frame_callback_->OnCompleteFrame(std::move(frame)); | |
270 RetryStashedFrames(); | |
271 } | |
272 | |
273 void PacketBuffer::FindReferencesVp8(std::unique_ptr<RtpFrameObject> frame) { | |
274 int index = frame->first_packet() % size_; | |
pbos-webrtc
2016/04/01 14:24:44
size_t
philipel
2016/04/05 12:40:49
Done.
| |
275 const VCMPacket& packet = data_buffer_[index]; | |
276 const RTPVideoHeaderVP8& codec_header = | |
277 packet.codecSpecificHeader.codecHeader.VP8; | |
278 | |
279 if (codec_header.pictureId == kNoPictureId || | |
280 codec_header.temporalIdx == kNoTemporalIdx || | |
281 codec_header.tl0PicIdx == kNoTl0PicIdx) { | |
282 FindReferencesGeneric(std::move(frame)); | |
283 return; | |
284 } | |
285 | |
286 frame->picture_id = codec_header.pictureId % kPicIdLength; | |
287 | |
288 if (last_picture_id_ == -1) | |
289 last_picture_id_ = frame->picture_id; | |
290 | |
291 // Find if there has been a gap in fully received frames and save the picture | |
292 // id of those frames in |not_yet_received_frames_|. | |
293 if (AheadOf<uint8_t, kPicIdLength>(frame->picture_id, last_picture_id_)) { | |
294 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); | |
295 while (last_picture_id_ != frame->picture_id) { | |
296 not_yet_received_frames_.insert(last_picture_id_); | |
297 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); | |
298 } | |
299 } | |
300 | |
301 if (packet.frameType == kVideoFrameKey) { | |
302 frame->num_references = 0; | |
pbos-webrtc
2016/04/01 14:24:44
Shouldn't this line be true for every (generic) fr
philipel
2016/04/05 12:40:49
No, generic frames can have 0 or 1 reference.
| |
303 layer_info_[codec_header.tl0PicIdx].fill(-1); | |
304 CompletedFrameVp8(std::move(frame)); | |
305 return; | |
306 } | |
307 | |
308 auto layer_info_it = layer_info_.find(codec_header.temporalIdx == 0 | |
309 ? codec_header.tl0PicIdx - 1 | |
310 : codec_header.tl0PicIdx); | |
311 | |
312 // If we don't have the base layer frame yet, stash this frame. | |
313 if (layer_info_it == layer_info_.end()) { | |
314 stashed_frames_.emplace(std::move(frame)); | |
315 return; | |
316 } | |
317 | |
318 // A non keyframe base layer frame has been received, copy the layer info | |
319 // from the previous base layer frame and set a reference to the previous | |
320 // base layer frame. | |
321 if (codec_header.temporalIdx == 0) { | |
pbos-webrtc
2016/04/01 14:24:44
Should parts of this be split out to non-VP8 code
philipel
2016/04/05 12:40:49
VP9 wont need this functionality at all.
| |
322 layer_info_it = | |
323 layer_info_ | |
324 .insert(make_pair(codec_header.tl0PicIdx, layer_info_it->second)) | |
325 .first; | |
326 frame->num_references = 1; | |
327 frame->references[0] = layer_info_it->second[0]; | |
328 CompletedFrameVp8(std::move(frame)); | |
329 return; | |
330 } | |
331 | |
332 // Layer sync frame, this frame only references its base layer frame. | |
333 if (codec_header.layerSync) { | |
334 frame->num_references = 1; | |
335 frame->references[0] = layer_info_it->second[0]; | |
336 | |
337 CompletedFrameVp8(std::move(frame)); | |
338 return; | |
339 } | |
340 | |
341 // Find all references for this frame. | |
342 frame->num_references = 0; | |
343 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) { | |
344 ++frame->num_references; | |
345 frame->references[layer] = layer_info_it->second[layer]; | |
346 | |
347 // If we have not yet received a frame between this frame and the referenced | |
348 // frame then we have to wait for that frame to be completed first. | |
349 auto not_received_frame_it = | |
350 not_yet_received_frames_.upper_bound(frame->references[layer]); | |
351 if (not_received_frame_it != not_yet_received_frames_.end() && | |
352 AheadOf<uint8_t, kPicIdLength>(frame->picture_id, | |
353 *not_received_frame_it)) { | |
354 stashed_frames_.emplace(std::move(frame)); | |
355 return; | |
356 } | |
357 } | |
358 | |
359 CompletedFrameVp8(std::move(frame)); | |
360 } | |
361 | |
362 void PacketBuffer::CompletedFrameVp8(std::unique_ptr<RtpFrameObject> frame) { | |
363 int index = frame->first_packet() % size_; | |
pbos-webrtc
2016/04/01 14:24:44
size_t
philipel
2016/04/05 12:40:49
Done.
| |
364 const VCMPacket& packet = data_buffer_[index]; | |
365 const RTPVideoHeaderVP8& codec_header = | |
366 packet.codecSpecificHeader.codecHeader.VP8; | |
367 | |
368 uint8_t tl0_pic_idx = codec_header.tl0PicIdx; | |
369 uint8_t temporal_index = codec_header.temporalIdx; | |
370 auto layer_info_it = layer_info_.find(tl0_pic_idx); | |
371 | |
372 // Update this layer info and newer. | |
373 while (layer_info_it != layer_info_.end()) { | |
374 if (layer_info_it->second[temporal_index] != -1 && | |
375 AheadOf<uint16_t, kPicIdLength>(layer_info_it->second[temporal_index], | |
376 frame->picture_id)) { | |
377 // The frame was not newer, then no subsequent layer info have to be | |
378 // update. | |
379 break; | |
380 } | |
381 | |
382 layer_info_it->second[codec_header.temporalIdx] = frame->picture_id; | |
383 ++tl0_pic_idx; | |
384 layer_info_it = layer_info_.find(tl0_pic_idx); | |
385 } | |
386 not_yet_received_frames_.erase(frame->picture_id); | |
387 | |
388 for (int r = 0; r < frame->num_references; ++r) { | |
389 frame->references[r] = UnwrapPictureId(frame->references[r]); | |
390 } | |
391 frame->picture_id = UnwrapPictureId(frame->picture_id); | |
392 | |
393 frame_callback_->OnCompleteFrame(std::move(frame)); | |
394 RetryStashedFrames(); | |
395 } | |
396 | |
397 uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) { | |
398 if (last_unwrap_ == -1) | |
399 last_unwrap_ = picture_id; | |
400 | |
401 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength; | |
402 uint16_t diff = MinDiff<uint8_t, kPicIdLength>(unwrap_truncated, picture_id); | |
403 | |
404 if (AheadOf<uint8_t, kPicIdLength>(picture_id, unwrap_truncated)) | |
405 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); | |
406 else | |
407 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); | |
408 | |
409 return last_unwrap_; | |
410 } | |
411 | |
195 void PacketBuffer::Flush() { | 412 void PacketBuffer::Flush() { |
196 rtc::CritScope lock(&crit_); | 413 rtc::CritScope lock(&crit_); |
197 for (size_t i = 0; i < size_; ++i) { | 414 for (size_t i = 0; i < size_; ++i) |
198 sequence_buffer_[i].used = false; | 415 sequence_buffer_[i].used = false; |
199 sequence_buffer_[i].continuous = false; | 416 |
200 } | 417 last_seq_num_for_kf_.clear(); |
418 while (!stashed_frames_.empty()) | |
419 stashed_frames_.pop(); | |
420 not_yet_received_frames_.clear(); | |
201 } | 421 } |
202 | 422 |
203 } // namespace video_coding | 423 } // namespace video_coding |
204 } // namespace webrtc | 424 } // namespace webrtc |
OLD | NEW |