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_framework/normal_test.h" 12 13 #include <sstream> 14 #include <string.h> 15 #include <time.h> 16 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" 19 #include "webrtc/test/testsupport/fileutils.h" 20 21 NormalTest::NormalTest() 22 : 23 CodecTest("Normal Test 1", "A test of normal execution of the codec"), 24 _testNo(1), 25 _lengthEncFrame(0), 26 _appendNext(false) 27 { 28 } 29 30 NormalTest::NormalTest(std::string name, std::string description, 31 unsigned int testNo) 32 : 33 CodecTest(name, description), 34 _requestKeyFrame(false), 35 _testNo(testNo), 36 _lengthEncFrame(0), 37 _appendNext(false) 38 { 39 } 40 41 NormalTest::NormalTest(std::string name, std::string description, 42 uint32_t bitRate, unsigned int testNo) 43 : 44 CodecTest(name, description, bitRate), 45 _requestKeyFrame(false), 46 _testNo(testNo), 47 _lengthEncFrame(0), 48 _appendNext(false) 49 { 50 } 51 52 void 53 NormalTest::Setup() 54 { 55 CodecTest::Setup(); 56 std::stringstream ss; 57 std::string strTestNo; 58 ss << _testNo; 59 ss >> strTestNo; 60 61 // Check if settings exist. Otherwise use defaults. 62 if (_outname == "") 63 { 64 _outname = webrtc::test::OutputPath() + "out_normaltest" + strTestNo + 65 ".yuv"; 66 } 67 68 if (_encodedName == "") 69 { 70 _encodedName = webrtc::test::OutputPath() + "encoded_normaltest" + 71 strTestNo + ".yuv"; 72 } 73 74 if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL) 75 { 76 printf("Cannot read file %s.\n", _inname.c_str()); 77 exit(1); 78 } 79 80 if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL) 81 { 82 printf("Cannot write encoded file.\n"); 83 exit(1); 84 } 85 86 char mode[3] = "wb"; 87 if (_appendNext) 88 { 89 strncpy(mode, "ab", 3); 90 } 91 92 if ((_decodedFile = fopen(_outname.c_str(), mode)) == NULL) 93 { 94 printf("Cannot write file %s.\n", _outname.c_str()); 95 exit(1); 96 } 97 98 _appendNext = true; 99 } 100 101 void 102 NormalTest::Teardown() 103 { 104 CodecTest::Teardown(); 105 fclose(_sourceFile); 106 fclose(_decodedFile); 107 } 108 109 void 110 NormalTest::Perform() 111 { 112 _width = 352; 113 _halfWidth = (_width + 1) / 2; 114 _height = 288; 115 _halfHeight = (_height + 1) / 2; 116 _sizeY = _width * _height; 117 _sizeUv = _halfWidth * _halfHeight; 118 _inname = webrtc::test::ProjectRootPath() + "resources/foreman_cif.yuv"; 119 CodecSettings(_width, _height, 30, _bitRate); 120 Setup(); 121 122 _inputVideoBuffer.CreateEmptyFrame(_width, _height, 123 _width, _halfWidth, _halfWidth); 124 _decodedVideoBuffer.CreateEmptyFrame(_width, _height, 125 _width, _halfWidth, _halfWidth); 126 _encodedVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); 127 128 _encoder->InitEncode(&_inst, 1, 1460); 129 CodecSpecific_InitBitrate(); 130 _decoder->InitDecode(&_inst,1); 131 132 _totalEncodeTime = _totalDecodeTime = 0; 133 _framecnt = 0; 134 _sumEncBytes = 0; 135 _lengthEncFrame = 0; 136 int decodeLength = 0; 137 while (!Encode()) 138 { 139 DoPacketLoss(); 140 _encodedVideoBuffer.SetLength(_encodedVideoBuffer.Length()); 141 if (fwrite(_encodedVideoBuffer.Buffer(), 1, 142 _encodedVideoBuffer.Length(), 143 _encodedFile) != _encodedVideoBuffer.Length()) { 144 return; 145 } 146 decodeLength = Decode(); 147 if (decodeLength < 0) 148 { 149 fprintf(stderr,"\n\nError in decoder: %d\n\n", decodeLength); 150 exit(EXIT_FAILURE); 151 } 152 if (PrintI420VideoFrame(_decodedVideoBuffer, _decodedFile) < 0) { 153 return; 154 } 155 CodecSpecific_InitBitrate(); 156 _framecnt++; 157 } 158 159 // Ensure we empty the decoding queue. 160 while (decodeLength > 0) 161 { 162 decodeLength = Decode(); 163 if (decodeLength < 0) 164 { 165 fprintf(stderr,"\n\nError in decoder: %d\n\n", decodeLength); 166 exit(EXIT_FAILURE); 167 } 168 if (PrintI420VideoFrame(_decodedVideoBuffer, _decodedFile) < 0) { 169 return; 170 } 171 } 172 173 double actualBitRate = ActualBitRate(_framecnt) / 1000.0; 174 double avgEncTime = _totalEncodeTime / _framecnt; 175 double avgDecTime = _totalDecodeTime / _framecnt; 176 printf("Actual bitrate: %f kbps\n", actualBitRate); 177 printf("Average encode time: %f s\n", avgEncTime); 178 printf("Average decode time: %f s\n", avgDecTime); 179 (*_log) << "Actual bitrate: " << actualBitRate << " kbps\tTarget: " << _bitRate << " kbps" << std::endl; 180 (*_log) << "Average encode time: " << avgEncTime << " s" << std::endl; 181 (*_log) << "Average decode time: " << avgDecTime << " s" << std::endl; 182 183 _encoder->Release(); 184 _decoder->Release(); 185 186 Teardown(); 187 } 188 189 bool 190 NormalTest::Encode() 191 { 192 _lengthEncFrame = 0; 193 EXPECT_GT(fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile), 0u); 194 if (feof(_sourceFile) != 0) 195 { 196 return true; 197 } 198 _inputVideoBuffer.CreateFrame(_sizeY, _sourceBuffer, 199 _sizeUv, _sourceBuffer + _sizeY, 200 _sizeUv, _sourceBuffer + _sizeY + 201 _sizeUv, 202 _width, _height, 203 _width, _halfWidth, _halfWidth); 204 _inputVideoBuffer.set_timestamp(_framecnt); 205 206 // This multiple attempt ridiculousness is to accomodate VP7: 207 // 1. The wrapper can unilaterally reduce the framerate for low bitrates. 208 // 2. The codec inexplicably likes to reject some frames. Perhaps there 209 // is a good reason for this... 210 int encodingAttempts = 0; 211 double starttime = 0; 212 double endtime = 0; 213 while (_lengthEncFrame == 0) 214 { 215 starttime = clock()/(double)CLOCKS_PER_SEC; 216 217 _inputVideoBuffer.set_width(_inst.width); 218 _inputVideoBuffer.set_height(_inst.height); 219 endtime = clock()/(double)CLOCKS_PER_SEC; 220 221 _encodedVideoBuffer.SetHeight(_inst.height); 222 _encodedVideoBuffer.SetWidth(_inst.width); 223 if (_lengthEncFrame < 0) 224 { 225 (*_log) << "Error in encoder: " << _lengthEncFrame << std::endl; 226 fprintf(stderr,"\n\nError in encoder: %d\n\n", _lengthEncFrame); 227 exit(EXIT_FAILURE); 228 } 229 _sumEncBytes += _lengthEncFrame; 230 231 encodingAttempts++; 232 if (encodingAttempts > 50) 233 { 234 (*_log) << "Unable to encode frame: " << _framecnt << std::endl; 235 fprintf(stderr,"\n\nUnable to encode frame: %d\n\n", _framecnt); 236 exit(EXIT_FAILURE); 237 } 238 } 239 _totalEncodeTime += endtime - starttime; 240 241 if (encodingAttempts > 1) 242 { 243 (*_log) << encodingAttempts << " attempts required to encode frame: " << 244 _framecnt + 1 << std::endl; 245 fprintf(stderr,"\n%d attempts required to encode frame: %d\n", encodingAttempts, 246 _framecnt + 1); 247 } 248 249 return false; 250 } 251 252 int 253 NormalTest::Decode(int lossValue) 254 { 255 _encodedVideoBuffer.SetWidth(_inst.width); 256 _encodedVideoBuffer.SetHeight(_inst.height); 257 int lengthDecFrame = 0; 258 if (lengthDecFrame < 0) 259 { 260 return lengthDecFrame; 261 } 262 _encodedVideoBuffer.SetLength(0); 263 return lengthDecFrame; 264 } 265