Home | History | Annotate | Download | only in test_framework
      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 
     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 
     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 
     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
     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
     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
    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
    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
    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 
    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 
    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 
    244 int PacketLossTest::ByteLoss(int size, unsigned char *pkg, int bytesToLose)
    245 {
    246     return size;
    247 }
    248 
    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