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/main/test/generic_codec_test.h" 12 13 #include <math.h> 14 #include <stdio.h> 15 16 #include "webrtc/common_video/interface/i420_video_frame.h" 17 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" 18 #include "webrtc/modules/video_coding/main/interface/video_coding.h" 19 #include "webrtc/modules/video_coding/main/test/test_macros.h" 20 #include "webrtc/system_wrappers/interface/clock.h" 21 #include "webrtc/test/testsupport/fileutils.h" 22 23 using namespace webrtc; 24 25 enum { kMaxWaitEncTimeMs = 100 }; 26 27 int GenericCodecTest::RunTest(CmdArgs& args) 28 { 29 SimulatedClock clock(0); 30 NullEventFactory event_factory; 31 VideoCodingModule* vcm = VideoCodingModule::Create(&clock, &event_factory); 32 GenericCodecTest* get = new GenericCodecTest(vcm, &clock); 33 Trace::CreateTrace(); 34 Trace::SetTraceFile( 35 (test::OutputPath() + "genericCodecTestTrace.txt").c_str()); 36 Trace::set_level_filter(webrtc::kTraceAll); 37 get->Perform(args); 38 Trace::ReturnTrace(); 39 delete get; 40 VideoCodingModule::Destroy(vcm); 41 return 0; 42 } 43 44 GenericCodecTest::GenericCodecTest(VideoCodingModule* vcm, 45 SimulatedClock* clock): 46 _clock(clock), 47 _vcm(vcm), 48 _width(0), 49 _height(0), 50 _frameRate(0), 51 _lengthSourceFrame(0), 52 _timeStamp(0) 53 { 54 } 55 56 GenericCodecTest::~GenericCodecTest() 57 { 58 } 59 60 void 61 GenericCodecTest::Setup(CmdArgs& args) 62 { 63 _timeStamp = 0; 64 65 /* Test Sequence parameters */ 66 67 _inname= args.inputFile; 68 if (args.outputFile.compare("")) 69 _outname = test::OutputPath() + "GCTest_decoded.yuv"; 70 else 71 _outname = args.outputFile; 72 _encodedName = test::OutputPath() + "GCTest_encoded.vp8"; 73 _width = args.width; 74 _height = args.height; 75 _frameRate = args.frameRate; 76 _lengthSourceFrame = 3*_width*_height/2; 77 78 /* File settings */ 79 80 if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL) 81 { 82 printf("Cannot read file %s.\n", _inname.c_str()); 83 exit(1); 84 } 85 if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL) 86 { 87 printf("Cannot write encoded file.\n"); 88 exit(1); 89 } 90 if ((_decodedFile = fopen(_outname.c_str(), "wb")) == NULL) 91 { 92 printf("Cannot write file %s.\n", _outname.c_str()); 93 exit(1); 94 } 95 96 return; 97 } 98 int32_t 99 GenericCodecTest::Perform(CmdArgs& args) 100 { 101 int32_t ret; 102 Setup(args); 103 /* 104 1. sanity checks 105 2. encode/decoder individuality 106 3. API testing 107 4. Target bitrate (within a specific timespan) 108 5. Pipeline Delay 109 */ 110 111 /*******************************/ 112 /* sanity checks on inputs */ 113 /*****************************/ 114 VideoCodec sendCodec, receiveCodec; 115 sendCodec.maxBitrate = 8000; 116 TEST(_vcm->NumberOfCodecs() > 0); // This works since we now initialize the list in the constructor 117 TEST(_vcm->Codec(0, &sendCodec) == VCM_OK); 118 _vcm->InitializeSender(); 119 _vcm->InitializeReceiver(); 120 int32_t NumberOfCodecs = _vcm->NumberOfCodecs(); 121 // registration of first codec in the list 122 int i = 0; 123 _vcm->Codec(0, &_sendCodec); 124 TEST(_vcm->RegisterSendCodec(&_sendCodec, 4, 1440) == VCM_OK); 125 // sanity on encoder registration 126 I420VideoFrame sourceFrame; 127 _vcm->InitializeSender(); 128 TEST(_vcm->Codec(kVideoCodecVP8, &sendCodec) == 0); 129 TEST(_vcm->RegisterSendCodec(&sendCodec, -1, 1440) < 0); // bad number of cores 130 sendCodec.maxBitrate = 8000; 131 _vcm->RegisterSendCodec(&sendCodec, 1, 1440); 132 _vcm->InitializeSender(); 133 _vcm->Codec(kVideoCodecVP8, &sendCodec); 134 sendCodec.height = 0; 135 TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0); // bad height 136 _vcm->Codec(kVideoCodecVP8, &sendCodec); 137 sendCodec.startBitrate = -2; 138 TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0); // bad bit rate 139 _vcm->Codec(kVideoCodecVP8, &sendCodec); 140 _vcm->InitializeSender(); 141 // Setting rate when encoder uninitialized. 142 TEST(_vcm->SetChannelParameters(100000, 0, 0) < 0); 143 // register all availbale decoders -- need to have more for this test 144 for (i=0; i< NumberOfCodecs; i++) 145 { 146 _vcm->Codec(i, &receiveCodec); 147 _vcm->RegisterReceiveCodec(&receiveCodec, 1); 148 } 149 uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame]; 150 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0); 151 int half_width = (_width + 1) / 2; 152 int half_height = (_height + 1) / 2; 153 int size_y = _width * _height; 154 int size_uv = half_width * half_height; 155 sourceFrame.CreateFrame(size_y, tmpBuffer, 156 size_uv, tmpBuffer + size_y, 157 size_uv, tmpBuffer + size_y + size_uv, 158 _width, _height, 159 _width, half_width, half_width); 160 sourceFrame.set_timestamp(_timeStamp++); 161 TEST(_vcm->AddVideoFrame(sourceFrame) < 0 ); // encoder uninitialized 162 _vcm->InitializeReceiver(); 163 // Setting rtt when receiver uninitialized. 164 TEST(_vcm->SetChannelParameters(100000, 0, 0) < 0); 165 166 /**************************************/ 167 /* encoder/decoder individuality test */ 168 /**************************************/ 169 //Register both encoder and decoder, reset decoder - encode, set up decoder, reset encoder - decode. 170 rewind(_sourceFile); 171 _vcm->InitializeReceiver(); 172 _vcm->InitializeSender(); 173 NumberOfCodecs = _vcm->NumberOfCodecs(); 174 // Register VP8 175 _vcm->Codec(kVideoCodecVP8, &_sendCodec); 176 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440); 177 _vcm->SendCodec(&sendCodec); 178 sendCodec.startBitrate = 2000; 179 180 // Set target frame rate to half of the incoming frame rate 181 // to test the frame rate control in the VCM 182 sendCodec.maxFramerate = (uint8_t)(_frameRate / 2); 183 sendCodec.width = _width; 184 sendCodec.height = _height; 185 TEST(strncmp(_sendCodec.plName, "VP8", 3) == 0); // was VP8 186 187 _decodeCallback = new VCMDecodeCompleteCallback(_decodedFile); 188 _encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile); 189 _vcm->RegisterReceiveCallback(_decodeCallback); 190 _vcm->RegisterTransportCallback(_encodeCompleteCallback); 191 _encodeCompleteCallback->RegisterReceiverVCM(_vcm); 192 193 _vcm->RegisterSendCodec(&sendCodec, 4, 1440); 194 _encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName)); 195 196 _vcm->InitializeReceiver(); 197 _vcm->Process(); 198 199 //encoding 1 second of video 200 for (i = 0; i < _frameRate; i++) 201 { 202 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0); 203 sourceFrame.CreateFrame(size_y, tmpBuffer, 204 size_uv, tmpBuffer + size_y, 205 size_uv, tmpBuffer + size_y + size_uv, 206 _width, _height, 207 _width, half_width, half_width); 208 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate)); 209 sourceFrame.set_timestamp(_timeStamp); 210 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK); 211 IncrementDebugClock(_frameRate); 212 _vcm->Process(); 213 } 214 sendCodec.maxFramerate = (uint8_t)_frameRate; 215 _vcm->InitializeSender(); 216 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK); // same codec for encode and decode 217 ret = 0; 218 i = 0; 219 while ((i < 25) && (ret == 0) ) 220 { 221 ret = _vcm->Decode(); 222 TEST(ret == VCM_OK); 223 if (ret < 0) 224 { 225 printf("error in frame # %d \n", i); 226 } 227 IncrementDebugClock(_frameRate); 228 i++; 229 } 230 //TEST((ret == 0) && (i = 50)); 231 if (ret == 0) 232 { 233 printf("Encoder/Decoder individuality test complete - View output files \n"); 234 } 235 // last frame - not decoded 236 _vcm->InitializeReceiver(); 237 TEST(_vcm->Decode() < 0); // frame to be encoded exists, decoder uninitialized 238 239 240 // Test key frame request on packet loss mode. 241 // This a frame as a key frame and fooling the receiver 242 // that the last packet was lost. The decoding will succeed, 243 // but the VCM will see a packet loss and request a new key frame. 244 VCMEncComplete_KeyReqTest keyReqTest_EncCompleteCallback(*_vcm); 245 KeyFrameReqTest frameTypeCallback; 246 _vcm->RegisterTransportCallback(&keyReqTest_EncCompleteCallback); 247 _encodeCompleteCallback->RegisterReceiverVCM(_vcm); 248 _vcm->RegisterSendCodec(&sendCodec, 4, 1440); 249 _encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName)); 250 TEST(_vcm->SetVideoProtection(kProtectionKeyOnKeyLoss, true) == VCM_OK); 251 TEST(_vcm->RegisterFrameTypeCallback(&frameTypeCallback) == VCM_OK); 252 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK); 253 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK); 254 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate)); 255 sourceFrame.set_timestamp(_timeStamp); 256 // First packet of a subsequent frame required before the jitter buffer 257 // will allow decoding an incomplete frame. 258 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK); 259 TEST(_vcm->Decode() == VCM_OK); 260 261 printf("API tests complete \n"); 262 263 /*******************/ 264 /* Bit Rate Tests */ 265 /*****************/ 266 /* Requirements: 267 * 1. OneSecReq = 15 % above/below target over a time period of 1s (_frameRate number of frames) 268 * 3. FullReq = 10% for total seq. (for 300 frames/seq. coincides with #1) 269 * 4. Test will go over all registered codecs 270 //NOTE: time requirements are not part of the release tests 271 */ 272 double FullReq = 0.1; 273 //double OneSecReq = 0.15; 274 printf("\n RATE CONTROL TEST\n"); 275 // initializing.... 276 _vcm->InitializeSender(); 277 _vcm->InitializeReceiver(); 278 rewind(_sourceFile); 279 sourceFrame.CreateEmptyFrame(_width, _height, _width, 280 (_width + 1) / 2, (_width + 1) / 2); 281 const float bitRate[] = {100, 400, 600, 1000, 2000}; 282 const float nBitrates = sizeof(bitRate)/sizeof(*bitRate); 283 float _bitRate = 0; 284 int _frameCnt = 0; 285 float totalBytesOneSec;//, totalBytesTenSec; 286 float totalBytes, actualBitrate; 287 VCMFrameCount frameCount; // testing frame type counters 288 // start test 289 NumberOfCodecs = _vcm->NumberOfCodecs(); 290 // going over all available codecs 291 _encodeCompleteCallback->SetFrameDimensions(_width, _height); 292 SendStatsTest sendStats; 293 for (int k = 0; k < NumberOfCodecs; k++) 294 //for (int k = NumberOfCodecs - 1; k >=0; k--) 295 {// static list starts from 0 296 //just checking 297 _vcm->InitializeSender(); 298 _sendCodec.maxBitrate = 8000; 299 TEST(_vcm->Codec(k, &_sendCodec)== VCM_OK); 300 _vcm->RegisterSendCodec(&_sendCodec, 1, 1440); 301 _vcm->RegisterTransportCallback(_encodeCompleteCallback); 302 _encodeCompleteCallback->SetCodecType(ConvertCodecType(_sendCodec.plName)); 303 printf (" \n\n Codec type = %s \n\n",_sendCodec.plName); 304 for (i = 0; i < nBitrates; i++) 305 { 306 _bitRate = static_cast<float>(bitRate[i]); 307 // just testing 308 _vcm->InitializeSender(); 309 _sendCodec.startBitrate = (int)_bitRate; 310 _sendCodec.maxBitrate = 8000; 311 _sendCodec.maxFramerate = _frameRate; 312 _vcm->RegisterSendCodec(&_sendCodec, 1, 1440); 313 _vcm->RegisterTransportCallback(_encodeCompleteCallback); 314 // up to here 315 _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 316 0, 20); 317 _frameCnt = 0; 318 totalBytes = 0; 319 _encodeCompleteCallback->Initialize(); 320 sendStats.set_framerate(static_cast<uint32_t>(_frameRate)); 321 sendStats.set_bitrate(1000 * _bitRate); 322 _vcm->RegisterSendStatisticsCallback(&sendStats); 323 while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) == 324 _lengthSourceFrame) 325 { 326 _frameCnt++; 327 sourceFrame.CreateFrame(size_y, tmpBuffer, 328 size_uv, tmpBuffer + size_y, 329 size_uv, tmpBuffer + size_y + size_uv, 330 _width, _height, 331 _width, (_width + 1) / 2, 332 (_width + 1) / 2); 333 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate)); 334 sourceFrame.set_timestamp(_timeStamp); 335 336 ret = _vcm->AddVideoFrame(sourceFrame); 337 IncrementDebugClock(_frameRate); 338 // The following should be uncommneted for timing tests. Release tests only include 339 // compliance with full sequence bit rate. 340 if (_frameCnt == _frameRate)// @ 1sec 341 { 342 totalBytesOneSec = _encodeCompleteCallback->EncodedBytes();//totalBytes; 343 } 344 TEST(_vcm->TimeUntilNextProcess() >= 0); 345 } // video seq. encode done 346 TEST(_vcm->TimeUntilNextProcess() == 0); 347 _vcm->Process(); // Let the module calculate its send bit rate estimate 348 // estimating rates 349 // complete sequence 350 // bit rate assumes input frame rate is as specified 351 totalBytes = _encodeCompleteCallback->EncodedBytes(); 352 actualBitrate = (float)(8.0/1000)*(totalBytes / (_frameCnt / _frameRate)); 353 354 printf("Complete Seq.: target bitrate: %.0f kbps, actual bitrate: %.1f kbps\n", _bitRate, actualBitrate); 355 TEST((fabs(actualBitrate - _bitRate) < FullReq * _bitRate) || 356 (strncmp(_sendCodec.plName, "I420", 4) == 0)); 357 358 // 1 Sec. 359 actualBitrate = (float)(8.0/1000)*(totalBytesOneSec); 360 //actualBitrate = (float)(8.0*totalBytesOneSec)/(oneSecTime - startTime); 361 //printf("First 1Sec: target bitrate: %.0f kbps, actual bitrate: %.1f kbps\n", _bitRate, actualBitrate); 362 //TEST(fabs(actualBitrate - _bitRate) < OneSecReq * _bitRate); 363 rewind(_sourceFile); 364 365 //checking key/delta frame count 366 _vcm->SentFrameCount(frameCount); 367 printf("frame count: %d delta, %d key\n", frameCount.numDeltaFrames, frameCount.numKeyFrames); 368 }// end per codec 369 370 } // end rate control test 371 /********************************/ 372 /* Encoder Pipeline Delay Test */ 373 /******************************/ 374 _vcm->InitializeSender(); 375 NumberOfCodecs = _vcm->NumberOfCodecs(); 376 bool encodeComplete = false; 377 // going over all available codecs 378 for (int k = 0; k < NumberOfCodecs; k++) 379 { 380 _vcm->Codec(k, &_sendCodec); 381 _vcm->InitializeSender(); 382 _sendCodec.maxBitrate = 8000; 383 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440); 384 _vcm->RegisterTransportCallback(_encodeCompleteCallback); 385 386 _frameCnt = 0; 387 encodeComplete = false; 388 while (encodeComplete == false) 389 { 390 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0); 391 _frameCnt++; 392 sourceFrame.CreateFrame(size_y, tmpBuffer, 393 size_uv, tmpBuffer + size_y, 394 size_uv, tmpBuffer + size_y + size_uv, 395 _width, _height, 396 _width, half_width, half_width); 397 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate)); 398 sourceFrame.set_timestamp(_timeStamp); 399 _vcm->AddVideoFrame(sourceFrame); 400 encodeComplete = _encodeCompleteCallback->EncodeComplete(); 401 } // first frame encoded 402 printf ("\n Codec type = %s \n", _sendCodec.plName); 403 printf(" Encoder pipeline delay = %d frames\n", _frameCnt - 1); 404 } // end for all codecs 405 406 /********************************/ 407 /* Encoder Packet Size Test */ 408 /********************************/ 409 RTPSendCallback_SizeTest sendCallback; 410 411 RtpRtcp::Configuration configuration; 412 configuration.id = 1; 413 configuration.audio = false; 414 configuration.outgoing_transport = &sendCallback; 415 416 RtpRtcp& rtpModule = *RtpRtcp::CreateRtpRtcp(configuration); 417 418 VCMRTPEncodeCompleteCallback encCompleteCallback(&rtpModule); 419 _vcm->InitializeSender(); 420 421 // Test temporal decimation settings 422 for (int k = 0; k < NumberOfCodecs; k++) 423 { 424 _vcm->Codec(k, &_sendCodec); 425 if (strncmp(_sendCodec.plName, "I420", 4) == 0) 426 { 427 // Only test with I420 428 break; 429 } 430 } 431 TEST(strncmp(_sendCodec.plName, "I420", 4) == 0); 432 _vcm->InitializeSender(); 433 _sendCodec.maxFramerate = static_cast<uint8_t>(_frameRate / 2.0 + 0.5f); 434 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440); 435 _vcm->SetChannelParameters(2000000, 0, 0); 436 _vcm->RegisterTransportCallback(_encodeCompleteCallback); 437 // up to here 438 _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 0, 20); 439 _encodeCompleteCallback->Initialize(); 440 sendStats.set_framerate(static_cast<uint32_t>(_frameRate)); 441 sendStats.set_bitrate(1000 * _bitRate); 442 _vcm->RegisterSendStatisticsCallback(&sendStats); 443 rewind(_sourceFile); 444 while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) == 445 _lengthSourceFrame) { 446 sourceFrame.CreateFrame(size_y, tmpBuffer, 447 size_uv, tmpBuffer + size_y, 448 size_uv, tmpBuffer + size_y + size_uv, 449 _width, _height, 450 _width, half_width, half_width); 451 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate)); 452 sourceFrame.set_timestamp(_timeStamp); 453 ret = _vcm->AddVideoFrame(sourceFrame); 454 if (_vcm->TimeUntilNextProcess() <= 0) 455 { 456 _vcm->Process(); 457 } 458 IncrementDebugClock(_frameRate); 459 } // first frame encoded 460 461 delete &rtpModule; 462 Print(); 463 delete tmpBuffer; 464 delete _decodeCallback; 465 delete _encodeCompleteCallback; 466 return 0; 467 } 468 469 470 void 471 GenericCodecTest::Print() 472 { 473 printf(" \n\n VCM Generic Encoder Test: \n\n%i tests completed\n", vcmMacrosTests); 474 if (vcmMacrosErrors > 0) 475 { 476 printf("%i FAILED\n\n", vcmMacrosErrors); 477 } 478 else 479 { 480 printf("ALL PASSED\n\n"); 481 } 482 } 483 484 float 485 GenericCodecTest::WaitForEncodedFrame() const 486 { 487 int64_t startTime = _clock->TimeInMilliseconds(); 488 while (_clock->TimeInMilliseconds() - startTime < kMaxWaitEncTimeMs*10) 489 { 490 if (_encodeCompleteCallback->EncodeComplete()) 491 { 492 return _encodeCompleteCallback->EncodedBytes(); 493 } 494 } 495 return 0; 496 } 497 498 void 499 GenericCodecTest::IncrementDebugClock(float frameRate) 500 { 501 _clock->AdvanceTimeMilliseconds(1000/frameRate); 502 } 503 504 int 505 RTPSendCallback_SizeTest::SendPacket(int channel, const void *data, int len) 506 { 507 _nPackets++; 508 _payloadSizeSum += len; 509 // Make sure no payloads (len - header size) are larger than maxPayloadSize 510 TEST(len > 0 && static_cast<uint32_t>(len - 12) <= _maxPayloadSize); 511 return 0; 512 } 513 514 void 515 RTPSendCallback_SizeTest::SetMaxPayloadSize(uint32_t maxPayloadSize) 516 { 517 _maxPayloadSize = maxPayloadSize; 518 } 519 520 void 521 RTPSendCallback_SizeTest::Reset() 522 { 523 _nPackets = 0; 524 _payloadSizeSum = 0; 525 } 526 527 float 528 RTPSendCallback_SizeTest::AveragePayloadSize() const 529 { 530 if (_nPackets > 0) 531 { 532 return _payloadSizeSum / static_cast<float>(_nPackets); 533 } 534 return 0; 535 } 536 537 int32_t 538 VCMEncComplete_KeyReqTest::SendData( 539 const FrameType frameType, 540 const uint8_t payloadType, 541 const uint32_t timeStamp, 542 int64_t capture_time_ms, 543 const uint8_t* payloadData, 544 const uint32_t payloadSize, 545 const RTPFragmentationHeader& /*fragmentationHeader*/, 546 const webrtc::RTPVideoHeader* /*videoHdr*/) 547 { 548 WebRtcRTPHeader rtpInfo; 549 rtpInfo.header.markerBit = true; // end of frame 550 rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8(); 551 rtpInfo.type.Video.codec = kRtpVideoVp8; 552 rtpInfo.header.payloadType = payloadType; 553 rtpInfo.header.sequenceNumber = _seqNo; 554 _seqNo += 2; 555 rtpInfo.header.ssrc = 0; 556 rtpInfo.header.timestamp = _timeStamp; 557 _timeStamp += 3000; 558 rtpInfo.type.Video.isFirstPacket = false; 559 rtpInfo.frameType = kVideoFrameKey; 560 return _vcm.IncomingPacket(payloadData, payloadSize, rtpInfo); 561 } 562