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
PacketManipulatorImpl(PacketReader * packet_reader,const NetworkingConfig & config,bool verbose)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
~PacketManipulatorImpl()33 PacketManipulatorImpl::~PacketManipulatorImpl() {
34 delete critsect_;
35 }
36
ManipulatePackets(webrtc::EncodedImage * encoded_image)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
InitializeRandomSeed(unsigned int seed)84 void PacketManipulatorImpl::InitializeRandomSeed(unsigned int seed) {
85 random_seed_ = seed;
86 }
87
RandomUniform()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
PacketLossModeToStr(PacketLossMode e)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