blob: d7b4f449e7be065f1bb2872678f0863f9fe0de56 [file] [log] [blame]
philipelc707ab72016-04-01 02:01:54 -07001/*
2 * Copyright (c) 2016 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 "webrtc/modules/video_coding/packet_buffer.h"
12
13#include <algorithm>
14#include <limits>
15
16#include "webrtc/base/checks.h"
17#include "webrtc/modules/video_coding/frame_object.h"
philipelc707ab72016-04-01 02:01:54 -070018
19namespace webrtc {
20namespace video_coding {
21
22PacketBuffer::PacketBuffer(size_t start_buffer_size,
23 size_t max_buffer_size,
24 OnCompleteFrameCallback* frame_callback)
25 : size_(start_buffer_size),
26 max_size_(max_buffer_size),
philipelc707ab72016-04-01 02:01:54 -070027 first_seq_num_(0),
philipelf4139332016-04-20 10:26:34 +020028 last_seq_num_(0),
29 first_packet_received_(false),
philipelc707ab72016-04-01 02:01:54 -070030 data_buffer_(start_buffer_size),
31 sequence_buffer_(start_buffer_size),
philipelf4139332016-04-20 10:26:34 +020032 frame_callback_(frame_callback),
33 last_picture_id_(-1),
34 last_unwrap_(-1) {
philipelc707ab72016-04-01 02:01:54 -070035 RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
36 // Buffer size must always be a power of 2.
37 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
38 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0);
39}
40
41bool PacketBuffer::InsertPacket(const VCMPacket& packet) {
42 rtc::CritScope lock(&crit_);
43 uint16_t seq_num = packet.seqNum;
philipelf4139332016-04-20 10:26:34 +020044 size_t index = seq_num % size_;
philipelc707ab72016-04-01 02:01:54 -070045
philipelf4139332016-04-20 10:26:34 +020046 if (!first_packet_received_) {
philipelc707ab72016-04-01 02:01:54 -070047 first_seq_num_ = seq_num - 1;
48 last_seq_num_ = seq_num;
philipelf4139332016-04-20 10:26:34 +020049 first_packet_received_ = true;
philipelc707ab72016-04-01 02:01:54 -070050 }
51
52 if (sequence_buffer_[index].used) {
53 // Duplicate packet, do nothing.
54 if (data_buffer_[index].seqNum == packet.seqNum)
55 return true;
56
57 // The packet buffer is full, try to expand the buffer.
58 while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {
59 }
60 index = seq_num % size_;
61
62 // Packet buffer is still full.
63 if (sequence_buffer_[index].used)
64 return false;
65 }
66
67 if (AheadOf(seq_num, last_seq_num_))
68 last_seq_num_ = seq_num;
69
70 sequence_buffer_[index].frame_begin = packet.isFirstPacket;
71 sequence_buffer_[index].frame_end = packet.markerBit;
72 sequence_buffer_[index].seq_num = packet.seqNum;
73 sequence_buffer_[index].continuous = false;
philipelf4139332016-04-20 10:26:34 +020074 sequence_buffer_[index].frame_created = false;
philipelc707ab72016-04-01 02:01:54 -070075 sequence_buffer_[index].used = true;
76 data_buffer_[index] = packet;
77
philipelf4139332016-04-20 10:26:34 +020078 FindFrames(seq_num);
philipelc707ab72016-04-01 02:01:54 -070079 return true;
80}
81
82void PacketBuffer::ClearTo(uint16_t seq_num) {
83 rtc::CritScope lock(&crit_);
philipelf4139332016-04-20 10:26:34 +020084 size_t index = first_seq_num_ % size_;
philipelc707ab72016-04-01 02:01:54 -070085 while (AheadOf<uint16_t>(seq_num, first_seq_num_ + 1)) {
86 index = (index + 1) % size_;
87 first_seq_num_ = Add<1 << 16>(first_seq_num_, 1);
88 sequence_buffer_[index].used = false;
89 }
90}
91
92bool PacketBuffer::ExpandBufferSize() {
93 if (size_ == max_size_)
94 return false;
95
96 size_t new_size = std::min(max_size_, 2 * size_);
97 std::vector<VCMPacket> new_data_buffer(new_size);
98 std::vector<ContinuityInfo> new_sequence_buffer(new_size);
99 for (size_t i = 0; i < size_; ++i) {
100 if (sequence_buffer_[i].used) {
philipelf4139332016-04-20 10:26:34 +0200101 size_t index = sequence_buffer_[i].seq_num % new_size;
philipelc707ab72016-04-01 02:01:54 -0700102 new_sequence_buffer[index] = sequence_buffer_[i];
103 new_data_buffer[index] = data_buffer_[i];
104 }
105 }
106 size_ = new_size;
107 sequence_buffer_ = std::move(new_sequence_buffer);
108 data_buffer_ = std::move(new_data_buffer);
109 return true;
110}
111
112bool PacketBuffer::IsContinuous(uint16_t seq_num) const {
philipelf4139332016-04-20 10:26:34 +0200113 size_t index = seq_num % size_;
philipelc707ab72016-04-01 02:01:54 -0700114 int prev_index = index > 0 ? index - 1 : size_ - 1;
philipelf4139332016-04-20 10:26:34 +0200115
philipelc707ab72016-04-01 02:01:54 -0700116 if (!sequence_buffer_[index].used)
117 return false;
philipelf4139332016-04-20 10:26:34 +0200118 if (sequence_buffer_[index].frame_created)
119 return false;
philipelc707ab72016-04-01 02:01:54 -0700120 if (sequence_buffer_[index].frame_begin)
121 return true;
122 if (!sequence_buffer_[prev_index].used)
123 return false;
philipelf4139332016-04-20 10:26:34 +0200124 if (sequence_buffer_[prev_index].seq_num !=
125 static_cast<uint16_t>(seq_num - 1))
126 return false;
philipelc707ab72016-04-01 02:01:54 -0700127 if (sequence_buffer_[prev_index].continuous)
128 return true;
129
130 return false;
131}
132
philipelf4139332016-04-20 10:26:34 +0200133void PacketBuffer::FindFrames(uint16_t seq_num) {
134 size_t index = seq_num % size_;
philipelc707ab72016-04-01 02:01:54 -0700135 while (IsContinuous(seq_num)) {
136 sequence_buffer_[index].continuous = true;
137
philipelf4139332016-04-20 10:26:34 +0200138 // If all packets of the frame is continuous, find the first packet of the
139 // frame and create an RtpFrameObject.
philipelc707ab72016-04-01 02:01:54 -0700140 if (sequence_buffer_[index].frame_end) {
philipelf4139332016-04-20 10:26:34 +0200141 int start_index = index;
philipelc707ab72016-04-01 02:01:54 -0700142 uint16_t start_seq_num = seq_num;
philipelf4139332016-04-20 10:26:34 +0200143
144 while (!sequence_buffer_[start_index].frame_begin) {
145 sequence_buffer_[start_index].frame_created = true;
146 start_index = start_index > 0 ? start_index - 1 : size_ - 1;
philipelc707ab72016-04-01 02:01:54 -0700147 start_seq_num--;
148 }
philipelf4139332016-04-20 10:26:34 +0200149 sequence_buffer_[start_index].frame_created = true;
philipelc707ab72016-04-01 02:01:54 -0700150
philipelf4139332016-04-20 10:26:34 +0200151 std::unique_ptr<RtpFrameObject> frame(
152 new RtpFrameObject(this, start_seq_num, seq_num));
153 ManageFrame(std::move(frame));
philipelc707ab72016-04-01 02:01:54 -0700154 }
155
156 index = (index + 1) % size_;
157 ++seq_num;
158 }
159}
160
161void PacketBuffer::ReturnFrame(RtpFrameObject* frame) {
162 rtc::CritScope lock(&crit_);
philipelf4139332016-04-20 10:26:34 +0200163 size_t index = frame->first_seq_num() % size_;
164 size_t end = (frame->last_seq_num() + 1) % size_;
165 uint16_t seq_num = frame->first_seq_num();
philipelc707ab72016-04-01 02:01:54 -0700166 while (index != end) {
philipelf4139332016-04-20 10:26:34 +0200167 if (sequence_buffer_[index].seq_num == seq_num)
philipelc707ab72016-04-01 02:01:54 -0700168 sequence_buffer_[index].used = false;
philipelf4139332016-04-20 10:26:34 +0200169
philipelc707ab72016-04-01 02:01:54 -0700170 index = (index + 1) % size_;
171 ++seq_num;
172 }
173
174 index = first_seq_num_ % size_;
175 while (AheadOf<uint16_t>(last_seq_num_, first_seq_num_) &&
176 !sequence_buffer_[index].used) {
177 ++first_seq_num_;
178 index = (index + 1) % size_;
179 }
180}
181
182bool PacketBuffer::GetBitstream(const RtpFrameObject& frame,
183 uint8_t* destination) {
184 rtc::CritScope lock(&crit_);
185
philipelf4139332016-04-20 10:26:34 +0200186 size_t index = frame.first_seq_num() % size_;
187 size_t end = (frame.last_seq_num() + 1) % size_;
188 uint16_t seq_num = frame.first_seq_num();
philipelc707ab72016-04-01 02:01:54 -0700189 while (index != end) {
190 if (!sequence_buffer_[index].used ||
191 sequence_buffer_[index].seq_num != seq_num) {
192 return false;
193 }
194
195 const uint8_t* source = data_buffer_[index].dataPtr;
196 size_t length = data_buffer_[index].sizeBytes;
197 memcpy(destination, source, length);
198 destination += length;
199 index = (index + 1) % size_;
200 ++seq_num;
201 }
202 return true;
203}
204
philipelf4139332016-04-20 10:26:34 +0200205void PacketBuffer::ManageFrame(std::unique_ptr<RtpFrameObject> frame) {
206 size_t start_index = frame->first_seq_num() % size_;
207 VideoCodecType codec_type = data_buffer_[start_index].codec;
208
209 switch (codec_type) {
Peter Boström2ddf0932016-04-20 14:06:45 +0200210 case kVideoCodecULPFEC:
211 case kVideoCodecRED:
212 case kVideoCodecUnknown:
philipelf4139332016-04-20 10:26:34 +0200213 RTC_NOTREACHED();
Peter Boström2ddf0932016-04-20 14:06:45 +0200214 break;
215 case kVideoCodecVP8:
philipelf4139332016-04-20 10:26:34 +0200216 ManageFrameVp8(std::move(frame));
217 break;
Peter Boström2ddf0932016-04-20 14:06:45 +0200218 case kVideoCodecVP9:
philipelf4139332016-04-20 10:26:34 +0200219 // TODO(philipel): ManageFrameVp9(std::move(frame));
220 break;
Peter Boström2ddf0932016-04-20 14:06:45 +0200221 case kVideoCodecH264:
222 case kVideoCodecI420:
223 case kVideoCodecGeneric:
philipelf4139332016-04-20 10:26:34 +0200224 ManageFrameGeneric(std::move(frame));
Peter Boström2ddf0932016-04-20 14:06:45 +0200225 break;
philipelf4139332016-04-20 10:26:34 +0200226 }
227}
228
229void PacketBuffer::RetryStashedFrames() {
230 size_t num_stashed_frames = stashed_frames_.size();
231
232 // Clean up stashed frames if there are too many.
233 while (stashed_frames_.size() > kMaxStashedFrames)
234 stashed_frames_.pop();
235
236 // Since frames are stashed if there is not enough data to determine their
237 // frame references we should at most check |stashed_frames_.size()| in
238 // order to not pop and push frames in and endless loop.
239 for (size_t i = 0; i < num_stashed_frames && !stashed_frames_.empty(); ++i) {
240 std::unique_ptr<RtpFrameObject> frame = std::move(stashed_frames_.front());
241 stashed_frames_.pop();
242 ManageFrame(std::move(frame));
243 }
244}
245
246void PacketBuffer::ManageFrameGeneric(
247 std::unique_ptr<RtpFrameObject> frame) {
248 size_t index = frame->first_seq_num() % size_;
249 const VCMPacket& packet = data_buffer_[index];
250
251 if (packet.frameType == kVideoFrameKey)
252 last_seq_num_gop_[frame->last_seq_num()] = frame->last_seq_num();
253
254 // We have received a frame but not yet a keyframe, stash this frame.
255 if (last_seq_num_gop_.empty()) {
256 stashed_frames_.emplace(std::move(frame));
257 return;
258 }
259
260 // Clean up info for old keyframes but make sure to keep info
261 // for the last keyframe.
262 auto clean_to = last_seq_num_gop_.lower_bound(frame->last_seq_num() - 100);
263 if (clean_to != last_seq_num_gop_.end())
264 last_seq_num_gop_.erase(last_seq_num_gop_.begin(), clean_to);
265
266 // Find the last sequence number of the last frame for the keyframe
267 // that this frame indirectly references.
268 auto seq_num_it = last_seq_num_gop_.upper_bound(frame->last_seq_num());
269 seq_num_it--;
270
271 // Make sure the packet sequence numbers are continuous, otherwise stash
272 // this frame.
273 if (packet.frameType == kVideoFrameDelta) {
274 if (seq_num_it->second !=
275 static_cast<uint16_t>(frame->first_seq_num() - 1)) {
276 stashed_frames_.emplace(std::move(frame));
277 return;
278 }
279 }
280
281 RTC_DCHECK(AheadOrAt(frame->last_seq_num(), seq_num_it->first));
282
283 // Since keyframes can cause reordering of the frames delivered from
284 // FindFrames() we can't simply assign the picture id according to some
285 // incrementing counter.
286 frame->picture_id = frame->last_seq_num();
287 frame->num_references = packet.frameType == kVideoFrameDelta;
288 frame->references[0] = seq_num_it->second;
289 seq_num_it->second = frame->picture_id;
290
291 last_picture_id_ = frame->picture_id;
292 frame_callback_->OnCompleteFrame(std::move(frame));
293 RetryStashedFrames();
294}
295
296void PacketBuffer::ManageFrameVp8(std::unique_ptr<RtpFrameObject> frame) {
297 size_t index = frame->first_seq_num() % size_;
298 const VCMPacket& packet = data_buffer_[index];
299 const RTPVideoHeaderVP8& codec_header =
300 packet.codecSpecificHeader.codecHeader.VP8;
301
302 if (codec_header.pictureId == kNoPictureId ||
303 codec_header.temporalIdx == kNoTemporalIdx ||
304 codec_header.tl0PicIdx == kNoTl0PicIdx) {
305 ManageFrameGeneric(std::move(frame));
306 return;
307 }
308
309 frame->picture_id = codec_header.pictureId % kPicIdLength;
310
311 if (last_unwrap_ == -1)
312 last_unwrap_ = codec_header.pictureId;
313
314 if (last_picture_id_ == -1)
315 last_picture_id_ = frame->picture_id;
316
317 // Find if there has been a gap in fully received frames and save the picture
318 // id of those frames in |not_yet_received_frames_|.
319 if (AheadOf<uint8_t, kPicIdLength>(frame->picture_id, last_picture_id_)) {
320 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
321 while (last_picture_id_ != frame->picture_id) {
322 not_yet_received_frames_.insert(last_picture_id_);
323 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
324 }
325 }
326
327 // Clean up info for base layers that are too old.
328 uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo;
329 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx);
330 layer_info_.erase(layer_info_.begin(), clean_layer_info_to);
331
332 // Clean up info about not yet received frames that are too old.
333 uint16_t old_picture_id = Subtract<kPicIdLength>(frame->picture_id,
334 kMaxNotYetReceivedFrames);
335 auto clean_frames_to = not_yet_received_frames_.lower_bound(old_picture_id);
336 not_yet_received_frames_.erase(not_yet_received_frames_.begin(),
337 clean_frames_to);
338
339 if (packet.frameType == kVideoFrameKey) {
340 frame->num_references = 0;
341 layer_info_[codec_header.tl0PicIdx].fill(-1);
342 CompletedFrameVp8(std::move(frame));
343 return;
344 }
345
346 auto layer_info_it = layer_info_.find(codec_header.temporalIdx == 0
347 ? codec_header.tl0PicIdx - 1
348 : codec_header.tl0PicIdx);
349
350 // If we don't have the base layer frame yet, stash this frame.
351 if (layer_info_it == layer_info_.end()) {
352 stashed_frames_.emplace(std::move(frame));
353 return;
354 }
355
356 // A non keyframe base layer frame has been received, copy the layer info
357 // from the previous base layer frame and set a reference to the previous
358 // base layer frame.
359 if (codec_header.temporalIdx == 0) {
360 layer_info_it =
361 layer_info_
362 .insert(make_pair(codec_header.tl0PicIdx, layer_info_it->second))
363 .first;
364 frame->num_references = 1;
365 frame->references[0] = layer_info_it->second[0];
366 CompletedFrameVp8(std::move(frame));
367 return;
368 }
369
370 // Layer sync frame, this frame only references its base layer frame.
371 if (codec_header.layerSync) {
372 frame->num_references = 1;
373 frame->references[0] = layer_info_it->second[0];
374
375 CompletedFrameVp8(std::move(frame));
376 return;
377 }
378
379 // Find all references for this frame.
380 frame->num_references = 0;
381 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) {
382 RTC_DCHECK_NE(-1, layer_info_it->second[layer]);
383
384 // If we have not yet received a frame between this frame and the referenced
385 // frame then we have to wait for that frame to be completed first.
386 auto not_received_frame_it =
387 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]);
388 if (not_received_frame_it != not_yet_received_frames_.end() &&
389 AheadOf<uint8_t, kPicIdLength>(frame->picture_id,
390 *not_received_frame_it)) {
391 stashed_frames_.emplace(std::move(frame));
392 return;
393 }
394
395 ++frame->num_references;
396 frame->references[layer] = layer_info_it->second[layer];
397 }
398
399 CompletedFrameVp8(std::move(frame));
400}
401
402void PacketBuffer::CompletedFrameVp8(std::unique_ptr<RtpFrameObject> frame) {
403 size_t index = frame->first_seq_num() % size_;
404 const VCMPacket& packet = data_buffer_[index];
405 const RTPVideoHeaderVP8& codec_header =
406 packet.codecSpecificHeader.codecHeader.VP8;
407
408 uint8_t tl0_pic_idx = codec_header.tl0PicIdx;
409 uint8_t temporal_index = codec_header.temporalIdx;
410 auto layer_info_it = layer_info_.find(tl0_pic_idx);
411
412 // Update this layer info and newer.
413 while (layer_info_it != layer_info_.end()) {
414 if (layer_info_it->second[temporal_index] != -1 &&
415 AheadOf<uint16_t, kPicIdLength>(layer_info_it->second[temporal_index],
416 frame->picture_id)) {
417 // The frame was not newer, then no subsequent layer info have to be
418 // update.
419 break;
420 }
421
422 layer_info_it->second[codec_header.temporalIdx] = frame->picture_id;
423 ++tl0_pic_idx;
424 layer_info_it = layer_info_.find(tl0_pic_idx);
425 }
426 not_yet_received_frames_.erase(frame->picture_id);
427
428 for (size_t r = 0; r < frame->num_references; ++r)
429 frame->references[r] = UnwrapPictureId(frame->references[r]);
430 frame->picture_id = UnwrapPictureId(frame->picture_id);
431
432 frame_callback_->OnCompleteFrame(std::move(frame));
433 RetryStashedFrames();
434}
435
436uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) {
437 if (last_unwrap_ == -1)
438 last_unwrap_ = picture_id;
439
440 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength;
441 uint16_t diff = MinDiff<uint8_t, kPicIdLength>(unwrap_truncated, picture_id);
442
443 if (AheadOf<uint8_t, kPicIdLength>(picture_id, unwrap_truncated))
444 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff);
445 else
446 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff);
447
448 return last_unwrap_;
449}
450
philipelc707ab72016-04-01 02:01:54 -0700451void PacketBuffer::Flush() {
452 rtc::CritScope lock(&crit_);
philipelf4139332016-04-20 10:26:34 +0200453 for (size_t i = 0; i < size_; ++i)
philipelc707ab72016-04-01 02:01:54 -0700454 sequence_buffer_[i].used = false;
philipelf4139332016-04-20 10:26:34 +0200455
456 last_seq_num_gop_.clear();
457 while (!stashed_frames_.empty())
458 stashed_frames_.pop();
459 not_yet_received_frames_.clear();
460
461 first_packet_received_ = false;
philipelc707ab72016-04-01 02:01:54 -0700462}
463
464} // namespace video_coding
465} // namespace webrtc