OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" | 11 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" |
12 | 12 |
13 #include <assert.h> // assert | 13 #include <assert.h> // assert |
14 #include <string.h> // memcpy | 14 #include <string.h> // memcpy |
15 | 15 |
16 #include <limits> | |
17 #include <utility> | |
16 #include <vector> | 18 #include <vector> |
17 | 19 |
18 #include "webrtc/base/logging.h" | 20 #include "webrtc/base/logging.h" |
19 #include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h" | |
20 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" | 21 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" |
21 | 22 |
22 namespace webrtc { | 23 namespace webrtc { |
23 namespace { | 24 namespace { |
24 int ParseVP8PictureID(RTPVideoHeaderVP8* vp8, | 25 int ParseVP8PictureID(RTPVideoHeaderVP8* vp8, |
25 const uint8_t** data, | 26 const uint8_t** data, |
26 size_t* data_length, | 27 size_t* data_length, |
27 size_t* parsed_bytes) { | 28 size_t* parsed_bytes) { |
28 assert(vp8 != NULL); | 29 assert(vp8 != NULL); |
29 if (*data_length == 0) | 30 if (*data_length == 0) |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 // For an I-frame we should always have the uncompressed VP8 header | 134 // For an I-frame we should always have the uncompressed VP8 header |
134 // in the beginning of the partition. | 135 // in the beginning of the partition. |
135 return -1; | 136 return -1; |
136 } | 137 } |
137 parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF; | 138 parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF; |
138 parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF; | 139 parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF; |
139 return 0; | 140 return 0; |
140 } | 141 } |
141 } // namespace | 142 } // namespace |
142 | 143 |
143 // Define how the VP8PacketizerModes are implemented. | |
144 // Modes are: kStrict, kAggregate, kEqualSize. | |
145 const RtpPacketizerVp8::AggregationMode RtpPacketizerVp8::aggr_modes_ | |
146 [kNumModes] = {kAggrNone, kAggrPartitions, kAggrFragments}; | |
147 const bool RtpPacketizerVp8::balance_modes_[kNumModes] = {true, true, true}; | |
148 const bool RtpPacketizerVp8::separate_first_modes_[kNumModes] = {true, false, | |
149 false}; | |
150 | |
151 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, | 144 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, |
152 size_t max_payload_len, | 145 size_t max_payload_len, |
146 size_t last_packet_reduction_len, | |
153 VP8PacketizerMode mode) | 147 VP8PacketizerMode mode) |
154 : payload_data_(NULL), | 148 : payload_data_(NULL), |
155 payload_size_(0), | 149 payload_size_(0), |
156 vp8_fixed_payload_descriptor_bytes_(1), | 150 vp8_fixed_payload_descriptor_bytes_(1), |
157 aggr_mode_(aggr_modes_[mode]), | 151 mode_(mode), |
158 balance_(balance_modes_[mode]), | |
159 separate_first_(separate_first_modes_[mode]), | |
160 hdr_info_(hdr_info), | 152 hdr_info_(hdr_info), |
161 num_partitions_(0), | 153 num_partitions_(0), |
162 max_payload_len_(max_payload_len), | 154 max_payload_len_(max_payload_len), |
163 packets_calculated_(false) { | 155 last_packet_reduction_len_(last_packet_reduction_len) {} |
164 } | |
165 | 156 |
166 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, | 157 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, |
167 size_t max_payload_len) | 158 size_t max_payload_len, |
159 size_t last_packet_reduction_len) | |
168 : payload_data_(NULL), | 160 : payload_data_(NULL), |
169 payload_size_(0), | 161 payload_size_(0), |
170 part_info_(), | 162 part_info_(), |
171 vp8_fixed_payload_descriptor_bytes_(1), | 163 vp8_fixed_payload_descriptor_bytes_(1), |
172 aggr_mode_(aggr_modes_[kEqualSize]), | 164 mode_(kEqualSize), |
173 balance_(balance_modes_[kEqualSize]), | |
174 separate_first_(separate_first_modes_[kEqualSize]), | |
175 hdr_info_(hdr_info), | 165 hdr_info_(hdr_info), |
176 num_partitions_(0), | 166 num_partitions_(0), |
177 max_payload_len_(max_payload_len), | 167 max_payload_len_(max_payload_len), |
178 packets_calculated_(false) { | 168 last_packet_reduction_len_(last_packet_reduction_len) {} |
179 } | |
180 | 169 |
181 RtpPacketizerVp8::~RtpPacketizerVp8() { | 170 RtpPacketizerVp8::~RtpPacketizerVp8() { |
182 } | 171 } |
183 | 172 |
184 void RtpPacketizerVp8::SetPayloadData( | 173 size_t RtpPacketizerVp8::SetPayloadData( |
185 const uint8_t* payload_data, | 174 const uint8_t* payload_data, |
186 size_t payload_size, | 175 size_t payload_size, |
187 const RTPFragmentationHeader* fragmentation) { | 176 const RTPFragmentationHeader* fragmentation) { |
188 payload_data_ = payload_data; | 177 payload_data_ = payload_data; |
189 payload_size_ = payload_size; | 178 payload_size_ = payload_size; |
190 if (fragmentation) { | 179 if (fragmentation) { |
191 part_info_.CopyFrom(*fragmentation); | 180 part_info_.CopyFrom(*fragmentation); |
192 num_partitions_ = fragmentation->fragmentationVectorSize; | 181 num_partitions_ = fragmentation->fragmentationVectorSize; |
193 } else { | 182 } else { |
194 part_info_.VerifyAndAllocateFragmentationHeader(1); | 183 part_info_.VerifyAndAllocateFragmentationHeader(1); |
195 part_info_.fragmentationLength[0] = payload_size; | 184 part_info_.fragmentationLength[0] = payload_size; |
196 part_info_.fragmentationOffset[0] = 0; | 185 part_info_.fragmentationOffset[0] = 0; |
197 num_partitions_ = part_info_.fragmentationVectorSize; | 186 num_partitions_ = part_info_.fragmentationVectorSize; |
198 } | 187 } |
188 if (GeneratePackets() < 0) { | |
189 return 0; | |
190 } | |
191 return packets_.size(); | |
199 } | 192 } |
200 | 193 |
201 bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet, bool* last_packet) { | 194 bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) { |
202 RTC_DCHECK(packet); | 195 RTC_DCHECK(packet); |
203 RTC_DCHECK(last_packet); | |
204 if (!packets_calculated_) { | |
205 int ret = 0; | |
206 if (aggr_mode_ == kAggrPartitions && balance_) { | |
207 ret = GeneratePacketsBalancedAggregates(); | |
208 } else { | |
209 ret = GeneratePackets(); | |
210 } | |
211 if (ret < 0) { | |
212 return false; | |
213 } | |
214 } | |
215 if (packets_.empty()) { | 196 if (packets_.empty()) { |
216 return false; | 197 return false; |
217 } | 198 } |
218 InfoStruct packet_info = packets_.front(); | 199 InfoStruct packet_info = packets_.front(); |
219 packets_.pop(); | 200 packets_.pop(); |
220 | 201 |
221 uint8_t* buffer = packet->AllocatePayload(max_payload_len_); | 202 uint8_t* buffer = packet->AllocatePayload( |
203 packets_.empty() ? max_payload_len_ - last_packet_reduction_len_ | |
204 : max_payload_len_); | |
222 int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_); | 205 int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_); |
223 if (bytes < 0) { | 206 if (bytes < 0) { |
224 return false; | 207 return false; |
225 } | 208 } |
226 packet->SetPayloadSize(bytes); | 209 packet->SetPayloadSize(bytes); |
227 *last_packet = packets_.empty(); | 210 packet->SetMarker(packets_.empty()); |
228 packet->SetMarker(*last_packet); | |
229 return true; | 211 return true; |
230 } | 212 } |
231 | 213 |
232 ProtectionType RtpPacketizerVp8::GetProtectionType() { | 214 ProtectionType RtpPacketizerVp8::GetProtectionType() { |
233 bool protect = | 215 bool protect = |
234 hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx; | 216 hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx; |
235 return protect ? kProtectedPacket : kUnprotectedPacket; | 217 return protect ? kProtectedPacket : kUnprotectedPacket; |
236 } | 218 } |
237 | 219 |
238 StorageType RtpPacketizerVp8::GetStorageType(uint32_t retransmission_settings) { | 220 StorageType RtpPacketizerVp8::GetStorageType(uint32_t retransmission_settings) { |
239 if (hdr_info_.temporalIdx == 0 && | 221 if (hdr_info_.temporalIdx == 0 && |
240 !(retransmission_settings & kRetransmitBaseLayer)) { | 222 !(retransmission_settings & kRetransmitBaseLayer)) { |
241 return kDontRetransmit; | 223 return kDontRetransmit; |
242 } | 224 } |
243 if (hdr_info_.temporalIdx != kNoTemporalIdx && | 225 if (hdr_info_.temporalIdx != kNoTemporalIdx && |
244 hdr_info_.temporalIdx > 0 && | 226 hdr_info_.temporalIdx > 0 && |
245 !(retransmission_settings & kRetransmitHigherLayers)) { | 227 !(retransmission_settings & kRetransmitHigherLayers)) { |
246 return kDontRetransmit; | 228 return kDontRetransmit; |
247 } | 229 } |
248 return kAllowRetransmission; | 230 return kAllowRetransmission; |
249 } | 231 } |
250 | 232 |
251 std::string RtpPacketizerVp8::ToString() { | 233 std::string RtpPacketizerVp8::ToString() { |
252 return "RtpPacketizerVp8"; | 234 return "RtpPacketizerVp8"; |
253 } | 235 } |
254 | 236 |
255 size_t RtpPacketizerVp8::CalcNextSize(size_t max_payload_len, | |
256 size_t remaining_bytes, | |
257 bool split_payload) const { | |
258 if (max_payload_len == 0 || remaining_bytes == 0) { | |
259 return 0; | |
260 } | |
261 if (!split_payload) { | |
262 return max_payload_len >= remaining_bytes ? remaining_bytes : 0; | |
263 } | |
264 | |
265 if (balance_) { | |
266 // Balance payload sizes to produce (almost) equal size | |
267 // fragments. | |
268 // Number of fragments for remaining_bytes: | |
269 size_t num_frags = remaining_bytes / max_payload_len + 1; | |
270 // Number of bytes in this fragment: | |
271 return static_cast<size_t>( | |
272 static_cast<double>(remaining_bytes) / num_frags + 0.5); | |
273 } else { | |
274 return max_payload_len >= remaining_bytes ? remaining_bytes | |
275 : max_payload_len; | |
276 } | |
277 } | |
278 | |
279 int RtpPacketizerVp8::GeneratePackets() { | 237 int RtpPacketizerVp8::GeneratePackets() { |
280 if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + | 238 if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + |
281 PayloadDescriptorExtraLength() + 1) { | 239 PayloadDescriptorExtraLength() + 1 + |
240 last_packet_reduction_len_) { | |
282 // The provided payload length is not long enough for the payload | 241 // The provided payload length is not long enough for the payload |
283 // descriptor and one payload byte. Return an error. | 242 // descriptor and one payload byte in the last packet. |
243 // Return an error. | |
284 return -1; | 244 return -1; |
285 } | 245 } |
286 size_t total_bytes_processed = 0; | 246 |
287 bool start_on_new_fragment = true; | 247 size_t per_packet_capacity = |
288 bool beginning = true; | 248 max_payload_len_ - |
249 (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength()); | |
250 | |
251 if (mode_ == kEqualSize) { | |
252 SplitPayloadBalanced(0, payload_size_, per_packet_capacity, true, 0); | |
253 return 0; | |
254 } | |
289 size_t part_ix = 0; | 255 size_t part_ix = 0; |
290 while (total_bytes_processed < payload_size_) { | 256 while (part_ix < num_partitions_) { |
291 size_t packet_bytes = 0; // How much data to send in this packet. | 257 size_t current_capacity = per_packet_capacity; |
292 bool split_payload = true; // Splitting of partitions is initially allowed. | 258 bool last = (part_ix + 1) == num_partitions_; |
293 size_t remaining_in_partition = part_info_.fragmentationOffset[part_ix] - | 259 if (last) |
294 total_bytes_processed + | 260 current_capacity -= last_packet_reduction_len_; |
295 part_info_.fragmentationLength[part_ix]; | 261 if (mode_ == kAggregate && |
296 size_t rem_payload_len = | 262 part_info_.fragmentationLength[part_ix] < current_capacity) { |
297 max_payload_len_ - | 263 part_ix = AggregatePartitions(part_ix, per_packet_capacity); |
298 (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength()); | 264 } else { |
299 size_t first_partition_in_packet = part_ix; | 265 SplitPayloadBalanced(part_info_.fragmentationOffset[part_ix], |
300 | 266 part_info_.fragmentationLength[part_ix], |
301 while (size_t next_size = CalcNextSize( | 267 per_packet_capacity, last, part_ix); |
302 rem_payload_len, remaining_in_partition, split_payload)) { | 268 part_ix++; |
303 packet_bytes += next_size; | |
304 rem_payload_len -= next_size; | |
305 remaining_in_partition -= next_size; | |
306 | |
307 if (remaining_in_partition == 0 && !(beginning && separate_first_)) { | |
308 // Advance to next partition? | |
309 // Check that there are more partitions; verify that we are either | |
310 // allowed to aggregate fragments, or that we are allowed to | |
311 // aggregate intact partitions and that we started this packet | |
312 // with an intact partition (indicated by first_fragment_ == true). | |
313 if (part_ix + 1 < num_partitions_ && | |
314 ((aggr_mode_ == kAggrFragments) || | |
315 (aggr_mode_ == kAggrPartitions && start_on_new_fragment))) { | |
316 assert(part_ix < num_partitions_); | |
317 remaining_in_partition = part_info_.fragmentationLength[++part_ix]; | |
318 // Disallow splitting unless kAggrFragments. In kAggrPartitions, | |
319 // we can only aggregate intact partitions. | |
320 split_payload = (aggr_mode_ == kAggrFragments); | |
321 } | |
322 } else if (balance_ && remaining_in_partition > 0) { | |
323 break; | |
324 } | |
325 } | 269 } |
326 if (remaining_in_partition == 0) { | |
327 ++part_ix; // Advance to next partition. | |
328 } | |
329 assert(packet_bytes > 0); | |
330 | |
331 QueuePacket(total_bytes_processed, | |
332 packet_bytes, | |
333 first_partition_in_packet, | |
334 start_on_new_fragment); | |
335 total_bytes_processed += packet_bytes; | |
336 start_on_new_fragment = (remaining_in_partition == 0); | |
337 beginning = false; // Next packet cannot be first packet in frame. | |
338 } | 270 } |
339 packets_calculated_ = true; | |
340 assert(total_bytes_processed == payload_size_); | |
341 return 0; | 271 return 0; |
342 } | 272 } |
343 | 273 |
344 int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() { | 274 void RtpPacketizerVp8::SplitPayloadBalanced(size_t payload_start, |
345 if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + | 275 size_t payload_len, |
346 PayloadDescriptorExtraLength() + 1) { | 276 size_t capacity, |
347 // The provided payload length is not long enough for the payload | 277 bool last, |
348 // descriptor and one payload byte. Return an error. | 278 size_t part_ix) { |
349 return -1; | 279 // Last packet of the last partition is smaller. Pretend that it's the same |
350 } | 280 // size, but we must write more payload to it. |
351 std::vector<int> partition_decision; | 281 size_t total_bytes = payload_len; |
352 const size_t overhead = | 282 if (last) |
353 vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength(); | 283 total_bytes += last_packet_reduction_len_; |
354 const size_t max_payload_len = max_payload_len_ - overhead; | 284 // Integer divisions with rounding up. |
355 int min_size, max_size; | 285 size_t num_packets_left = (total_bytes + capacity - 1) / capacity; |
356 AggregateSmallPartitions(&partition_decision, &min_size, &max_size); | 286 size_t bytes_per_packet = (total_bytes) / num_packets_left; |
danilchap
2017/05/18 11:14:24
remove () round total_bytes
ilnik
2017/05/18 12:22:52
Done.
| |
357 | 287 size_t num_larger_packets = total_bytes % num_packets_left; |
358 size_t total_bytes_processed = 0; | 288 size_t remaining_data = payload_len; |
359 size_t part_ix = 0; | 289 while (remaining_data > 0) { |
360 while (part_ix < num_partitions_) { | 290 // Only first num_larger_packets are 1 byte wider than the rest. |
danilchap
2017/05/18 11:14:24
Aren't |num_larger_packets| last?
ilnik
2017/05/18 12:22:52
Forgot to change the comment according to changed
| |
361 if (partition_decision[part_ix] == -1) { | 291 if (num_packets_left == num_larger_packets) |
362 // Split large partitions. | 292 ++bytes_per_packet; |
363 size_t remaining_partition = part_info_.fragmentationLength[part_ix]; | 293 size_t current_packet_bytes = bytes_per_packet; |
364 size_t num_fragments = Vp8PartitionAggregator::CalcNumberOfFragments( | 294 if (current_packet_bytes > remaining_data) { |
365 remaining_partition, max_payload_len, overhead, min_size, max_size); | 295 current_packet_bytes = remaining_data; |
366 const size_t packet_bytes = | |
367 (remaining_partition + num_fragments - 1) / num_fragments; | |
368 for (size_t n = 0; n < num_fragments; ++n) { | |
369 const size_t this_packet_bytes = packet_bytes < remaining_partition | |
370 ? packet_bytes | |
371 : remaining_partition; | |
372 QueuePacket( | |
373 total_bytes_processed, this_packet_bytes, part_ix, (n == 0)); | |
374 remaining_partition -= this_packet_bytes; | |
375 total_bytes_processed += this_packet_bytes; | |
376 if (static_cast<int>(this_packet_bytes) < min_size) { | |
377 min_size = this_packet_bytes; | |
378 } | |
379 if (static_cast<int>(this_packet_bytes) > max_size) { | |
380 max_size = this_packet_bytes; | |
381 } | |
382 } | |
383 assert(remaining_partition == 0); | |
384 ++part_ix; | |
385 } else { | |
386 size_t this_packet_bytes = 0; | |
387 const size_t first_partition_in_packet = part_ix; | |
388 const int aggregation_index = partition_decision[part_ix]; | |
389 while (part_ix < partition_decision.size() && | |
390 partition_decision[part_ix] == aggregation_index) { | |
391 // Collect all partitions that were aggregated into the same packet. | |
392 this_packet_bytes += part_info_.fragmentationLength[part_ix]; | |
393 ++part_ix; | |
394 } | |
395 QueuePacket(total_bytes_processed, | |
396 this_packet_bytes, | |
397 first_partition_in_packet, | |
398 true); | |
399 total_bytes_processed += this_packet_bytes; | |
400 } | 296 } |
401 } | 297 // This is not the last packet in the whole payload, but there's no data |
402 packets_calculated_ = true; | 298 // left for the last packet. Leave at least one byte for the last packet. |
403 return 0; | 299 if (num_packets_left == 2 && current_packet_bytes == remaining_data && |
404 } | 300 last) { |
405 | 301 --current_packet_bytes; |
406 void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec, | |
407 int* min_size, | |
408 int* max_size) { | |
409 assert(min_size && max_size); | |
410 *min_size = -1; | |
411 *max_size = -1; | |
412 assert(partition_vec); | |
413 partition_vec->assign(num_partitions_, -1); | |
414 const size_t overhead = | |
415 vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength(); | |
416 const size_t max_payload_len = max_payload_len_ - overhead; | |
417 size_t first_in_set = 0; | |
418 size_t last_in_set = 0; | |
419 int num_aggregate_packets = 0; | |
420 // Find sets of partitions smaller than max_payload_len_. | |
421 while (first_in_set < num_partitions_) { | |
422 if (part_info_.fragmentationLength[first_in_set] < max_payload_len) { | |
423 // Found start of a set. | |
424 last_in_set = first_in_set; | |
425 while (last_in_set + 1 < num_partitions_ && | |
426 part_info_.fragmentationLength[last_in_set + 1] < | |
427 max_payload_len) { | |
428 ++last_in_set; | |
429 } | |
430 // Found end of a set. Run optimized aggregator. It is ok if start == end. | |
431 Vp8PartitionAggregator aggregator(part_info_, first_in_set, last_in_set); | |
432 if (*min_size >= 0 && *max_size >= 0) { | |
433 aggregator.SetPriorMinMax(*min_size, *max_size); | |
434 } | |
435 Vp8PartitionAggregator::ConfigVec optimal_config = | |
436 aggregator.FindOptimalConfiguration(max_payload_len, overhead); | |
437 aggregator.CalcMinMax(optimal_config, min_size, max_size); | |
438 for (size_t i = first_in_set, j = 0; i <= last_in_set; ++i, ++j) { | |
439 // Transfer configuration for this set of partitions to the joint | |
440 // partition vector representing all partitions in the frame. | |
441 (*partition_vec)[i] = num_aggregate_packets + optimal_config[j]; | |
442 } | |
443 num_aggregate_packets += optimal_config.back() + 1; | |
444 first_in_set = last_in_set; | |
445 } | 302 } |
446 ++first_in_set; | 303 QueuePacket(payload_start + payload_len - remaining_data, |
304 current_packet_bytes, part_ix, remaining_data == payload_len); | |
305 remaining_data -= current_packet_bytes; | |
306 --num_packets_left; | |
447 } | 307 } |
448 } | 308 } |
449 | 309 |
310 size_t RtpPacketizerVp8::AggregatePartitions(size_t part_ix, size_t capacity) { | |
311 // Bloat the last partition by the reduction of the last packet. As it always | |
312 // will be in the last packet we can pretend that the last packet is the same | |
313 // size as the rest of the packets. Done temporary to simplify calculations. | |
314 part_info_.fragmentationLength[num_partitions_ - 1] += | |
315 last_packet_reduction_len_; | |
316 // Current partition should fit into the packet. | |
317 RTC_CHECK_LE(part_info_.fragmentationLength[part_ix], capacity); | |
318 // Find all partitions, shorter than capacity. | |
319 size_t end_part = part_ix + 1; | |
320 while (end_part < num_partitions_ && | |
321 part_info_.fragmentationLength[end_part] <= capacity) { | |
322 end_part++; | |
323 } | |
324 size_t total_partitions = end_part - part_ix; | |
325 | |
326 // Aggregate partitions start..finish-1 to blocks of size at most |capacity| | |
327 // minimizing the number of packets and then size of a largest block using | |
328 // dynamic programming. score[i] stores best score in the form | |
329 // <number of packets, largest packet> for last i partitions. Maximum index is | |
330 // |total_partitions|, minimum index is 0, hence the length is | |
331 // |total_partitions|+1. | |
332 | |
333 std::vector<std::pair<size_t, size_t>> score( | |
334 total_partitions + 1, std::make_pair(std::numeric_limits<size_t>::max(), | |
335 std::numeric_limits<size_t>::max())); | |
336 // Best number of partitions in the first packet in block realizing optimal | |
337 // score. | |
338 std::vector<size_t> best_block_size(total_partitions + 1, 0); | |
339 // 0 partitions can be split into 0 packets with largest of size 0. | |
340 score[0] = std::make_pair(0, 0); | |
341 // Calculate score and best_block_size iteratively. | |
342 for (size_t left = 0; left < total_partitions; ++left) { | |
343 // Here score[left] is already calculated correctly. Update possible score | |
344 // for every possible new_left > left by aggregating all partitions in | |
345 // between into a single packet. | |
346 size_t current_payload_len = 0; | |
347 std::pair<size_t, size_t> current_score = score[left]; | |
348 // One more packet. | |
349 current_score.first += 1; | |
350 // Calculating new score for last |new_left| partitions given best score for | |
351 // |left| partitions. | |
352 for (size_t new_left = left + 1; new_left <= total_partitions; ++new_left) { | |
353 current_payload_len += | |
354 part_info_.fragmentationLength[end_part - new_left]; | |
355 if (current_payload_len > capacity) | |
356 break; | |
357 // Update maximum packet size. | |
358 if (current_payload_len > current_score.second) | |
359 current_score.second = current_payload_len; | |
360 // std::pair < operator firstly compares first value like we want here. | |
361 if (current_score < score[new_left]) { | |
362 score[new_left] = current_score; | |
363 best_block_size[new_left] = new_left - left; | |
364 } | |
365 } | |
366 } | |
367 // Undo temporal change. | |
368 part_info_.fragmentationLength[num_partitions_ - 1] -= | |
369 last_packet_reduction_len_; | |
370 // Restore answer given sizes of aggregated blocks in |best_block_size| for | |
371 // each possible left number of partitions. | |
372 size_t partitions_left = total_partitions; | |
373 while (partitions_left > 0) { | |
374 size_t cur_parts = best_block_size[partitions_left]; | |
375 size_t first_partition = end_part - partitions_left; | |
376 size_t start_offset = part_info_.fragmentationOffset[first_partition]; | |
377 size_t post_last_partition = first_partition + cur_parts; | |
378 size_t finish_offset = | |
379 (post_last_partition < num_partitions_) | |
380 ? part_info_.fragmentationOffset[post_last_partition] | |
381 : payload_size_; | |
382 size_t current_payload_len = finish_offset - start_offset; | |
383 QueuePacket(start_offset, current_payload_len, first_partition, true); | |
384 // Go to next packet. | |
385 partitions_left -= cur_parts; | |
386 } | |
387 return end_part; | |
388 } | |
389 | |
450 void RtpPacketizerVp8::QueuePacket(size_t start_pos, | 390 void RtpPacketizerVp8::QueuePacket(size_t start_pos, |
451 size_t packet_size, | 391 size_t packet_size, |
452 size_t first_partition_in_packet, | 392 size_t first_partition_in_packet, |
453 bool start_on_new_fragment) { | 393 bool start_on_new_fragment) { |
454 // Write info to packet info struct and store in packet info queue. | 394 // Write info to packet info struct and store in packet info queue. |
455 InfoStruct packet_info; | 395 InfoStruct packet_info; |
456 packet_info.payload_start_pos = start_pos; | 396 packet_info.payload_start_pos = start_pos; |
457 packet_info.size = packet_size; | 397 packet_info.size = packet_size; |
458 packet_info.first_partition_ix = first_partition_in_packet; | 398 packet_info.first_partition_ix = first_partition_in_packet; |
459 packet_info.first_fragment = start_on_new_fragment; | 399 packet_info.first_fragment = start_on_new_fragment; |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) != | 676 if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) != |
737 0) { | 677 0) { |
738 return false; | 678 return false; |
739 } | 679 } |
740 | 680 |
741 parsed_payload->payload = payload_data; | 681 parsed_payload->payload = payload_data; |
742 parsed_payload->payload_length = payload_data_length; | 682 parsed_payload->payload_length = payload_data_length; |
743 return true; | 683 return true; |
744 } | 684 } |
745 } // namespace webrtc | 685 } // namespace webrtc |
OLD | NEW |