blob: 37da9dbfa9840cda0eef57750290d521411fef88 [file] [log] [blame]
/*
* 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