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 // Both |start_buffer_size| and |max_buffer_size| must be a power of 2. | |
stefan-webrtc
2016/03/30 12:56:20
I think this is better suited in the header file s
philipel
2016/03/30 13:35:52
Done.
| |
24 PacketBuffer::PacketBuffer(size_t start_buffer_size, | |
25 size_t max_buffer_size, | |
26 OnCompleteFrameCallback* frame_callback) | |
27 : size_(start_buffer_size), | |
28 max_size_(max_buffer_size), | |
29 clear_up_to_(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 clear_up_to_ = seq_num; | |
47 initialized_ = true; | |
48 } | |
49 | |
50 if (sequence_buffer_[index].used) { | |
51 // Duplicate packet, do nothing. | |
52 if (data_buffer_[index].seqNum == packet.seqNum) | |
53 return false; | |
54 | |
55 // The packet buffer is full, try to expand the buffer. | |
56 while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {} | |
57 index = seq_num % size_; | |
58 // If still full, test if the old packet can be discarded (overwritten | |
59 // later in the code), if not, return false. | |
60 if (sequence_buffer_[index].used && | |
61 AheadOrAt(sequence_buffer_[index].seq_num, clear_up_to_)) | |
62 return false; | |
63 } | |
64 | |
65 sequence_buffer_[index].frame_begin = packet.isFirstPacket; | |
66 sequence_buffer_[index].frame_end = packet.markerBit; | |
67 sequence_buffer_[index].seq_num = packet.seqNum; | |
68 sequence_buffer_[index].continuous = false; | |
69 sequence_buffer_[index].used = true; | |
70 data_buffer_[index] = packet; | |
71 | |
72 FindCompleteFrames(seq_num); | |
73 return true; | |
74 } | |
75 | |
76 void PacketBuffer::ClearUpTo(uint16_t seq_num) { | |
77 rtc::CritScope lock(&crit_); | |
78 clear_up_to_ = seq_num; | |
79 } | |
80 | |
81 bool PacketBuffer::ExpandBufferSize() { | |
82 if (size_ == max_size_) { | |
83 return false; | |
84 } | |
85 | |
86 size_t new_size = std::min(max_size_, 2 * size_); | |
87 std::vector<VCMPacket> new_data_buffer(new_size); | |
88 std::vector<ContinuityInfo> new_sequence_buffer(new_size); | |
89 for (size_t i = 0; i < size_; ++i) { | |
90 if (sequence_buffer_[i].used) { | |
91 int index = sequence_buffer_[i].seq_num % new_size; | |
92 new_sequence_buffer[index] = sequence_buffer_[i]; | |
93 new_data_buffer[index] = data_buffer_[i]; | |
94 } | |
95 } | |
96 size_ = new_size; | |
97 sequence_buffer_ = std::move(new_sequence_buffer); | |
98 data_buffer_ = std::move(new_data_buffer); | |
99 return true; | |
100 } | |
101 | |
102 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { | |
103 int index = seq_num % size_; | |
104 int prev_index = index > 0 ? index - 1 : size_ - 1; | |
105 if (!sequence_buffer_[index].used) | |
106 return false; | |
107 if (sequence_buffer_[index].frame_begin) | |
108 return true; | |
109 if (!sequence_buffer_[prev_index].used) | |
110 return false; | |
111 if (sequence_buffer_[prev_index].continuous) | |
112 return true; | |
113 | |
114 return false; | |
115 } | |
116 | |
117 void PacketBuffer::FindCompleteFrames(uint16_t seq_num) { | |
118 int index = seq_num % size_; | |
119 while (IsContinuous(seq_num)) { | |
120 sequence_buffer_[index].continuous = true; | |
121 | |
122 // If the frame is complete, find the first packet of the frame and | |
123 // create a FrameObject. | |
124 if (sequence_buffer_[index].frame_end) { | |
125 int rindex = index; | |
126 uint16_t start_seq_num = seq_num; | |
127 while (!sequence_buffer_[rindex].frame_begin) { | |
128 rindex = rindex > 0 ? rindex - 1 : size_ - 1; | |
129 start_seq_num--; | |
130 } | |
131 | |
132 std::unique_ptr<FrameObject> frame( | |
133 new RtpFrameObject(this, 1, start_seq_num, seq_num)); | |
134 frame_callback_->OnCompleteFrame(std::move(frame)); | |
135 } | |
136 | |
137 index = (index + 1) % size_; | |
138 ++seq_num; | |
139 } | |
140 } | |
141 | |
142 void PacketBuffer::ReturnFrame(RtpFrameObject* frame) { | |
143 rtc::CritScope lock(&crit_); | |
144 int index = frame->first_packet() % size_; | |
145 int end = (frame->last_packet() + 1) % size_; | |
146 uint16_t seq_num = frame->first_packet(); | |
147 while (index != end) { | |
148 if (sequence_buffer_[index].seq_num == seq_num) { | |
149 sequence_buffer_[index].used = false; | |
150 sequence_buffer_[index].continuous = false; | |
151 } | |
152 index = (index + 1) % size_; | |
153 ++seq_num; | |
154 } | |
155 } | |
156 | |
157 bool PacketBuffer::GetBitstream(const RtpFrameObject& frame, | |
158 uint8_t* destination) { | |
159 rtc::CritScope lock(&crit_); | |
160 | |
161 int index = frame.first_packet() % size_; | |
162 int end = (frame.last_packet() + 1) % size_; | |
163 uint16_t seq_num = frame.first_packet(); | |
164 while (index != end) { | |
165 if (!sequence_buffer_[index].used || | |
166 sequence_buffer_[index].seq_num != seq_num) { | |
167 return false; | |
168 } | |
169 | |
170 const uint8_t* source = data_buffer_[index].dataPtr; | |
171 size_t length = data_buffer_[index].sizeBytes; | |
172 memcpy(destination, source, length); | |
173 destination += length; | |
174 index = (index + 1) % size_; | |
175 ++seq_num; | |
176 } | |
177 return true; | |
178 } | |
179 | |
180 void PacketBuffer::Flush() { | |
181 rtc::CritScope lock(&crit_); | |
182 for (size_t i = 0; i < size_; ++i) { | |
183 sequence_buffer_[i].used = false; | |
184 sequence_buffer_[i].continuous = false; | |
185 } | |
186 } | |
187 | |
188 } // namespace video_coding | |
189 } // namespace webrtc | |
OLD | NEW |