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