• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <assert.h>
12 #include <string.h>
13 
14 #include <sstream>
15 
16 #include "webrtc/modules/video_coding/codecs/test_framework/packet_loss_test.h"
17 #include "webrtc/modules/video_coding/codecs/test_framework/video_source.h"
18 
19 using namespace webrtc;
20 
PacketLossTest()21 PacketLossTest::PacketLossTest()
22 :
23 NormalAsyncTest("PacketLossTest", "Encode, remove lost packets, decode", 300,
24                 5),
25 _lossRate(0.1),
26 _lossProbability(0.1),
27 _lastFrame(NULL),
28 _lastFrameLength(0)
29 {
30 }
31 
PacketLossTest(std::string name,std::string description)32 PacketLossTest::PacketLossTest(std::string name, std::string description)
33 :
34 NormalAsyncTest(name, description, 300, 5),
35 _lossRate(0.1),
36 _lossProbability(0.1),
37 _lastFrame(NULL),
38 _lastFrameLength(0)
39 {
40 }
41 
PacketLossTest(std::string name,std::string description,double lossRate,bool useNack,unsigned int rttFrames)42 PacketLossTest::PacketLossTest(std::string name, std::string description, double lossRate, bool useNack, unsigned int rttFrames /* = 0*/)
43 :
44 NormalAsyncTest(name, description, 300, 5, rttFrames),
45 _lossRate(lossRate),
46 _lastFrame(NULL),
47 _lastFrameLength(0)
48 {
49     assert(lossRate >= 0 && lossRate <= 1);
50     if (useNack)
51     {
52         _lossProbability = 0;
53     }
54     else
55     {
56         _lossProbability = lossRate;
57     }
58 }
59 
60 void
Encoded(const EncodedImage & encodedImage)61 PacketLossTest::Encoded(const EncodedImage& encodedImage)
62 {
63     // push timestamp to queue
64     _frameQueue.push_back(encodedImage._timeStamp);
65     NormalAsyncTest::Encoded(encodedImage);
66 }
67 
68 void
Decoded(const I420VideoFrame & decodedImage)69 PacketLossTest::Decoded(const I420VideoFrame& decodedImage)
70 {
71     // check the frame queue if any frames have gone missing
72     assert(!_frameQueue.empty()); // decoded frame is not in the queue
73     while(_frameQueue.front() < decodedImage.timestamp())
74     {
75         // this frame is missing
76         // write previous decoded frame again (frame freeze)
77         if (_decodedFile && _lastFrame)
78         {
79           if (fwrite(_lastFrame, 1, _lastFrameLength,
80                      _decodedFile) != _lastFrameLength) {
81             return;
82           }
83         }
84 
85         // remove frame from queue
86         _frameQueue.pop_front();
87     }
88     // Decoded frame is not in the queue.
89     assert(_frameQueue.front() == decodedImage.timestamp());
90 
91     // pop the current frame
92     _frameQueue.pop_front();
93 
94     // save image for future freeze-frame
95     unsigned int length = CalcBufferSize(kI420, decodedImage.width(),
96                                          decodedImage.height());
97     if (_lastFrameLength < length)
98     {
99         if (_lastFrame) delete [] _lastFrame;
100 
101         _lastFrame = new uint8_t[length];
102     }
103     // TODO(mikhal): Can't the last frame be a I420VideoFrame?
104     ExtractBuffer(decodedImage, length, _lastFrame);
105     _lastFrameLength = length;
106 
107     NormalAsyncTest::Decoded(decodedImage);
108 }
109 
110 void
Teardown()111 PacketLossTest::Teardown()
112 {
113     if (_totalKept + _totalThrown > 0)
114     {
115         printf("Target packet loss rate: %.4f\n", _lossProbability);
116         printf("Actual packet loss rate: %.4f\n", (_totalThrown * 1.0f) / (_totalKept + _totalThrown));
117         printf("Channel rate: %.2f kbps\n",
118             0.001 * 8.0 * _sumChannelBytes / ((_framecnt * 1.0f) / _inst.maxFramerate));
119     }
120     else
121     {
122         printf("No packet losses inflicted\n");
123     }
124 
125     NormalAsyncTest::Teardown();
126 }
127 
128 void
Setup()129 PacketLossTest::Setup()
130 {
131     const VideoSource source(_inname, _inst.width, _inst.height, _inst.maxFramerate);
132 
133     std::stringstream ss;
134     std::string lossRateStr;
135     ss << _lossRate;
136     ss >> lossRateStr;
137     _encodedName = source.GetName() + "-" + lossRateStr;
138     _outname = "out-" + source.GetName() + "-" + lossRateStr;
139 
140     if (_lossProbability != _lossRate)
141     {
142         _encodedName += "-nack";
143         _outname += "-nack";
144     }
145     _encodedName += ".vp8";
146     _outname += ".yuv";
147 
148     _totalKept = 0;
149     _totalThrown = 0;
150     _sumChannelBytes = 0;
151 
152     NormalAsyncTest::Setup();
153 }
154 
155 void
CodecSpecific_InitBitrate()156 PacketLossTest::CodecSpecific_InitBitrate()
157 {
158     assert(_bitRate > 0);
159     uint32_t simulatedBitRate;
160     if (_lossProbability != _lossRate)
161     {
162         // Simulating NACK
163         simulatedBitRate = uint32_t(_bitRate / (1 + _lossRate));
164     }
165     else
166     {
167         simulatedBitRate = _bitRate;
168     }
169     int rtt = 0;
170     if (_inst.maxFramerate > 0)
171       rtt = _rttFrames * (1000 / _inst.maxFramerate);
172     _encoder->SetChannelParameters((uint32_t)(_lossProbability * 255.0),
173                                                     rtt);
174     _encoder->SetRates(simulatedBitRate, _inst.maxFramerate);
175 }
176 
DoPacketLoss()177 int PacketLossTest::DoPacketLoss()
178 {
179     // Only packet loss for delta frames
180     // TODO(mikhal): Identify delta frames
181     // First frame so never a delta frame.
182     if (_frameToDecode->_frame->Length() == 0 || _sumChannelBytes == 0)
183     {
184         _sumChannelBytes += _frameToDecode->_frame->Length();
185         return 0;
186     }
187     unsigned char *packet = NULL;
188     VideoFrame newEncBuf;
189     newEncBuf.VerifyAndAllocate(_lengthSourceFrame);
190     _inBufIdx = 0;
191     _outBufIdx = 0;
192     int size = 1;
193     int kept = 0;
194     int thrown = 0;
195     while ((size = NextPacket(1500, &packet)) > 0)
196     {
197         if (!PacketLoss(_lossProbability, thrown))
198         {
199             InsertPacket(&newEncBuf, packet, size);
200             kept++;
201         }
202         else
203         {
204             // Use the ByteLoss function if you want to lose only
205             // parts of a packet, and not the whole packet.
206 
207             //int size2 = ByteLoss(size, packet, 15);
208             thrown++;
209             //if (size2 != size)
210             //{
211             //    InsertPacket(&newEncBuf, packet, size2);
212             //}
213         }
214     }
215     int	lossResult  = (thrown!=0);	// 0 = no loss	1 = loss(es)
216     if (lossResult)
217     {
218         lossResult += (kept==0);	// 2 = all lost = full frame
219     }
220     _frameToDecode->_frame->CopyFrame(newEncBuf.Length(), newEncBuf.Buffer());
221     _sumChannelBytes += newEncBuf.Length();
222     _totalKept += kept;
223     _totalThrown += thrown;
224 
225     return lossResult;
226     //printf("Threw away: %d out of %d packets\n", thrown, thrown + kept);
227     //printf("Encoded left: %d bytes\n", _encodedVideoBuffer.Length());
228 }
229 
NextPacket(int mtu,unsigned char ** pkg)230 int PacketLossTest::NextPacket(int mtu, unsigned char **pkg)
231 {
232     unsigned char *buf = _frameToDecode->_frame->Buffer();
233     *pkg = buf + _inBufIdx;
234     if (static_cast<long>(_frameToDecode->_frame->Length()) - _inBufIdx <= mtu)
235     {
236         int size = _frameToDecode->_frame->Length() - _inBufIdx;
237         _inBufIdx = _frameToDecode->_frame->Length();
238         return size;
239     }
240     _inBufIdx += mtu;
241     return mtu;
242 }
243 
ByteLoss(int size,unsigned char * pkg,int bytesToLose)244 int PacketLossTest::ByteLoss(int size, unsigned char *pkg, int bytesToLose)
245 {
246     return size;
247 }
248 
InsertPacket(VideoFrame * buf,unsigned char * pkg,int size)249 void PacketLossTest::InsertPacket(VideoFrame *buf, unsigned char *pkg, int size)
250 {
251     if (static_cast<long>(buf->Size()) - _outBufIdx < size)
252     {
253         printf("InsertPacket error!\n");
254         return;
255     }
256     memcpy(buf->Buffer() + _outBufIdx, pkg, size);
257     buf->SetLength(buf->Length() + size);
258     _outBufIdx += size;
259 }
260