blob: 8cbfc0c66f417c2cd6063f12ef41cd5d22a909fd [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) {
210 case kVideoCodecULPFEC :
211 case kVideoCodecRED :
212 case kVideoCodecUnknown : {
213 RTC_NOTREACHED();
214 }
215 case kVideoCodecVP8 : {
216 ManageFrameVp8(std::move(frame));
217 break;
218 }
219 case kVideoCodecVP9 : {
220 // TODO(philipel): ManageFrameVp9(std::move(frame));
221 break;
222 }
223 case kVideoCodecH264 :
224 case kVideoCodecI420 :
225 case kVideoCodecGeneric :
226 default : {
227 ManageFrameGeneric(std::move(frame));
228 }
229 }
230}
231
232void PacketBuffer::RetryStashedFrames() {
233 size_t num_stashed_frames = stashed_frames_.size();
234
235 // Clean up stashed frames if there are too many.
236 while (stashed_frames_.size() > kMaxStashedFrames)
237 stashed_frames_.pop();
238
239 // Since frames are stashed if there is not enough data to determine their
240 // frame references we should at most check |stashed_frames_.size()| in
241 // order to not pop and push frames in and endless loop.
242 for (size_t i = 0; i < num_stashed_frames && !stashed_frames_.empty(); ++i) {
243 std::unique_ptr<RtpFrameObject> frame = std::move(stashed_frames_.front());
244 stashed_frames_.pop();
245 ManageFrame(std::move(frame));
246 }
247}
248
249void PacketBuffer::ManageFrameGeneric(
250 std::unique_ptr<RtpFrameObject> frame) {
251 size_t index = frame->first_seq_num() % size_;
252 const VCMPacket& packet = data_buffer_[index];
253
254 if (packet.frameType == kVideoFrameKey)
255 last_seq_num_gop_[frame->last_seq_num()] = frame->last_seq_num();
256
257 // We have received a frame but not yet a keyframe, stash this frame.
258 if (last_seq_num_gop_.empty()) {
259 stashed_frames_.emplace(std::move(frame));
260 return;
261 }
262
263 // Clean up info for old keyframes but make sure to keep info
264 // for the last keyframe.
265 auto clean_to = last_seq_num_gop_.lower_bound(frame->last_seq_num() - 100);
266 if (clean_to != last_seq_num_gop_.end())
267 last_seq_num_gop_.erase(last_seq_num_gop_.begin(), clean_to);
268
269 // Find the last sequence number of the last frame for the keyframe
270 // that this frame indirectly references.
271 auto seq_num_it = last_seq_num_gop_.upper_bound(frame->last_seq_num());
272 seq_num_it--;
273
274 // Make sure the packet sequence numbers are continuous, otherwise stash
275 // this frame.
276 if (packet.frameType == kVideoFrameDelta) {
277 if (seq_num_it->second !=
278 static_cast<uint16_t>(frame->first_seq_num() - 1)) {
279 stashed_frames_.emplace(std::move(frame));
280 return;
281 }
282 }
283
284 RTC_DCHECK(AheadOrAt(frame->last_seq_num(), seq_num_it->first));
285
286 // Since keyframes can cause reordering of the frames delivered from
287 // FindFrames() we can't simply assign the picture id according to some
288 // incrementing counter.
289 frame->picture_id = frame->last_seq_num();
290 frame->num_references = packet.frameType == kVideoFrameDelta;
291 frame->references[0] = seq_num_it->second;
292 seq_num_it->second = frame->picture_id;
293
294 last_picture_id_ = frame->picture_id;
295 frame_callback_->OnCompleteFrame(std::move(frame));
296 RetryStashedFrames();
297}
298
299void PacketBuffer::ManageFrameVp8(std::unique_ptr<RtpFrameObject> frame) {
300 size_t index = frame->first_seq_num() % size_;
301 const VCMPacket& packet = data_buffer_[index];
302 const RTPVideoHeaderVP8& codec_header =
303 packet.codecSpecificHeader.codecHeader.VP8;
304
305 if (codec_header.pictureId == kNoPictureId ||
306 codec_header.temporalIdx == kNoTemporalIdx ||
307 codec_header.tl0PicIdx == kNoTl0PicIdx) {
308 ManageFrameGeneric(std::move(frame));
309 return;
310 }
311
312 frame->picture_id = codec_header.pictureId % kPicIdLength;
313
314 if (last_unwrap_ == -1)
315 last_unwrap_ = codec_header.pictureId;
316
317 if (last_picture_id_ == -1)
318 last_picture_id_ = frame->picture_id;
319
320 // Find if there has been a gap in fully received frames and save the picture
321 // id of those frames in |not_yet_received_frames_|.
322 if (AheadOf<uint8_t, kPicIdLength>(frame->picture_id, last_picture_id_)) {
323 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
324 while (last_picture_id_ != frame->picture_id) {
325 not_yet_received_frames_.insert(last_picture_id_);
326 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
327 }
328 }
329
330 // Clean up info for base layers that are too old.
331 uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo;
332 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx);
333 layer_info_.erase(layer_info_.begin(), clean_layer_info_to);
334
335 // Clean up info about not yet received frames that are too old.
336 uint16_t old_picture_id = Subtract<kPicIdLength>(frame->picture_id,
337 kMaxNotYetReceivedFrames);
338 auto clean_frames_to = not_yet_received_frames_.lower_bound(old_picture_id);
339 not_yet_received_frames_.erase(not_yet_received_frames_.begin(),
340 clean_frames_to);
341
342 if (packet.frameType == kVideoFrameKey) {
343 frame->num_references = 0;
344 layer_info_[codec_header.tl0PicIdx].fill(-1);
345 CompletedFrameVp8(std::move(frame));
346 return;
347 }
348
349 auto layer_info_it = layer_info_.find(codec_header.temporalIdx == 0
350 ? codec_header.tl0PicIdx - 1
351 : codec_header.tl0PicIdx);
352
353 // If we don't have the base layer frame yet, stash this frame.
354 if (layer_info_it == layer_info_.end()) {
355 stashed_frames_.emplace(std::move(frame));
356 return;
357 }
358
359 // A non keyframe base layer frame has been received, copy the layer info
360 // from the previous base layer frame and set a reference to the previous
361 // base layer frame.
362 if (codec_header.temporalIdx == 0) {
363 layer_info_it =
364 layer_info_
365 .insert(make_pair(codec_header.tl0PicIdx, layer_info_it->second))
366 .first;
367 frame->num_references = 1;
368 frame->references[0] = layer_info_it->second[0];
369 CompletedFrameVp8(std::move(frame));
370 return;
371 }
372
373 // Layer sync frame, this frame only references its base layer frame.
374 if (codec_header.layerSync) {
375 frame->num_references = 1;
376 frame->references[0] = layer_info_it->second[0];
377
378 CompletedFrameVp8(std::move(frame));
379 return;
380 }
381
382 // Find all references for this frame.
383 frame->num_references = 0;
384 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) {
385 RTC_DCHECK_NE(-1, layer_info_it->second[layer]);
386
387 // If we have not yet received a frame between this frame and the referenced
388 // frame then we have to wait for that frame to be completed first.
389 auto not_received_frame_it =
390 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]);
391 if (not_received_frame_it != not_yet_received_frames_.end() &&
392 AheadOf<uint8_t, kPicIdLength>(frame->picture_id,
393 *not_received_frame_it)) {
394 stashed_frames_.emplace(std::move(frame));
395 return;
396 }
397
398 ++frame->num_references;
399 frame->references[layer] = layer_info_it->second[layer];
400 }
401
402 CompletedFrameVp8(std::move(frame));
403}
404
405void PacketBuffer::CompletedFrameVp8(std::unique_ptr<RtpFrameObject> frame) {
406 size_t index = frame->first_seq_num() % size_;
407 const VCMPacket& packet = data_buffer_[index];
408 const RTPVideoHeaderVP8& codec_header =
409 packet.codecSpecificHeader.codecHeader.VP8;
410
411 uint8_t tl0_pic_idx = codec_header.tl0PicIdx;
412 uint8_t temporal_index = codec_header.temporalIdx;
413 auto layer_info_it = layer_info_.find(tl0_pic_idx);
414
415 // Update this layer info and newer.
416 while (layer_info_it != layer_info_.end()) {
417 if (layer_info_it->second[temporal_index] != -1 &&
418 AheadOf<uint16_t, kPicIdLength>(layer_info_it->second[temporal_index],
419 frame->picture_id)) {
420 // The frame was not newer, then no subsequent layer info have to be
421 // update.
422 break;
423 }
424
425 layer_info_it->second[codec_header.temporalIdx] = frame->picture_id;
426 ++tl0_pic_idx;
427 layer_info_it = layer_info_.find(tl0_pic_idx);
428 }
429 not_yet_received_frames_.erase(frame->picture_id);
430
431 for (size_t r = 0; r < frame->num_references; ++r)
432 frame->references[r] = UnwrapPictureId(frame->references[r]);
433 frame->picture_id = UnwrapPictureId(frame->picture_id);
434
435 frame_callback_->OnCompleteFrame(std::move(frame));
436 RetryStashedFrames();
437}
438
439uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) {
440 if (last_unwrap_ == -1)
441 last_unwrap_ = picture_id;
442
443 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength;
444 uint16_t diff = MinDiff<uint8_t, kPicIdLength>(unwrap_truncated, picture_id);
445
446 if (AheadOf<uint8_t, kPicIdLength>(picture_id, unwrap_truncated))
447 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff);
448 else
449 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff);
450
451 return last_unwrap_;
452}
453
philipelc707ab72016-04-01 02:01:54 -0700454void PacketBuffer::Flush() {
455 rtc::CritScope lock(&crit_);
philipelf4139332016-04-20 10:26:34 +0200456 for (size_t i = 0; i < size_; ++i)
philipelc707ab72016-04-01 02:01:54 -0700457 sequence_buffer_[i].used = false;
philipelf4139332016-04-20 10:26:34 +0200458
459 last_seq_num_gop_.clear();
460 while (!stashed_frames_.empty())
461 stashed_frames_.pop();
462 not_yet_received_frames_.clear();
463
464 first_packet_received_ = false;
philipelc707ab72016-04-01 02:01:54 -0700465}
466
467} // namespace video_coding
468} // namespace webrtc