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