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_async_test.h" 12 13 #include <assert.h> 14 #include <queue> 15 #include <sstream> 16 #include <string.h> 17 #include <vector> 18 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" 21 #include "webrtc/system_wrappers/interface/tick_util.h" 22 #include "webrtc/test/testsupport/fileutils.h" 23 #include "webrtc/typedefs.h" 24 25 using namespace webrtc; 26 27 NormalAsyncTest::NormalAsyncTest() 28 : 29 NormalTest("Async Normal Test 1", "A test of normal execution of the codec", 1), 30 _decodeCompleteTime(0), 31 _encodeCompleteTime(0), 32 _encFrameCnt(0), 33 _decFrameCnt(0), 34 _requestKeyFrame(false), 35 _appendNext(false), 36 _missingFrames(false), 37 _rttFrames(0), 38 _hasReceivedSLI(false), 39 _hasReceivedRPSI(false), 40 _hasReceivedPLI(false), 41 _waitForKey(false) 42 { 43 } 44 45 NormalAsyncTest::NormalAsyncTest(uint32_t bitRate) 46 : 47 NormalTest("Async Normal Test 1", "A test of normal execution of the codec", 48 bitRate, 49 1), 50 _decodeCompleteTime(0), 51 _encodeCompleteTime(0), 52 _encFrameCnt(0), 53 _decFrameCnt(0), 54 _requestKeyFrame(false), 55 _appendNext(false), 56 _missingFrames(false), 57 _rttFrames(0), 58 _hasReceivedSLI(false), 59 _hasReceivedRPSI(false), 60 _hasReceivedPLI(false), 61 _waitForKey(false) 62 { 63 } 64 65 NormalAsyncTest::NormalAsyncTest(std::string name, std::string description, 66 unsigned int testNo) 67 : 68 NormalTest(name, description, testNo), 69 _decodeCompleteTime(0), 70 _encodeCompleteTime(0), 71 _encFrameCnt(0), 72 _decFrameCnt(0), 73 _requestKeyFrame(false), 74 _lengthEncFrame(0), 75 _appendNext(false), 76 _missingFrames(false), 77 _rttFrames(0), 78 _hasReceivedSLI(false), 79 _hasReceivedRPSI(false), 80 _hasReceivedPLI(false), 81 _waitForKey(false) 82 { 83 } 84 85 NormalAsyncTest::NormalAsyncTest(std::string name, std::string description, 86 uint32_t bitRate, unsigned int testNo) 87 : 88 NormalTest(name, description, bitRate, testNo), 89 _decodeCompleteTime(0), 90 _encodeCompleteTime(0), 91 _encFrameCnt(0), 92 _decFrameCnt(0), 93 _requestKeyFrame(false), 94 _lengthEncFrame(0), 95 _appendNext(false), 96 _missingFrames(false), 97 _rttFrames(0), 98 _hasReceivedSLI(false), 99 _hasReceivedRPSI(false), 100 _hasReceivedPLI(false), 101 _waitForKey(false) 102 { 103 } 104 105 NormalAsyncTest::NormalAsyncTest(std::string name, std::string description, 106 uint32_t bitRate, unsigned int testNo, 107 unsigned int rttFrames) 108 : 109 NormalTest(name, description, bitRate, testNo), 110 _decodeCompleteTime(0), 111 _encodeCompleteTime(0), 112 _encFrameCnt(0), 113 _decFrameCnt(0), 114 _requestKeyFrame(false), 115 _lengthEncFrame(0), 116 _appendNext(false), 117 _missingFrames(false), 118 _rttFrames(rttFrames), 119 _hasReceivedSLI(false), 120 _hasReceivedRPSI(false), 121 _hasReceivedPLI(false), 122 _waitForKey(false) 123 { 124 } 125 126 void 127 NormalAsyncTest::Setup() 128 { 129 CodecTest::Setup(); 130 std::stringstream ss; 131 std::string strTestNo; 132 ss << _testNo; 133 ss >> strTestNo; 134 135 // Check if settings exist. Otherwise use defaults. 136 if (_outname == "") 137 { 138 _outname = webrtc::test::OutputPath() + "out_normaltest" + strTestNo + 139 ".yuv"; 140 } 141 142 if (_encodedName == "") 143 { 144 _encodedName = webrtc::test::OutputPath() + "encoded_normaltest" + 145 strTestNo + ".yuv"; 146 } 147 148 if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL) 149 { 150 printf("Cannot read file %s.\n", _inname.c_str()); 151 exit(1); 152 } 153 154 if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL) 155 { 156 printf("Cannot write encoded file.\n"); 157 exit(1); 158 } 159 160 char mode[3] = "wb"; 161 if (_appendNext) 162 { 163 strncpy(mode, "ab", 3); 164 } 165 166 if ((_decodedFile = fopen(_outname.c_str(), mode)) == NULL) 167 { 168 printf("Cannot write file %s.\n", _outname.c_str()); 169 exit(1); 170 } 171 172 _appendNext = true; 173 } 174 175 void 176 NormalAsyncTest::Teardown() 177 { 178 CodecTest::Teardown(); 179 fclose(_sourceFile); 180 fclose(_encodedFile); 181 fclose(_decodedFile); 182 } 183 184 FrameQueueTuple::~FrameQueueTuple() 185 { 186 if (_codecSpecificInfo != NULL) 187 { 188 delete _codecSpecificInfo; 189 } 190 if (_frame != NULL) 191 { 192 delete _frame; 193 } 194 } 195 196 void FrameQueue::PushFrame(VideoFrame *frame, 197 webrtc::CodecSpecificInfo* codecSpecificInfo) 198 { 199 WriteLockScoped cs(_queueRWLock); 200 _frameBufferQueue.push(new FrameQueueTuple(frame, codecSpecificInfo)); 201 } 202 203 FrameQueueTuple* FrameQueue::PopFrame() 204 { 205 WriteLockScoped cs(_queueRWLock); 206 if (_frameBufferQueue.empty()) 207 { 208 return NULL; 209 } 210 FrameQueueTuple* tuple = _frameBufferQueue.front(); 211 _frameBufferQueue.pop(); 212 return tuple; 213 } 214 215 bool FrameQueue::Empty() 216 { 217 ReadLockScoped cs(_queueRWLock); 218 return _frameBufferQueue.empty(); 219 } 220 221 uint32_t VideoEncodeCompleteCallback::EncodedBytes() 222 { 223 return _encodedBytes; 224 } 225 226 int32_t 227 VideoEncodeCompleteCallback::Encoded(EncodedImage& encodedImage, 228 const webrtc::CodecSpecificInfo* codecSpecificInfo, 229 const webrtc::RTPFragmentationHeader* 230 fragmentation) 231 { 232 _test.Encoded(encodedImage); 233 VideoFrame *newBuffer = new VideoFrame(); 234 newBuffer->VerifyAndAllocate(encodedImage._size); 235 _encodedBytes += encodedImage._length; 236 // If _frameQueue would have been a fixed sized buffer we could have asked 237 // it for an empty frame and then just do: 238 // emptyFrame->SwapBuffers(encodedBuffer); 239 // This is how it should be done in Video Engine to save in on memcpys 240 webrtc::CodecSpecificInfo* codecSpecificInfoCopy = 241 _test.CopyCodecSpecificInfo(codecSpecificInfo); 242 _test.CopyEncodedImage(*newBuffer, encodedImage, codecSpecificInfoCopy); 243 if (_encodedFile != NULL) 244 { 245 if (fwrite(newBuffer->Buffer(), 1, newBuffer->Length(), 246 _encodedFile) != newBuffer->Length()) { 247 return -1; 248 } 249 } 250 _frameQueue->PushFrame(newBuffer, codecSpecificInfoCopy); 251 return 0; 252 } 253 254 uint32_t VideoDecodeCompleteCallback::DecodedBytes() 255 { 256 return _decodedBytes; 257 } 258 259 int32_t 260 VideoDecodeCompleteCallback::Decoded(I420VideoFrame& image) 261 { 262 _test.Decoded(image); 263 _decodedBytes += CalcBufferSize(kI420, image.width(), image.height()); 264 if (_decodedFile != NULL) 265 { 266 return PrintI420VideoFrame(image, _decodedFile); 267 } 268 return 0; 269 } 270 271 int32_t 272 VideoDecodeCompleteCallback::ReceivedDecodedReferenceFrame( 273 const uint64_t pictureId) 274 { 275 return _test.ReceivedDecodedReferenceFrame(pictureId); 276 } 277 278 int32_t 279 VideoDecodeCompleteCallback::ReceivedDecodedFrame( 280 const uint64_t pictureId) 281 { 282 return _test.ReceivedDecodedFrame(pictureId); 283 } 284 285 void 286 NormalAsyncTest::Encoded(const EncodedImage& encodedImage) 287 { 288 _encodeCompleteTime = tGetTime(); 289 _encFrameCnt++; 290 _totalEncodePipeTime += _encodeCompleteTime - 291 _encodeTimes[encodedImage._timeStamp]; 292 } 293 294 void 295 NormalAsyncTest::Decoded(const I420VideoFrame& decodedImage) 296 { 297 _decodeCompleteTime = tGetTime(); 298 _decFrameCnt++; 299 _totalDecodePipeTime += _decodeCompleteTime - 300 _decodeTimes[decodedImage.timestamp()]; 301 _decodedWidth = decodedImage.width(); 302 _decodedHeight = decodedImage.height(); 303 } 304 305 void 306 NormalAsyncTest::Perform() 307 { 308 _inname = webrtc::test::ProjectRootPath() + "resources/foreman_cif.yuv"; 309 CodecSettings(352, 288, 30, _bitRate); 310 Setup(); 311 if(_encoder->InitEncode(&_inst, 1, 1440) < 0) 312 { 313 exit(EXIT_FAILURE); 314 } 315 _decoder->InitDecode(&_inst, 1); 316 FrameQueue frameQueue; 317 VideoEncodeCompleteCallback encCallback(_encodedFile, &frameQueue, *this); 318 VideoDecodeCompleteCallback decCallback(_decodedFile, *this); 319 _encoder->RegisterEncodeCompleteCallback(&encCallback); 320 _decoder->RegisterDecodeCompleteCallback(&decCallback); 321 if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) 322 { 323 exit(EXIT_FAILURE); 324 } 325 _totalEncodeTime = _totalDecodeTime = 0; 326 _totalEncodePipeTime = _totalDecodePipeTime = 0; 327 bool complete = false; 328 _framecnt = 0; 329 _encFrameCnt = 0; 330 _decFrameCnt = 0; 331 _sumEncBytes = 0; 332 _lengthEncFrame = 0; 333 double starttime = tGetTime(); 334 while (!complete) 335 { 336 CodecSpecific_InitBitrate(); 337 complete = Encode(); 338 if (!frameQueue.Empty() || complete) 339 { 340 while (!frameQueue.Empty()) 341 { 342 _frameToDecode = 343 static_cast<FrameQueueTuple *>(frameQueue.PopFrame()); 344 int lost = DoPacketLoss(); 345 if (lost == 2) 346 { 347 // Lost the whole frame, continue 348 _missingFrames = true; 349 delete _frameToDecode; 350 _frameToDecode = NULL; 351 continue; 352 } 353 int ret = Decode(lost); 354 delete _frameToDecode; 355 _frameToDecode = NULL; 356 if (ret < 0) 357 { 358 fprintf(stderr,"\n\nError in decoder: %d\n\n", ret); 359 exit(EXIT_FAILURE); 360 } 361 else if (ret == 0) 362 { 363 _framecnt++; 364 } 365 else 366 { 367 fprintf(stderr, 368 "\n\nPositive return value from decode!\n\n"); 369 } 370 } 371 } 372 } 373 double endtime = tGetTime(); 374 double totalExecutionTime = endtime - starttime; 375 printf("Total execution time: %.1f s\n", totalExecutionTime); 376 _sumEncBytes = encCallback.EncodedBytes(); 377 double actualBitRate = ActualBitRate(_encFrameCnt) / 1000.0; 378 double avgEncTime = _totalEncodeTime / _encFrameCnt; 379 double avgDecTime = _totalDecodeTime / _decFrameCnt; 380 printf("Actual bitrate: %f kbps\n", actualBitRate); 381 printf("Average encode time: %.1f ms\n", 1000 * avgEncTime); 382 printf("Average decode time: %.1f ms\n", 1000 * avgDecTime); 383 printf("Average encode pipeline time: %.1f ms\n", 384 1000 * _totalEncodePipeTime / _encFrameCnt); 385 printf("Average decode pipeline time: %.1f ms\n", 386 1000 * _totalDecodePipeTime / _decFrameCnt); 387 printf("Number of encoded frames: %u\n", _encFrameCnt); 388 printf("Number of decoded frames: %u\n", _decFrameCnt); 389 (*_log) << "Actual bitrate: " << actualBitRate << " kbps\tTarget: " << 390 _bitRate << " kbps" << std::endl; 391 (*_log) << "Average encode time: " << avgEncTime << " s" << std::endl; 392 (*_log) << "Average decode time: " << avgDecTime << " s" << std::endl; 393 _encoder->Release(); 394 _decoder->Release(); 395 Teardown(); 396 } 397 398 bool 399 NormalAsyncTest::Encode() 400 { 401 _lengthEncFrame = 0; 402 if (feof(_sourceFile) != 0) 403 { 404 return true; 405 } 406 EXPECT_GT(fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile), 0u); 407 EXPECT_EQ(0, _inputVideoBuffer.CreateFrame(_sizeY, _sourceBuffer, 408 _sizeUv, _sourceBuffer + _sizeY, 409 _sizeUv, _sourceBuffer + _sizeY + _sizeUv, 410 _width, _height, 411 _width, _halfWidth, _halfWidth)); 412 _inputVideoBuffer.set_timestamp((unsigned int) 413 (_encFrameCnt * 9e4 / _inst.maxFramerate)); 414 _encodeCompleteTime = 0; 415 _encodeTimes[_inputVideoBuffer.timestamp()] = tGetTime(); 416 std::vector<VideoFrameType> frame_types(1, kDeltaFrame); 417 418 // check SLI queue 419 _hasReceivedSLI = false; 420 while (!_signalSLI.empty() && _signalSLI.front().delay == 0) 421 { 422 // SLI message has arrived at sender side 423 _hasReceivedSLI = true; 424 _pictureIdSLI = _signalSLI.front().id; 425 _signalSLI.pop_front(); 426 } 427 // decrement SLI queue times 428 for (std::list<fbSignal>::iterator it = _signalSLI.begin(); 429 it !=_signalSLI.end(); it++) 430 { 431 (*it).delay--; 432 } 433 434 // check PLI queue 435 _hasReceivedPLI = false; 436 while (!_signalPLI.empty() && _signalPLI.front().delay == 0) 437 { 438 // PLI message has arrived at sender side 439 _hasReceivedPLI = true; 440 _signalPLI.pop_front(); 441 } 442 // decrement PLI queue times 443 for (std::list<fbSignal>::iterator it = _signalPLI.begin(); 444 it != _signalPLI.end(); it++) 445 { 446 (*it).delay--; 447 } 448 449 if (_hasReceivedPLI) 450 { 451 // respond to PLI by encoding a key frame 452 frame_types[0] = kKeyFrame; 453 _hasReceivedPLI = false; 454 _hasReceivedSLI = false; // don't trigger both at once 455 } 456 457 webrtc::CodecSpecificInfo* codecSpecificInfo = CreateEncoderSpecificInfo(); 458 int ret = _encoder->Encode(_inputVideoBuffer, 459 codecSpecificInfo, &frame_types); 460 EXPECT_EQ(ret, WEBRTC_VIDEO_CODEC_OK); 461 if (codecSpecificInfo != NULL) 462 { 463 delete codecSpecificInfo; 464 codecSpecificInfo = NULL; 465 } 466 if (_encodeCompleteTime > 0) 467 { 468 _totalEncodeTime += _encodeCompleteTime - 469 _encodeTimes[_inputVideoBuffer.timestamp()]; 470 } 471 else 472 { 473 _totalEncodeTime += tGetTime() - 474 _encodeTimes[_inputVideoBuffer.timestamp()]; 475 } 476 assert(ret >= 0); 477 return false; 478 } 479 480 int 481 NormalAsyncTest::Decode(int lossValue) 482 { 483 _sumEncBytes += _frameToDecode->_frame->Length(); 484 EncodedImage encodedImage; 485 VideoEncodedBufferToEncodedImage(*(_frameToDecode->_frame), encodedImage); 486 encodedImage._completeFrame = !lossValue; 487 _decodeCompleteTime = 0; 488 _decodeTimes[encodedImage._timeStamp] = tGetTime(); 489 int ret = WEBRTC_VIDEO_CODEC_OK; 490 // TODO(mikhal): Update frame type. 491 //if (!_waitForKey || encodedImage._frameType == kKeyFrame) 492 { 493 _waitForKey = false; 494 ret = _decoder->Decode(encodedImage, _missingFrames, NULL, 495 _frameToDecode->_codecSpecificInfo); 496 497 if (ret >= 0) 498 { 499 _missingFrames = false; 500 } 501 } 502 503 // check for SLI 504 if (ret == WEBRTC_VIDEO_CODEC_REQUEST_SLI) 505 { 506 // add an SLI feedback to the feedback "queue" 507 // to be delivered to encoder with _rttFrames delay 508 _signalSLI.push_back(fbSignal(_rttFrames, 509 static_cast<uint8_t>((_lastDecPictureId) & 0x3f))); // 6 lsb 510 511 ret = WEBRTC_VIDEO_CODEC_OK; 512 } 513 else if (ret == WEBRTC_VIDEO_CODEC_ERR_REQUEST_SLI) 514 { 515 // add an SLI feedback to the feedback "queue" 516 // to be delivered to encoder with _rttFrames delay 517 _signalSLI.push_back(fbSignal(_rttFrames, 518 static_cast<uint8_t>((_lastDecPictureId + 1) & 0x3f)));//6 lsb 519 520 ret = WEBRTC_VIDEO_CODEC_OK; 521 } 522 else if (ret == WEBRTC_VIDEO_CODEC_ERROR) 523 { 524 // wait for new key frame 525 // add an PLI feedback to the feedback "queue" 526 // to be delivered to encoder with _rttFrames delay 527 _signalPLI.push_back(fbSignal(_rttFrames, 0 /* picId not used*/)); 528 _waitForKey = true; 529 530 ret = WEBRTC_VIDEO_CODEC_OK; 531 } 532 533 if (_decodeCompleteTime > 0) 534 { 535 _totalDecodeTime += _decodeCompleteTime - 536 _decodeTimes[encodedImage._timeStamp]; 537 } 538 else 539 { 540 _totalDecodeTime += tGetTime() - _decodeTimes[encodedImage._timeStamp]; 541 } 542 return ret; 543 } 544 545 webrtc::CodecSpecificInfo* 546 NormalAsyncTest::CopyCodecSpecificInfo( 547 const webrtc::CodecSpecificInfo* codecSpecificInfo) const 548 { 549 webrtc::CodecSpecificInfo* info = new webrtc::CodecSpecificInfo; 550 *info = *codecSpecificInfo; 551 return info; 552 } 553 554 void NormalAsyncTest::CodecSpecific_InitBitrate() 555 { 556 if (_bitRate == 0) 557 { 558 _encoder->SetRates(600, _inst.maxFramerate); 559 } 560 else 561 { 562 _encoder->SetRates(_bitRate, _inst.maxFramerate); 563 } 564 } 565 566 void NormalAsyncTest::CopyEncodedImage(VideoFrame& dest, 567 EncodedImage& src, 568 void* /*codecSpecificInfo*/) const 569 { 570 dest.CopyFrame(src._length, src._buffer); 571 //dest.SetFrameType(src._frameType); 572 dest.SetWidth((uint16_t)src._encodedWidth); 573 dest.SetHeight((uint16_t)src._encodedHeight); 574 dest.SetTimeStamp(src._timeStamp); 575 } 576 577 int32_t NormalAsyncTest::ReceivedDecodedReferenceFrame( 578 const uint64_t pictureId) { 579 _lastDecRefPictureId = pictureId; 580 return 0; 581 } 582 583 int32_t NormalAsyncTest::ReceivedDecodedFrame( 584 const uint64_t pictureId) { 585 _lastDecPictureId = pictureId; 586 return 0; 587 } 588 589 double 590 NormalAsyncTest::tGetTime() 591 {// return time in sec 592 return ((double) (TickTime::MillisecondTimestamp())/1000); 593 } 594