2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 // Implementation of Media Optimization Test
12 // testing is done via the VCM module, no specific Media opt functionality.
14 #include "webrtc/modules/video_coding/main/test/media_opt_test.h"
21 #include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
22 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
23 #include "webrtc/modules/video_coding/main/test/test_macros.h"
24 #include "webrtc/modules/video_coding/main/test/test_util.h"
25 #include "webrtc/test/testsupport/fileutils.h"
26 #include "webrtc/test/testsupport/metrics/video_metrics.h"
28 using namespace webrtc;
30 int MediaOptTest::RunTest(int testNum, CmdArgs& args)
33 Trace::SetTraceFile((test::OutputPath() + "mediaOptTestTrace.txt").c_str());
34 Trace::set_level_filter(webrtc::kTraceAll);
35 VideoCodingModule* vcm = VideoCodingModule::Create();
36 Clock* clock = Clock::GetRealTimeClock();
37 MediaOptTest* mot = new MediaOptTest(vcm, clock);
43 mot->Print(1);// print to screen
52 { // release test, running from script
56 mot->Print(1);// print to screen
60 VideoCodingModule::Destroy(vcm);
68 MediaOptTest::MediaOptTest(VideoCodingModule* vcm, Clock* clock)
71 _outgoingTransport(NULL),
76 _lengthSourceFrame(0),
91 MediaOptTest::~MediaOptTest() {
95 void MediaOptTest::Setup(int testType, CmdArgs& args) {
96 /*TEST USER SETTINGS*/
98 _inname = args.inputFile;
99 if (args.outputFile == "")
100 _outname = test::OutputPath() + "MOTest_out.vp8";
102 _outname = args.outputFile;
103 // actual source after frame dropping
104 _actualSourcename = test::OutputPath() + "MOTestSource.yuv";
105 _codecName = args.codecName;
106 _sendCodecType = args.codecType;
108 _height = args.height;
109 _frameRate = args.frameRate;
110 _bitRate = args.bitRate;
114 _nackEnabled = false;
116 _nackFecEnabled = false;
119 _lossRate = 0.00*255; // no packet loss
121 _testType = testType;
123 //For multiple runs with script
126 float rateTest,lossTest;
128 _fpinp = fopen("dat_inp","rb");
129 _fpout = fopen("test_runs/dat_out","ab");
130 _fpout2 = fopen("test_runs/dat_out2","ab");
131 TEST(fscanf(_fpinp,"%f %f %d \n",&rateTest,&lossTest,&numRuns) > 0);
133 _lossRate = lossTest;
136 // for bit rates: 500, 1000, 2000, 3000,4000
137 // for loss rates: 0, 1, 3, 5, 10%
140 _testNum = numRuns + 1;
141 if (rateTest == 0.0) _lossRate = 0.0;
144 if (rateTest == 4000) //final bit rate
146 if (lossTest == 0.1*255) _lossRate = 0.0; //start at 1%
148 if (lossTest == 0.05*255) _lossRate = 0.1*255; //final loss rate
150 if (lossTest == 0.0) _lossRate = 0.01*255;
151 else _lossRate = lossTest + 0.02*255;
155 if (rateTest == 0.0 || rateTest == 4000) _bitRate = 500; //starting bit rate
157 if (rateTest == 500) _bitRate = 1000;
158 else _bitRate = rateTest + 1000;
163 /* test settings end*/
165 _lengthSourceFrame = 3*_width*_height/2;
166 _log.open((test::OutputPath() + "VCM_MediaOptLog.txt").c_str(),
167 std::fstream::out | std::fstream::app);
171 MediaOptTest::GeneralSetup()
173 uint32_t minPlayoutDelayMs = 0;
175 if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
177 printf("Cannot read file %s.\n", _inname.c_str());
181 if ((_decodedFile = fopen(_outname.c_str(), "wb")) == NULL)
183 printf("Cannot read file %s.\n", _outname.c_str());
187 if ((_actualSourceFile = fopen(_actualSourcename.c_str(), "wb")) == NULL)
189 printf("Cannot read file %s.\n", _actualSourcename.c_str());
192 if (_vcm->InitializeReceiver() < 0)
196 if (_vcm->InitializeSender())
200 _outgoingTransport = new RTPSendCompleteCallback(_clock);
201 _dataCallback = new RtpDataCallback(_vcm);
203 RtpRtcp::Configuration configuration;
204 configuration.id = 1;
205 configuration.audio = false;
206 configuration.outgoing_transport = _outgoingTransport;
207 _rtp = RtpRtcp::CreateRtpRtcp(configuration);
209 _outgoingTransport->SetRtpModule(_rtp);
211 // Registering codecs for the RTP module
213 // Register receive and send payload
214 VideoCodec video_codec;
215 strncpy(video_codec.plName, "VP8", 32);
216 video_codec.plType = VCM_VP8_PAYLOAD_TYPE;
217 rtp_receiver_->RegisterReceivePayload(video_codec.plName,
221 video_codec.maxBitrate);
222 _rtp->RegisterSendPayload(video_codec);
224 strncpy(video_codec.plName, "ULPFEC", 32);
225 video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
226 rtp_receiver_->RegisterReceivePayload(video_codec.plName,
230 video_codec.maxBitrate);
231 _rtp->RegisterSendPayload(video_codec);
233 strncpy(video_codec.plName, "RED", 32);
234 video_codec.plType = VCM_RED_PAYLOAD_TYPE;
235 rtp_receiver_->RegisterReceivePayload(video_codec.plName,
239 video_codec.maxBitrate);
240 _rtp->RegisterSendPayload(video_codec);
242 if (_nackFecEnabled == 1)
243 _rtp->SetGenericFECStatus(_nackFecEnabled, VCM_RED_PAYLOAD_TYPE,
244 VCM_ULPFEC_PAYLOAD_TYPE);
246 _rtp->SetGenericFECStatus(_fecEnabled, VCM_RED_PAYLOAD_TYPE,
247 VCM_ULPFEC_PAYLOAD_TYPE);
249 // VCM: Registering codecs
250 VideoCodec sendCodec;
251 _vcm->InitializeSender();
252 _vcm->InitializeReceiver();
253 int32_t numberOfCodecs = _vcm->NumberOfCodecs();
254 if (numberOfCodecs < 1)
259 if (_vcm->Codec(_sendCodecType, &sendCodec) != 0)
261 printf("Unknown codec\n");
265 sendCodec.startBitrate = (int) _bitRate;
266 sendCodec.height = _height;
267 sendCodec.width = _width;
268 sendCodec.maxFramerate = (uint8_t)_frameRate;
269 _vcm->RegisterSendCodec(&sendCodec, _numberOfCores, 1440);
270 _vcm->RegisterReceiveCodec(&sendCodec, _numberOfCores); // same settings for encode and decode
272 _vcm->SetRenderDelay(_renderDelayMs);
273 _vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs);
275 // The following test shall be conducted under release tests
280 MediaOptTest::Perform()
282 VCMDecodeCompleteCallback receiveCallback(_decodedFile);
284 VCMRTPEncodeCompleteCallback* encodeCompleteCallback = new VCMRTPEncodeCompleteCallback(_rtp);
285 _vcm->RegisterTransportCallback(encodeCompleteCallback);
286 encodeCompleteCallback->SetCodecType(ConvertCodecType(_codecName.c_str()));
287 encodeCompleteCallback->SetFrameDimensions(_width, _height);
290 VideoProtectionCallback protectionCallback;
291 protectionCallback.RegisterRtpModule(_rtp);
292 _vcm->RegisterProtectionCallback(&protectionCallback);
294 // set error resilience / test parameters:
295 _outgoingTransport->SetLossPct(_lossRate);
296 if (_nackFecEnabled == 1) {
297 _vcm->SetVideoProtection(kProtectionNackFEC, _nackFecEnabled);
299 _vcm->SetVideoProtection(kProtectionNack, _nackEnabled);
300 _vcm->SetVideoProtection(kProtectionFEC, _fecEnabled);
304 I420VideoFrame sourceFrame;
305 uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
306 _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate),
307 (uint8_t)_lossRate, _rttMS);
308 _vcm->RegisterReceiveCallback(&receiveCallback);
312 _numFramesDropped = 0;
313 int half_width = (_width + 1) / 2;
314 int half_height = (_height + 1) / 2;
315 int size_y = _width * _height;
316 int size_uv = half_width * half_height;
318 while (feof(_sourceFile)== 0)
320 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
322 sourceFrame.CreateFrame(size_y, tmpBuffer,
323 size_uv, tmpBuffer + size_y,
324 size_uv, tmpBuffer + size_y + size_uv,
326 _width, half_width, half_width);
327 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
328 sourceFrame.set_timestamp(_timeStamp);
329 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
330 // inform RTP Module of error resilience features
331 //_rtp->SetFECCodeRate(protectionCallback.FECKeyRate(),protectionCallback.FECDeltaRate());
332 //_rtp->SetNACKStatus(protectionCallback.NACKMethod());
334 int32_t ret = _vcm->Decode();
338 printf ("Decode error in frame # %d",_frameCnt);
341 float encBytes = encodeCompleteCallback->EncodedBytes();
344 _numFramesDropped += 1;
345 //printf("frame #%d dropped \n", _frameCnt );
349 // write frame to file
350 if (PrintI420VideoFrame(sourceFrame, _actualSourceFile) < 0) {
355 _sumEncBytes += encBytes;
359 delete encodeCompleteCallback;
367 MediaOptTest::RTTest()
369 // will only calculate PSNR - not create output files for all
372 const float bitRateVec[] = {500, 1000, 2000,3000, 4000};
373 //const float bitRateVec[] = {1000};
374 // Set Packet loss values ([0,255])
375 const double lossPctVec[] = {0.0*255, 0.0*255, 0.01*255, 0.01*255, 0.03*255, 0.03*255, 0.05*255, 0.05*255, 0.1*255, 0.1*255};
376 const bool nackEnabledVec[] = {false , false, false, false, false, false, false, false , false, false};
377 const bool fecEnabledVec[] = {false , true, false, true , false, true , false, true , false, true};
378 // fec and nack are set according to the packet loss values
380 const float nBitrates = sizeof(bitRateVec)/sizeof(*bitRateVec);
381 const float nlossPct = sizeof(lossPctVec)/sizeof(*lossPctVec);
383 std::vector<const VideoSource*> sources;
384 std::vector<const VideoSource*>::iterator it;
386 sources.push_back(new const VideoSource(_inname, _width, _height));
389 // constant settings (valid for entire run time)
393 // same out name for all
394 _outname = test::OutputPath() + "RTMOTest_out.yuv";
395 // actual source after frame dropping
396 _actualSourcename = test::OutputPath() + "RTMOTestSource.yuv";
398 _codecName = "VP8"; // for now just this one - later iterate over all codec types
399 _log.open((test::OutputPath() + "/VCM_RTMediaOptLog.txt").c_str(),
400 std::fstream::out | std::fstream::app);
401 _outputRes=fopen((test::OutputPath() + "VCM_MediaOptResults.txt").c_str(),
404 //char filename[128];
405 /* test settings end*/
408 // iterate over test sequences
409 printf("\n****START TEST OVER ALL RUNS ****\n");
411 for (it = sources.begin() ; it < sources.end(); it++)
415 _inname = (*it)->GetFileName();
416 _width = (*it)->GetWidth();
417 _height = (*it)->GetHeight();
418 _lengthSourceFrame = 3*_width*_height/2;
419 _frameRate = (*it)->GetFrameRate();
423 // iterate over all bit rates
424 for (int i = 0; i < nBitrates; i++)
426 _bitRate = static_cast<float>(bitRateVec[i]);
427 // iterate over all packet loss values
428 for (int j = 0; j < nlossPct; j++)
430 _lossRate = static_cast<float>(lossPctVec[j]);
431 _nackEnabled = static_cast<bool>(nackEnabledVec[j]);
432 _fecEnabled = static_cast<bool>(fecEnabledVec[j]);
435 printf("run #%d out of %d \n", runCnt,(int)(nlossPct*nBitrates*numOfSrc));
437 //printf("**FOR RUN: **%d %d %d %d \n",_nackEnabled,_fecEnabled,int(lossPctVec[j]),int(_bitRate));
440 int ch = sprintf(filename,"../test_mediaOpt/RTMOTest_%d_%d_%d_%d.yuv",_nackEnabled,_fecEnabled,int(lossPctVec[j]),int(_bitRate));
443 printf("**FOR RUN: **%d %d %d %d \n",_nackEnabled,_fecEnabled,int(lossPctVec[j]),int(_bitRate));
451 //printf("**DONE WITH RUN: **%d %d %f %d \n",_nackEnabled,_fecEnabled,lossPctVec[j],int(_bitRate));
454 }// end of packet loss loop
455 }// end of bit rate loop
457 }// end of video sequence loop
458 // at end of sequence
460 printf("\nVCM Media Optimization Test: \n\n%i tests completed\n", vcmMacrosTests);
461 if (vcmMacrosErrors > 0)
463 printf("%i FAILED\n\n", vcmMacrosErrors);
467 printf("ALL PASSED\n\n");
473 MediaOptTest::Print(int mode)
475 double ActualBitRate = 8.0 *( _sumEncBytes / (_frameCnt / _frameRate));
476 double actualBitRate = ActualBitRate / 1000.0;
477 webrtc::test::QualityMetricsResult psnr;
478 I420PSNRFromFiles(_actualSourcename.c_str(), _outname.c_str(), _width,
481 (_log) << "VCM: Media Optimization Test Cycle Completed!" << std::endl;
482 (_log) << "Input file: " << _inname << std::endl;
483 (_log) << "Output file:" << _outname << std::endl;
484 ( _log) << "Actual bitrate: " << actualBitRate<< " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
485 (_log) << "Error Reslience: NACK:" << _nackEnabled << "; FEC: " << _fecEnabled << std::endl;
486 (_log) << "Packet Loss applied= %f " << _lossRate << std::endl;
487 (_log) << _numFramesDropped << " FRames were dropped" << std::endl;
488 ( _log) << "PSNR: " << psnr.average << std::endl;
493 fprintf(_outputRes,"************\n");
494 fprintf(_outputRes,"\n\n\n");
495 fprintf(_outputRes,"Actual bitrate: %f kbps\n", actualBitRate);
496 fprintf(_outputRes,"Target bitrate: %f kbps\n", _bitRate);
497 fprintf(_outputRes,"NACK: %s ",(_nackEnabled)?"true":"false");
498 fprintf(_outputRes,"FEC: %s \n ",(_fecEnabled)?"true":"false");
499 fprintf(_outputRes,"Packet loss applied = %f\n", _lossRate);
500 fprintf(_outputRes,"%d frames were dropped, and total number of frames processed %d \n",_numFramesDropped,_frameCnt);
501 fprintf(_outputRes,"PSNR: %f \n", psnr.average);
502 fprintf(_outputRes,"************\n");
509 fprintf(_fpout,"************\n");
510 fprintf(_fpout,"\n\n\n");
511 fprintf(_fpout,"Actual bitrate: %f kbps\n", actualBitRate);
512 fprintf(_fpout,"Target bitrate: %f kbps\n", _bitRate);
513 fprintf(_fpout,"NACK: %s ",(_nackEnabled)?"true":"false");
514 fprintf(_fpout,"FEC: %s \n ",(_fecEnabled)?"true":"false");
515 fprintf(_fpout,"Packet loss applied = %f\n", _lossRate);
516 fprintf(_fpout,"%d frames were dropped, and total number of frames processed %d \n",_numFramesDropped,_frameCnt);
517 fprintf(_fpout,"PSNR: %f \n", psnr.average);
518 fprintf(_fpout,"************\n");
520 int testNum1 = _testNum/(_numParRuns +1) + 1;
521 int testNum2 = _testNum%_numParRuns;
522 if (testNum2 == 0) testNum2 = _numParRuns;
523 fprintf(_fpout2,"%d %d %f %f %f %f \n",testNum1,testNum2,_bitRate,actualBitRate,_lossRate,psnr.average);
525 _fpinp = fopen("dat_inp","wb");
526 fprintf(_fpinp,"%f %f %d \n",_bitRate,_lossRate,_testNum);
535 printf("Actual bitrate: %f kbps\n", actualBitRate);
536 printf("Target bitrate: %f kbps\n", _bitRate);
537 printf("NACK: %s ",(_nackEnabled)?"true":"false");
538 printf("FEC: %s \n",(_fecEnabled)?"true":"false");
539 printf("Packet loss applied = %f\n", _lossRate);
540 printf("%d frames were dropped, and total number of frames processed %d \n",_numFramesDropped,_frameCnt);
541 printf("PSNR: %f \n", psnr.average);
543 TEST(psnr.average > 10); // low becuase of possible frame dropping (need to verify that OK for all packet loss values/ rates)
546 void MediaOptTest::TearDown() {
549 delete _outgoingTransport;
550 _outgoingTransport = NULL;
551 delete _dataCallback;
552 _dataCallback = NULL;
555 fclose(_decodedFile);
556 fclose(_actualSourceFile);