OLD | NEW |
(Empty) | |
| 1 /* |
| 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/mod_ops.h" |
| 17 #include "webrtc/base/checks.h" |
| 18 #include "webrtc/modules/video_coding/frame_object.h" |
| 19 |
| 20 namespace webrtc { |
| 21 namespace video_coding { |
| 22 |
| 23 PacketBuffer::PacketBuffer(size_t start_buffer_size, |
| 24 size_t max_buffer_size, |
| 25 OnCompleteFrameCallback* frame_callback) |
| 26 : size_(start_buffer_size), |
| 27 max_size_(max_buffer_size), |
| 28 clear_up_to_(0), |
| 29 initialized_(false), |
| 30 data_buffer_(start_buffer_size), |
| 31 sequence_buffer_(start_buffer_size), |
| 32 frame_callback_(frame_callback) { |
| 33 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); |
| 34 // Buffer size must always be a power of 2. |
| 35 RTC_DCHECK((start_buffer_size & start_buffer_size - 1) == 0); |
| 36 RTC_DCHECK((max_buffer_size & max_buffer_size - 1) == 0); |
| 37 } |
| 38 |
| 39 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { |
| 40 rtc::CritScope lock(&crit_); |
| 41 uint16_t seq_num = packet.seqNum; |
| 42 int index = seq_num % size_; |
| 43 |
| 44 if (!initialized_) { |
| 45 clear_up_to_ = seq_num; |
| 46 initialized_ = true; |
| 47 } |
| 48 |
| 49 if (sequence_buffer_[index].used) { |
| 50 // Duplicate packet, do nothing. |
| 51 if (data_buffer_[index].seqNum == packet.seqNum) |
| 52 return false; |
| 53 |
| 54 // The packet buffer is full, try to expand the buffer. |
| 55 while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {} |
| 56 index = seq_num % size_; |
| 57 // If still full, test if the old packet can be discarded (overwritten |
| 58 // later in the code), if not, return false. |
| 59 if (sequence_buffer_[index].used && |
| 60 AheadOrAt(sequence_buffer_[index].seq_num, clear_up_to_)) |
| 61 return false; |
| 62 } |
| 63 |
| 64 sequence_buffer_[index].frame_begin = packet.isFirstPacket; |
| 65 sequence_buffer_[index].frame_end = packet.markerBit; |
| 66 sequence_buffer_[index].seq_num = packet.seqNum; |
| 67 sequence_buffer_[index].continuous = false; |
| 68 sequence_buffer_[index].used = true; |
| 69 data_buffer_[index] = packet; |
| 70 |
| 71 FindCompleteFrames(seq_num); |
| 72 return true; |
| 73 } |
| 74 |
| 75 void PacketBuffer::ClearUpTo(uint16_t seq_num) { |
| 76 rtc::CritScope lock(&crit_); |
| 77 clear_up_to_ = seq_num; |
| 78 } |
| 79 |
| 80 bool PacketBuffer::ExpandBufferSize() { |
| 81 if (size_ == max_size_) { |
| 82 return false; |
| 83 } |
| 84 |
| 85 size_t new_size = std::min(max_size_, 2 * size_); |
| 86 std::vector<VCMPacket> new_data_buffer(new_size); |
| 87 std::vector<ContinuityInfo> new_sequence_buffer(new_size); |
| 88 for (size_t i = 0; i < size_; ++i) { |
| 89 if (sequence_buffer_[i].used) { |
| 90 int index = sequence_buffer_[i].seq_num % new_size; |
| 91 new_sequence_buffer[index] = sequence_buffer_[i]; |
| 92 new_data_buffer[index] = data_buffer_[i]; |
| 93 } |
| 94 } |
| 95 size_ = new_size; |
| 96 sequence_buffer_ = std::move(new_sequence_buffer); |
| 97 data_buffer_ = std::move(new_data_buffer); |
| 98 return true; |
| 99 } |
| 100 |
| 101 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { |
| 102 int index = seq_num % size_; |
| 103 int prev_index = index > 0 ? index - 1 : size_ - 1; |
| 104 if (!sequence_buffer_[index].used) |
| 105 return false; |
| 106 if (sequence_buffer_[index].frame_begin) |
| 107 return true; |
| 108 if (!sequence_buffer_[prev_index].used) |
| 109 return false; |
| 110 if (sequence_buffer_[prev_index].continuous) |
| 111 return true; |
| 112 |
| 113 return false; |
| 114 } |
| 115 |
| 116 void PacketBuffer::FindCompleteFrames(uint16_t seq_num) { |
| 117 int index = seq_num % size_; |
| 118 while (IsContinuous(seq_num)) { |
| 119 sequence_buffer_[index].continuous = true; |
| 120 |
| 121 // If the frame is complete, find the first packet of the frame and |
| 122 // create a FrameObject. |
| 123 if (sequence_buffer_[index].frame_end) { |
| 124 int rindex = index; |
| 125 uint16_t start_seq_num = seq_num; |
| 126 while (!sequence_buffer_[rindex].frame_begin) { |
| 127 rindex = rindex > 0 ? rindex - 1 : size_ - 1; |
| 128 start_seq_num--; |
| 129 } |
| 130 |
| 131 std::unique_ptr<FrameObject> frame( |
| 132 new RtpFrameObject(this, 1, start_seq_num, seq_num)); |
| 133 frame_callback_->OnCompleteFrame(std::move(frame)); |
| 134 } |
| 135 |
| 136 index = (index + 1) % size_; |
| 137 ++seq_num; |
| 138 } |
| 139 } |
| 140 |
| 141 void PacketBuffer::Flush() { |
| 142 rtc::CritScope lock(&crit_); |
| 143 for (size_t i = 0; i < size_; ++i) { |
| 144 sequence_buffer_[i].used = false; |
| 145 sequence_buffer_[i].continuous = false; |
| 146 } |
| 147 } |
| 148 |
| 149 } // namespace video_coding |
| 150 } // namespace webrtc |
OLD | NEW |