1 /* 2 * Copyright (c) 2012 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/codecs/test/packet_manipulator.h" 12 13 #include <assert.h> 14 #include <stdio.h> 15 16 #include "webrtc/base/format_macros.h" 17 18 namespace webrtc { 19 namespace test { 20 21 PacketManipulatorImpl::PacketManipulatorImpl(PacketReader* packet_reader, 22 const NetworkingConfig& config, 23 bool verbose) 24 : packet_reader_(packet_reader), 25 config_(config), 26 active_burst_packets_(0), 27 critsect_(CriticalSectionWrapper::CreateCriticalSection()), 28 random_seed_(1), 29 verbose_(verbose) { 30 assert(packet_reader); 31 } 32 33 PacketManipulatorImpl::~PacketManipulatorImpl() { 34 delete critsect_; 35 } 36 37 int PacketManipulatorImpl::ManipulatePackets( 38 webrtc::EncodedImage* encoded_image) { 39 int nbr_packets_dropped = 0; 40 // There's no need to build a copy of the image data since viewing an 41 // EncodedImage object, setting the length to a new lower value represents 42 // that everything is dropped after that position in the byte array. 43 // EncodedImage._size is the allocated bytes. 44 // EncodedImage._length is how many that are filled with data. 45 int new_length = 0; 46 packet_reader_->InitializeReading(encoded_image->_buffer, 47 encoded_image->_length, 48 config_.packet_size_in_bytes); 49 uint8_t* packet = NULL; 50 int nbr_bytes_to_read; 51 // keep track of if we've lost any packets, since then we shall loose 52 // the remains of the current frame: 53 bool packet_loss_has_occurred = false; 54 while ((nbr_bytes_to_read = packet_reader_->NextPacket(&packet)) > 0) { 55 // Check if we're currently in a packet loss burst that is not completed: 56 if (active_burst_packets_ > 0) { 57 active_burst_packets_--; 58 nbr_packets_dropped++; 59 } else if (RandomUniform() < config_.packet_loss_probability || 60 packet_loss_has_occurred) { 61 packet_loss_has_occurred = true; 62 nbr_packets_dropped++; 63 if (config_.packet_loss_mode == kBurst) { 64 // Initiate a new burst 65 active_burst_packets_ = config_.packet_loss_burst_length - 1; 66 } 67 } else { 68 new_length += nbr_bytes_to_read; 69 } 70 } 71 encoded_image->_length = new_length; 72 if (nbr_packets_dropped > 0) { 73 // Must set completeFrame to false to inform the decoder about this: 74 encoded_image->_completeFrame = false; 75 if (verbose_) { 76 printf("Dropped %d packets for frame %d (frame length: %" PRIuS ")\n", 77 nbr_packets_dropped, encoded_image->_timeStamp, 78 encoded_image->_length); 79 } 80 } 81 return nbr_packets_dropped; 82 } 83 84 void PacketManipulatorImpl::InitializeRandomSeed(unsigned int seed) { 85 random_seed_ = seed; 86 } 87 88 inline double PacketManipulatorImpl::RandomUniform() { 89 // Use the previous result as new seed before each rand() call. Doing this 90 // it doesn't matter if other threads are calling rand() since we'll always 91 // get the same behavior as long as we're using a fixed initial seed. 92 critsect_->Enter(); 93 srand(random_seed_); 94 random_seed_ = rand(); // NOLINT (rand_r instead of rand) 95 critsect_->Leave(); 96 return (random_seed_ + 1.0) / (RAND_MAX + 1.0); 97 } 98 99 const char* PacketLossModeToStr(PacketLossMode e) { 100 switch (e) { 101 case kUniform: 102 return "Uniform"; 103 case kBurst: 104 return "Burst"; 105 default: 106 assert(false); 107 return "Unknown"; 108 } 109 } 110 111 } // namespace test 112 } // namespace webrtc 113