Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(508)

Side by Side Diff: webrtc/modules/video_coding/packet_buffer.cc

Issue 1847193003: Convert Vp8 Rtp headers to frame references. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698