| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h" |
| |
| #include <assert.h> |
| #include <stdio.h> |
| |
| #include "webrtc/rtc_base/format_macros.h" |
| |
| namespace webrtc { |
| namespace test { |
| |
| PacketManipulatorImpl::PacketManipulatorImpl(PacketReader* packet_reader, |
| const NetworkingConfig& config, |
| bool verbose) |
| : packet_reader_(packet_reader), |
| config_(config), |
| active_burst_packets_(0), |
| random_seed_(1), |
| verbose_(verbose) { |
| assert(packet_reader); |
| } |
| |
| int PacketManipulatorImpl::ManipulatePackets( |
| webrtc::EncodedImage* encoded_image) { |
| int nbr_packets_dropped = 0; |
| // There's no need to build a copy of the image data since viewing an |
| // EncodedImage object, setting the length to a new lower value represents |
| // that everything is dropped after that position in the byte array. |
| // EncodedImage._size is the allocated bytes. |
| // EncodedImage._length is how many that are filled with data. |
| int new_length = 0; |
| packet_reader_->InitializeReading(encoded_image->_buffer, |
| encoded_image->_length, |
| config_.packet_size_in_bytes); |
| uint8_t* packet = NULL; |
| int nbr_bytes_to_read; |
| // keep track of if we've lost any packets, since then we shall loose |
| // the remains of the current frame: |
| bool packet_loss_has_occurred = false; |
| while ((nbr_bytes_to_read = packet_reader_->NextPacket(&packet)) > 0) { |
| // Check if we're currently in a packet loss burst that is not completed: |
| if (active_burst_packets_ > 0) { |
| active_burst_packets_--; |
| nbr_packets_dropped++; |
| } else if (RandomUniform() < config_.packet_loss_probability || |
| packet_loss_has_occurred) { |
| packet_loss_has_occurred = true; |
| nbr_packets_dropped++; |
| if (config_.packet_loss_mode == kBurst) { |
| // Initiate a new burst |
| active_burst_packets_ = config_.packet_loss_burst_length - 1; |
| } |
| } else { |
| new_length += nbr_bytes_to_read; |
| } |
| } |
| encoded_image->_length = new_length; |
| if (nbr_packets_dropped > 0) { |
| // Must set completeFrame to false to inform the decoder about this: |
| encoded_image->_completeFrame = false; |
| if (verbose_) { |
| printf("Dropped %d packets for frame %d (frame length: %" PRIuS ")\n", |
| nbr_packets_dropped, encoded_image->_timeStamp, |
| encoded_image->_length); |
| } |
| } |
| return nbr_packets_dropped; |
| } |
| |
| void PacketManipulatorImpl::InitializeRandomSeed(unsigned int seed) { |
| random_seed_ = seed; |
| } |
| |
| inline double PacketManipulatorImpl::RandomUniform() { |
| // Use the previous result as new seed before each rand() call. Doing this |
| // it doesn't matter if other threads are calling rand() since we'll always |
| // get the same behavior as long as we're using a fixed initial seed. |
| critsect_.Enter(); |
| srand(random_seed_); |
| random_seed_ = rand(); // NOLINT (rand_r instead of rand) |
| critsect_.Leave(); |
| return (random_seed_ + 1.0) / (RAND_MAX + 1.0); |
| } |
| |
| const char* PacketLossModeToStr(PacketLossMode e) { |
| switch (e) { |
| case kUniform: |
| return "Uniform"; |
| case kBurst: |
| return "Burst"; |
| default: |
| assert(false); |
| return "Unknown"; |
| } |
| } |
| |
| } // namespace test |
| } // namespace webrtc |