Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc

Issue 2871173008: Fix packetization logic to leave space for extensions in the last packet (Closed)
Patch Set: Implement Danilchap@ comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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;
287 bool start_on_new_fragment = true;
288 bool beginning = true;
289 size_t part_ix = 0;
290 while (total_bytes_processed < payload_size_) {
291 size_t packet_bytes = 0; // How much data to send in this packet.
292 bool split_payload = true; // Splitting of partitions is initially allowed.
293 size_t remaining_in_partition = part_info_.fragmentationOffset[part_ix] -
294 total_bytes_processed +
295 part_info_.fragmentationLength[part_ix];
296 size_t rem_payload_len =
297 max_payload_len_ -
298 (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
299 size_t first_partition_in_packet = part_ix;
300 246
301 while (size_t next_size = CalcNextSize( 247 size_t per_packet_capacity =
302 rem_payload_len, remaining_in_partition, split_payload)) { 248 max_payload_len_ -
303 packet_bytes += next_size; 249 (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
304 rem_payload_len -= next_size;
305 remaining_in_partition -= next_size;
306 250
307 if (remaining_in_partition == 0 && !(beginning && separate_first_)) { 251 if (mode_ == kEqualSize) {
308 // Advance to next partition? 252 GeneratePacketsSplitPayloadBalanced(0, payload_size_, per_packet_capacity,
309 // Check that there are more partitions; verify that we are either 253 true, 0);
310 // allowed to aggregate fragments, or that we are allowed to 254 return 0;
311 // aggregate intact partitions and that we started this packet 255 }
312 // with an intact partition (indicated by first_fragment_ == true). 256 size_t part_idx = 0;
313 if (part_ix + 1 < num_partitions_ && 257 while (part_idx < num_partitions_) {
314 ((aggr_mode_ == kAggrFragments) || 258 size_t current_packet_capacity = per_packet_capacity;
315 (aggr_mode_ == kAggrPartitions && start_on_new_fragment))) { 259 bool last_partition = (part_idx + 1) == num_partitions_;
316 assert(part_ix < num_partitions_); 260 if (last_partition)
317 remaining_in_partition = part_info_.fragmentationLength[++part_ix]; 261 current_packet_capacity -= last_packet_reduction_len_;
318 // Disallow splitting unless kAggrFragments. In kAggrPartitions, 262 // Check if the next partition fits in to single packet with some space
319 // we can only aggregate intact partitions. 263 // left to aggregate some partitions together.
320 split_payload = (aggr_mode_ == kAggrFragments); 264 if (mode_ == kAggregate &&
321 } 265 part_info_.fragmentationLength[part_idx] < current_packet_capacity) {
322 } else if (balance_ && remaining_in_partition > 0) { 266 part_idx =
323 break; 267 GeneratePacketsAggregatePartitions(part_idx, per_packet_capacity);
324 } 268 } else {
269 GeneratePacketsSplitPayloadBalanced(
270 part_info_.fragmentationOffset[part_idx],
271 part_info_.fragmentationLength[part_idx], per_packet_capacity,
272 last_partition, part_idx);
273 ++part_idx;
325 } 274 }
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 } 275 }
339 packets_calculated_ = true;
340 assert(total_bytes_processed == payload_size_);
341 return 0; 276 return 0;
342 } 277 }
343 278
344 int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() { 279 void RtpPacketizerVp8::GeneratePacketsSplitPayloadBalanced(size_t payload_start,
345 if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + 280 size_t payload_len,
346 PayloadDescriptorExtraLength() + 1) { 281 size_t capacity,
347 // The provided payload length is not long enough for the payload 282 bool last_partition,
348 // descriptor and one payload byte. Return an error. 283 size_t part_idx) {
349 return -1; 284 // Last packet of the last partition is smaller. Pretend that it's the same
350 } 285 // size, but we must write more payload to it.
351 std::vector<int> partition_decision; 286 size_t total_bytes = payload_len;
352 const size_t overhead = 287 if (last_partition)
353 vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength(); 288 total_bytes += last_packet_reduction_len_;
354 const size_t max_payload_len = max_payload_len_ - overhead; 289 // Integer divisions with rounding up.
355 int min_size, max_size; 290 size_t num_packets_left = (total_bytes + capacity - 1) / capacity;
356 AggregateSmallPartitions(&partition_decision, &min_size, &max_size); 291 size_t bytes_per_packet = total_bytes / num_packets_left;
357 292 size_t num_larger_packets = total_bytes % num_packets_left;
358 size_t total_bytes_processed = 0; 293 size_t remaining_data = payload_len;
359 size_t part_ix = 0; 294 while (remaining_data > 0) {
360 while (part_ix < num_partitions_) { 295 // Last num_larger_packets are 1 byte wider than the rest. Increase
361 if (partition_decision[part_ix] == -1) { 296 // per-packet payload size when needed.
362 // Split large partitions. 297 if (num_packets_left == num_larger_packets)
363 size_t remaining_partition = part_info_.fragmentationLength[part_ix]; 298 ++bytes_per_packet;
364 size_t num_fragments = Vp8PartitionAggregator::CalcNumberOfFragments( 299 size_t current_packet_bytes = bytes_per_packet;
365 remaining_partition, max_payload_len, overhead, min_size, max_size); 300 if (current_packet_bytes > remaining_data) {
366 const size_t packet_bytes = 301 current_packet_bytes = remaining_data;
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 } 302 }
401 } 303 // This is not the last packet in the whole payload, but there's no data
402 packets_calculated_ = true; 304 // left for the last packet. Leave at least one byte for the last packet.
403 return 0; 305 if (num_packets_left == 2 && current_packet_bytes == remaining_data &&
404 } 306 last_partition) {
405 307 --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 } 308 }
446 ++first_in_set; 309 QueuePacket(payload_start + payload_len - remaining_data,
310 current_packet_bytes, part_idx, remaining_data == payload_len);
311 remaining_data -= current_packet_bytes;
312 --num_packets_left;
447 } 313 }
448 } 314 }
449 315
316 size_t RtpPacketizerVp8::GeneratePacketsAggregatePartitions(size_t part_idx,
317 size_t capacity) {
318 // Bloat the last partition by the reduction of the last packet. As it always
319 // will be in the last packet we can pretend that the last packet is the same
320 // size as the rest of the packets. Done temporary to simplify calculations.
321 part_info_.fragmentationLength[num_partitions_ - 1] +=
322 last_packet_reduction_len_;
323 // Current partition should fit into the packet.
324 RTC_CHECK_LE(part_info_.fragmentationLength[part_idx], capacity);
325 // Find all partitions, shorter than capacity.
326 size_t end_part = part_idx + 1;
327 while (end_part < num_partitions_ &&
328 part_info_.fragmentationLength[end_part] <= capacity) {
329 end_part++;
danilchap 2017/05/23 15:55:03 ++end_part
ilnik 2017/05/23 16:14:29 Done.
330 }
331 size_t total_partitions = end_part - part_idx;
332
333 // Aggregate partitions |part_idx|..|end_part-1| to blocks of size at most
334 // |capacity| minimizing the number of packets and then size of a largest
335 // block using dynamic programming. |scores[i]| stores best score in the form
336 // <number of packets, largest packet> for last i partitions. Maximum index is
337 // |total_partitions|, minimum index is 0, hence the length is
338 // |total_partitions|+1.
339
340 struct PartitionScore {
341 size_t num_packets = std::numeric_limits<size_t>::max();
342 size_t largest_packet_len = std::numeric_limits<size_t>::max();
343 // Compare num_packets first then largest_packet_len
344 bool operator <(const PartitionScore& other) const {
345 if (num_packets < other.num_packets) return true;
346 if (num_packets > other.num_packets) return false;
347 return largest_packet_len < other.largest_packet_len;
348 }
349 };
350
351 std::vector<PartitionScore> scores(total_partitions + 1);
352 // 0 partitions can be split into 0 packets with largest of size 0.
353 scores[0].num_packets = 0;
354 scores[0].largest_packet_len = 0;
355
356 // best_block_size[i] stores optimal number of partitions to be aggregated
357 // in the first packet if only last i partitions are considered.
358 std::vector<size_t> best_block_size(total_partitions + 1, 0);
359 // Calculate scores and best_block_size iteratively.
360 for (size_t partitions_left = 0; partitions_left < total_partitions;
361 ++partitions_left) {
362 // Here scores[paritions_left] is already calculated correctly. Update
363 // possible score for every possible new_paritions_left > partitions_left by
364 // aggregating all partitions in between into a single packet.
365 size_t current_payload_len = 0;
366 PartitionScore current_score = scores[partitions_left];
367 // Some next partitions are aggregated into one packet.
368 current_score.num_packets += 1;
369 // Calculate new score for last |new_partitions_left| partitions given
370 // best score for |partitions_left| partitions.
371 for (size_t new_partitions_left = partitions_left + 1;
372 new_partitions_left <= total_partitions; ++new_partitions_left) {
373 current_payload_len +=
374 part_info_.fragmentationLength[end_part - new_partitions_left];
375 if (current_payload_len > capacity)
376 break;
377 // Update maximum packet size.
378 if (current_payload_len > current_score.largest_packet_len)
379 current_score.largest_packet_len = current_payload_len;
380 // Score with less num_packets is better. If equal, minimum largest packet
381 // size is better.
382 if (current_score < scores[new_partitions_left]) {
383 scores[new_partitions_left] = current_score;
384 best_block_size[new_partitions_left] =
385 new_partitions_left - partitions_left;
386 }
387 }
388 }
389 // Undo temporary change.
390 part_info_.fragmentationLength[num_partitions_ - 1] -=
391 last_packet_reduction_len_;
392 // Restore answer given sizes of aggregated blocks in |best_block_size| for
393 // each possible left number of partitions.
394 size_t partitions_left = total_partitions;
395 while (partitions_left > 0) {
396 size_t cur_parts = best_block_size[partitions_left];
397 size_t first_partition = end_part - partitions_left;
398 size_t start_offset = part_info_.fragmentationOffset[first_partition];
399 size_t post_last_partition = first_partition + cur_parts;
400 size_t finish_offset =
401 (post_last_partition < num_partitions_)
402 ? part_info_.fragmentationOffset[post_last_partition]
403 : payload_size_;
404 size_t current_payload_len = finish_offset - start_offset;
405 QueuePacket(start_offset, current_payload_len, first_partition, true);
406 // Go to next packet.
407 partitions_left -= cur_parts;
408 }
409 return end_part;
410 }
411
450 void RtpPacketizerVp8::QueuePacket(size_t start_pos, 412 void RtpPacketizerVp8::QueuePacket(size_t start_pos,
451 size_t packet_size, 413 size_t packet_size,
452 size_t first_partition_in_packet, 414 size_t first_partition_in_packet,
453 bool start_on_new_fragment) { 415 bool start_on_new_fragment) {
454 // Write info to packet info struct and store in packet info queue. 416 // Write info to packet info struct and store in packet info queue.
455 InfoStruct packet_info; 417 InfoStruct packet_info;
456 packet_info.payload_start_pos = start_pos; 418 packet_info.payload_start_pos = start_pos;
457 packet_info.size = packet_size; 419 packet_info.size = packet_size;
458 packet_info.first_partition_ix = first_partition_in_packet; 420 packet_info.first_partition_ix = first_partition_in_packet;
459 packet_info.first_fragment = start_on_new_fragment; 421 packet_info.first_fragment = start_on_new_fragment;
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) != 698 if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) !=
737 0) { 699 0) {
738 return false; 700 return false;
739 } 701 }
740 702
741 parsed_payload->payload = payload_data; 703 parsed_payload->payload = payload_data;
742 parsed_payload->payload_length = payload_data_length; 704 parsed_payload->payload_length = payload_data_length;
743 return true; 705 return true;
744 } 706 }
745 } // namespace webrtc 707 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698