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 last_seq_num_(0), | |
29 cleared_to_seq_num_(0), | |
30 initialized_(false), | |
31 data_buffer_(start_buffer_size), | |
32 sequence_buffer_(start_buffer_size), | |
33 frame_callback_(frame_callback) { | |
34 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); | |
35 // Buffer size must always be a power of 2. | |
36 RTC_DCHECK((start_buffer_size & start_buffer_size - 1) == 0); | |
37 RTC_DCHECK((max_buffer_size & max_buffer_size - 1) == 0); | |
38 } | |
39 | |
40 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { | |
41 rtc::CritScope lock(&crit_); | |
42 uint16_t seq_num = packet.seqNum; | |
43 int index = seq_num % size_; | |
44 | |
45 if (!initialized_) { | |
46 cleared_to_seq_num_ = seq_num - 1; | |
stefan-webrtc
2016/03/31 13:03:00
I would still prefer to call this first_seq_num_,
philipel
2016/03/31 14:09:42
Agree, changed.
| |
47 last_seq_num_ = seq_num; | |
48 initialized_ = true; | |
49 } | |
50 | |
51 if (sequence_buffer_[index].used) { | |
52 // Duplicate packet, do nothing. | |
53 if (data_buffer_[index].seqNum == packet.seqNum) | |
54 return true; | |
55 | |
56 // The packet buffer is full, try to expand the buffer. | |
57 while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {} | |
58 index = seq_num % size_; | |
59 | |
60 // Packet buffer is still full. | |
61 if (sequence_buffer_[index].used) | |
62 return false; | |
63 } | |
64 | |
65 if (AheadOf(seq_num, last_seq_num_)) | |
66 last_seq_num_ = seq_num; | |
67 | |
68 sequence_buffer_[index].frame_begin = packet.isFirstPacket; | |
69 sequence_buffer_[index].frame_end = packet.markerBit; | |
70 sequence_buffer_[index].seq_num = packet.seqNum; | |
71 sequence_buffer_[index].continuous = false; | |
72 sequence_buffer_[index].used = true; | |
73 data_buffer_[index] = packet; | |
74 | |
75 FindCompleteFrames(seq_num); | |
76 return true; | |
77 } | |
78 | |
79 void PacketBuffer::ClearTo(uint16_t seq_num) { | |
80 rtc::CritScope lock(&crit_); | |
81 int index = cleared_to_seq_num_ % size_; | |
82 while (AheadOf<uint16_t>(seq_num, cleared_to_seq_num_ + 1)) { | |
83 index = (index + 1) % size_; | |
84 cleared_to_seq_num_ = Add<1 << 16>(cleared_to_seq_num_, 1); | |
85 sequence_buffer_[index].used = false; | |
86 } | |
87 } | |
88 | |
89 bool PacketBuffer::ExpandBufferSize() { | |
90 if (size_ == max_size_) | |
91 return false; | |
92 | |
93 size_t new_size = std::min(max_size_, 2 * size_); | |
94 std::vector<VCMPacket> new_data_buffer(new_size); | |
95 std::vector<ContinuityInfo> new_sequence_buffer(new_size); | |
96 for (size_t i = 0; i < size_; ++i) { | |
97 if (sequence_buffer_[i].used) { | |
98 int index = sequence_buffer_[i].seq_num % new_size; | |
99 new_sequence_buffer[index] = sequence_buffer_[i]; | |
100 new_data_buffer[index] = data_buffer_[i]; | |
101 } | |
102 } | |
103 size_ = new_size; | |
104 sequence_buffer_ = std::move(new_sequence_buffer); | |
105 data_buffer_ = std::move(new_data_buffer); | |
106 return true; | |
107 } | |
108 | |
109 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { | |
110 int index = seq_num % size_; | |
111 int prev_index = index > 0 ? index - 1 : size_ - 1; | |
112 if (!sequence_buffer_[index].used) | |
113 return false; | |
114 if (sequence_buffer_[index].frame_begin) | |
115 return true; | |
116 if (!sequence_buffer_[prev_index].used) | |
117 return false; | |
118 if (sequence_buffer_[prev_index].continuous) | |
119 return true; | |
120 | |
121 return false; | |
122 } | |
123 | |
124 void PacketBuffer::FindCompleteFrames(uint16_t seq_num) { | |
125 int index = seq_num % size_; | |
126 while (IsContinuous(seq_num)) { | |
127 sequence_buffer_[index].continuous = true; | |
128 | |
129 // If the frame is complete, find the first packet of the frame and | |
130 // create a FrameObject. | |
131 if (sequence_buffer_[index].frame_end) { | |
132 int rindex = index; | |
133 uint16_t start_seq_num = seq_num; | |
134 while (!sequence_buffer_[rindex].frame_begin) { | |
135 rindex = rindex > 0 ? rindex - 1 : size_ - 1; | |
136 start_seq_num--; | |
137 } | |
138 | |
139 std::unique_ptr<FrameObject> frame( | |
140 new RtpFrameObject(this, 1, start_seq_num, seq_num)); | |
141 frame_callback_->OnCompleteFrame(std::move(frame)); | |
142 } | |
143 | |
144 index = (index + 1) % size_; | |
145 ++seq_num; | |
146 } | |
147 } | |
148 | |
149 void PacketBuffer::ReturnFrame(RtpFrameObject* frame) { | |
150 rtc::CritScope lock(&crit_); | |
151 int index = frame->first_packet() % size_; | |
152 int end = (frame->last_packet() + 1) % size_; | |
153 uint16_t seq_num = frame->first_packet(); | |
154 while (index != end) { | |
155 if (sequence_buffer_[index].seq_num == seq_num) { | |
156 sequence_buffer_[index].used = false; | |
157 sequence_buffer_[index].continuous = false; | |
158 } | |
159 index = (index + 1) % size_; | |
160 ++seq_num; | |
161 } | |
162 | |
163 index = cleared_to_seq_num_ % size_; | |
164 while (AheadOf<uint16_t>(last_seq_num_, cleared_to_seq_num_) && | |
165 !sequence_buffer_[index].used) { | |
stefan-webrtc
2016/03/31 13:03:00
git cl format
philipel
2016/03/31 14:09:42
Formated, but nothing changed.
| |
166 ++cleared_to_seq_num_; | |
167 index = (index + 1) % size_; | |
168 } | |
169 } | |
170 | |
171 bool PacketBuffer::GetBitstream(const RtpFrameObject& frame, | |
172 uint8_t* destination) { | |
173 rtc::CritScope lock(&crit_); | |
174 | |
175 int index = frame.first_packet() % size_; | |
176 int end = (frame.last_packet() + 1) % size_; | |
177 uint16_t seq_num = frame.first_packet(); | |
178 while (index != end) { | |
179 if (!sequence_buffer_[index].used || | |
180 sequence_buffer_[index].seq_num != seq_num) { | |
181 return false; | |
182 } | |
183 | |
184 const uint8_t* source = data_buffer_[index].dataPtr; | |
185 size_t length = data_buffer_[index].sizeBytes; | |
186 memcpy(destination, source, length); | |
187 destination += length; | |
188 index = (index + 1) % size_; | |
189 ++seq_num; | |
190 } | |
191 return true; | |
192 } | |
193 | |
194 void PacketBuffer::Flush() { | |
195 rtc::CritScope lock(&crit_); | |
196 for (size_t i = 0; i < size_; ++i) { | |
197 sequence_buffer_[i].used = false; | |
198 sequence_buffer_[i].continuous = false; | |
199 } | |
200 } | |
201 | |
202 } // namespace video_coding | |
203 } // namespace webrtc | |
OLD | NEW |