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; | |
stefan-webrtc
2016/03/30 13:47:35
Maybe we should treat this as a success and just s
philipel
2016/03/31 12:21:50
Done.
| |
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 | |
58 // Packet buffer is still full. | |
59 if (sequence_buffer_[index].used) | |
60 return false; | |
61 } | |
62 | |
63 sequence_buffer_[index].frame_begin = packet.isFirstPacket; | |
64 sequence_buffer_[index].frame_end = packet.markerBit; | |
65 sequence_buffer_[index].seq_num = packet.seqNum; | |
66 sequence_buffer_[index].continuous = false; | |
67 sequence_buffer_[index].used = true; | |
68 data_buffer_[index] = packet; | |
69 | |
70 FindCompleteFrames(seq_num); | |
71 return true; | |
72 } | |
73 | |
74 void PacketBuffer::ClearUpTo(uint16_t seq_num) { | |
75 rtc::CritScope lock(&crit_); | |
76 int index = clear_up_to_ % size_; | |
stefan-webrtc
2016/03/30 13:47:35
Would lowest_seq_num_ or something like that be a
philipel
2016/03/31 12:21:50
Renamed |clear_up_to_| to |cleared_to_seq_num_|. A
| |
77 while (AheadOf<uint16_t>(seq_num, clear_up_to_)) { | |
78 sequence_buffer_[index].used = false; | |
79 index = (index + 1) % size_; | |
80 clear_up_to_ = Add<1 << 16>(clear_up_to_, 1); | |
81 } | |
82 } | |
83 | |
84 bool PacketBuffer::ExpandBufferSize() { | |
85 if (size_ == max_size_) { | |
86 return false; | |
87 } | |
88 | |
89 size_t new_size = std::min(max_size_, 2 * size_); | |
90 std::vector<VCMPacket> new_data_buffer(new_size); | |
91 std::vector<ContinuityInfo> new_sequence_buffer(new_size); | |
92 for (size_t i = 0; i < size_; ++i) { | |
93 if (sequence_buffer_[i].used) { | |
94 int index = sequence_buffer_[i].seq_num % new_size; | |
95 new_sequence_buffer[index] = sequence_buffer_[i]; | |
96 new_data_buffer[index] = data_buffer_[i]; | |
97 } | |
98 } | |
99 size_ = new_size; | |
100 sequence_buffer_ = std::move(new_sequence_buffer); | |
101 data_buffer_ = std::move(new_data_buffer); | |
102 return true; | |
103 } | |
104 | |
105 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { | |
106 int index = seq_num % size_; | |
107 int prev_index = index > 0 ? index - 1 : size_ - 1; | |
108 if (!sequence_buffer_[index].used) | |
109 return false; | |
110 if (sequence_buffer_[index].frame_begin) | |
111 return true; | |
112 if (!sequence_buffer_[prev_index].used) | |
113 return false; | |
114 if (sequence_buffer_[prev_index].continuous) | |
115 return true; | |
116 | |
117 return false; | |
118 } | |
119 | |
120 void PacketBuffer::FindCompleteFrames(uint16_t seq_num) { | |
121 int index = seq_num % size_; | |
122 while (IsContinuous(seq_num)) { | |
123 sequence_buffer_[index].continuous = true; | |
124 | |
125 // If the frame is complete, find the first packet of the frame and | |
126 // create a FrameObject. | |
127 if (sequence_buffer_[index].frame_end) { | |
128 int rindex = index; | |
129 uint16_t start_seq_num = seq_num; | |
130 while (!sequence_buffer_[rindex].frame_begin) { | |
131 rindex = rindex > 0 ? rindex - 1 : size_ - 1; | |
132 start_seq_num--; | |
133 } | |
134 | |
135 std::unique_ptr<FrameObject> frame( | |
136 new RtpFrameObject(this, 1, start_seq_num, seq_num)); | |
137 frame_callback_->OnCompleteFrame(std::move(frame)); | |
138 } | |
139 | |
140 index = (index + 1) % size_; | |
141 ++seq_num; | |
142 } | |
143 } | |
144 | |
145 void PacketBuffer::ReturnFrame(RtpFrameObject* frame) { | |
146 rtc::CritScope lock(&crit_); | |
147 int index = frame->first_packet() % size_; | |
148 int end = (frame->last_packet() + 1) % size_; | |
149 uint16_t seq_num = frame->first_packet(); | |
150 while (index != end) { | |
151 if (sequence_buffer_[index].seq_num == seq_num) { | |
152 sequence_buffer_[index].used = false; | |
153 sequence_buffer_[index].continuous = false; | |
154 } | |
155 index = (index + 1) % size_; | |
156 ++seq_num; | |
157 } | |
158 } | |
159 | |
160 bool PacketBuffer::GetBitstream(const RtpFrameObject& frame, | |
161 uint8_t* destination) { | |
162 rtc::CritScope lock(&crit_); | |
163 | |
164 int index = frame.first_packet() % size_; | |
165 int end = (frame.last_packet() + 1) % size_; | |
166 uint16_t seq_num = frame.first_packet(); | |
167 while (index != end) { | |
168 if (!sequence_buffer_[index].used || | |
169 sequence_buffer_[index].seq_num != seq_num) { | |
170 return false; | |
171 } | |
172 | |
173 const uint8_t* source = data_buffer_[index].dataPtr; | |
174 size_t length = data_buffer_[index].sizeBytes; | |
175 memcpy(destination, source, length); | |
176 destination += length; | |
177 index = (index + 1) % size_; | |
178 ++seq_num; | |
179 } | |
180 return true; | |
181 } | |
182 | |
183 void PacketBuffer::Flush() { | |
184 rtc::CritScope lock(&crit_); | |
185 for (size_t i = 0; i < size_; ++i) { | |
186 sequence_buffer_[i].used = false; | |
187 sequence_buffer_[i].continuous = false; | |
188 } | |
189 } | |
190 | |
191 } // namespace video_coding | |
192 } // namespace webrtc | |
OLD | NEW |