/* * 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 #include #include "webrtc/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), critsect_(CriticalSectionWrapper::CreateCriticalSection()), random_seed_(1), verbose_(verbose) { assert(packet_reader); } PacketManipulatorImpl::~PacketManipulatorImpl() { delete critsect_; } 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