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 #include "webrtc/modules/video_coding/main/test/generic_codec_test.h"
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"
23 using namespace webrtc;
25 enum { kMaxWaitEncTimeMs = 100 };
27 int GenericCodecTest::RunTest(CmdArgs& args)
29 SimulatedClock clock(0);
30 NullEventFactory event_factory;
31 VideoCodingModule* vcm = VideoCodingModule::Create(&clock, &event_factory);
32 GenericCodecTest* get = new GenericCodecTest(vcm, &clock);
35 (test::OutputPath() + "genericCodecTestTrace.txt").c_str());
36 Trace::set_level_filter(webrtc::kTraceAll);
40 VideoCodingModule::Destroy(vcm);
44 GenericCodecTest::GenericCodecTest(VideoCodingModule* vcm,
45 SimulatedClock* clock):
51 _lengthSourceFrame(0),
56 GenericCodecTest::~GenericCodecTest()
61 GenericCodecTest::Setup(CmdArgs& args)
65 /* Test Sequence parameters */
67 _inname= args.inputFile;
68 if (args.outputFile.compare(""))
69 _outname = test::OutputPath() + "GCTest_decoded.yuv";
71 _outname = args.outputFile;
72 _encodedName = test::OutputPath() + "GCTest_encoded.vp8";
74 _height = args.height;
75 _frameRate = args.frameRate;
76 _lengthSourceFrame = 3*_width*_height/2;
80 if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
82 printf("Cannot read file %s.\n", _inname.c_str());
85 if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
87 printf("Cannot write encoded file.\n");
90 if ((_decodedFile = fopen(_outname.c_str(), "wb")) == NULL)
92 printf("Cannot write file %s.\n", _outname.c_str());
99 GenericCodecTest::Perform(CmdArgs& args)
105 2. encode/decoder individuality
107 4. Target bitrate (within a specific timespan)
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
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 sendCodec.maxBitrate = 8000;
130 _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
131 _vcm->InitializeSender();
132 _vcm->Codec(kVideoCodecVP8, &sendCodec);
133 sendCodec.height = 0;
134 TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0); // bad height
135 _vcm->Codec(kVideoCodecVP8, &sendCodec);
136 _vcm->Codec(kVideoCodecVP8, &sendCodec);
137 _vcm->InitializeSender();
138 // Setting rate when encoder uninitialized.
139 TEST(_vcm->SetChannelParameters(100000, 0, 0) < 0);
140 // register all availbale decoders -- need to have more for this test
141 for (i=0; i< NumberOfCodecs; i++)
143 _vcm->Codec(i, &receiveCodec);
144 _vcm->RegisterReceiveCodec(&receiveCodec, 1);
146 uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
147 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
148 int half_width = (_width + 1) / 2;
149 int half_height = (_height + 1) / 2;
150 int size_y = _width * _height;
151 int size_uv = half_width * half_height;
152 sourceFrame.CreateFrame(size_y, tmpBuffer,
153 size_uv, tmpBuffer + size_y,
154 size_uv, tmpBuffer + size_y + size_uv,
156 _width, half_width, half_width);
157 sourceFrame.set_timestamp(_timeStamp++);
158 TEST(_vcm->AddVideoFrame(sourceFrame) < 0 ); // encoder uninitialized
159 _vcm->InitializeReceiver();
160 // Setting rtt when receiver uninitialized.
161 TEST(_vcm->SetChannelParameters(100000, 0, 0) < 0);
163 /**************************************/
164 /* encoder/decoder individuality test */
165 /**************************************/
166 //Register both encoder and decoder, reset decoder - encode, set up decoder, reset encoder - decode.
168 _vcm->InitializeReceiver();
169 _vcm->InitializeSender();
170 NumberOfCodecs = _vcm->NumberOfCodecs();
172 _vcm->Codec(kVideoCodecVP8, &_sendCodec);
173 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
174 _vcm->SendCodec(&sendCodec);
175 sendCodec.startBitrate = 2000;
177 // Set target frame rate to half of the incoming frame rate
178 // to test the frame rate control in the VCM
179 sendCodec.maxFramerate = (uint8_t)(_frameRate / 2);
180 sendCodec.width = _width;
181 sendCodec.height = _height;
182 TEST(strncmp(_sendCodec.plName, "VP8", 3) == 0); // was VP8
184 _decodeCallback = new VCMDecodeCompleteCallback(_decodedFile);
185 _encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile);
186 _vcm->RegisterReceiveCallback(_decodeCallback);
187 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
188 _encodeCompleteCallback->RegisterReceiverVCM(_vcm);
190 _vcm->RegisterSendCodec(&sendCodec, 4, 1440);
191 _encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName));
193 _vcm->InitializeReceiver();
196 //encoding 1 second of video
197 for (i = 0; i < _frameRate; i++)
199 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
200 sourceFrame.CreateFrame(size_y, tmpBuffer,
201 size_uv, tmpBuffer + size_y,
202 size_uv, tmpBuffer + size_y + size_uv,
204 _width, half_width, half_width);
205 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
206 sourceFrame.set_timestamp(_timeStamp);
207 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
208 IncrementDebugClock(_frameRate);
211 sendCodec.maxFramerate = (uint8_t)_frameRate;
212 _vcm->InitializeSender();
213 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK); // same codec for encode and decode
216 while ((i < 25) && (ret == 0) )
218 ret = _vcm->Decode();
222 printf("error in frame # %d \n", i);
224 IncrementDebugClock(_frameRate);
227 //TEST((ret == 0) && (i = 50));
230 printf("Encoder/Decoder individuality test complete - View output files \n");
232 // last frame - not decoded
233 _vcm->InitializeReceiver();
234 TEST(_vcm->Decode() < 0); // frame to be encoded exists, decoder uninitialized
237 // Test key frame request on packet loss mode.
238 // This a frame as a key frame and fooling the receiver
239 // that the last packet was lost. The decoding will succeed,
240 // but the VCM will see a packet loss and request a new key frame.
241 VCMEncComplete_KeyReqTest keyReqTest_EncCompleteCallback(*_vcm);
242 KeyFrameReqTest frameTypeCallback;
243 _vcm->RegisterTransportCallback(&keyReqTest_EncCompleteCallback);
244 _encodeCompleteCallback->RegisterReceiverVCM(_vcm);
245 _vcm->RegisterSendCodec(&sendCodec, 4, 1440);
246 _encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName));
247 TEST(_vcm->SetVideoProtection(kProtectionKeyOnKeyLoss, true) == VCM_OK);
248 TEST(_vcm->RegisterFrameTypeCallback(&frameTypeCallback) == VCM_OK);
249 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
250 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
251 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
252 sourceFrame.set_timestamp(_timeStamp);
253 // First packet of a subsequent frame required before the jitter buffer
254 // will allow decoding an incomplete frame.
255 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
256 TEST(_vcm->Decode() == VCM_OK);
258 printf("API tests complete \n");
260 /*******************/
264 * 1. OneSecReq = 15 % above/below target over a time period of 1s (_frameRate number of frames)
265 * 3. FullReq = 10% for total seq. (for 300 frames/seq. coincides with #1)
266 * 4. Test will go over all registered codecs
267 //NOTE: time requirements are not part of the release tests
269 double FullReq = 0.1;
270 //double OneSecReq = 0.15;
271 printf("\n RATE CONTROL TEST\n");
273 _vcm->InitializeSender();
274 _vcm->InitializeReceiver();
276 sourceFrame.CreateEmptyFrame(_width, _height, _width,
277 (_width + 1) / 2, (_width + 1) / 2);
278 const float bitRate[] = {100, 400, 600, 1000, 2000};
279 const float nBitrates = sizeof(bitRate)/sizeof(*bitRate);
282 float totalBytesOneSec = 0;//, totalBytesTenSec;
283 float totalBytes, actualBitrate;
284 VCMFrameCount frameCount; // testing frame type counters
286 NumberOfCodecs = _vcm->NumberOfCodecs();
287 // going over all available codecs
288 _encodeCompleteCallback->SetFrameDimensions(_width, _height);
289 SendStatsTest sendStats;
290 for (int k = 0; k < NumberOfCodecs; k++)
291 //for (int k = NumberOfCodecs - 1; k >=0; k--)
292 {// static list starts from 0
294 _vcm->InitializeSender();
295 _sendCodec.maxBitrate = 8000;
296 TEST(_vcm->Codec(k, &_sendCodec)== VCM_OK);
297 _vcm->RegisterSendCodec(&_sendCodec, 1, 1440);
298 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
299 _encodeCompleteCallback->SetCodecType(ConvertCodecType(_sendCodec.plName));
300 printf (" \n\n Codec type = %s \n\n",_sendCodec.plName);
301 for (i = 0; i < nBitrates; i++)
303 _bitRate = static_cast<float>(bitRate[i]);
305 _vcm->InitializeSender();
306 _sendCodec.startBitrate = (int)_bitRate;
307 _sendCodec.maxBitrate = 8000;
308 _sendCodec.maxFramerate = _frameRate;
309 _vcm->RegisterSendCodec(&_sendCodec, 1, 1440);
310 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
312 _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate),
316 _encodeCompleteCallback->Initialize();
317 sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
318 sendStats.set_bitrate(1000 * _bitRate);
319 _vcm->RegisterSendStatisticsCallback(&sendStats);
320 while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) ==
324 sourceFrame.CreateFrame(size_y, tmpBuffer,
325 size_uv, tmpBuffer + size_y,
326 size_uv, tmpBuffer + size_y + size_uv,
328 _width, (_width + 1) / 2,
330 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
331 sourceFrame.set_timestamp(_timeStamp);
333 ret = _vcm->AddVideoFrame(sourceFrame);
334 IncrementDebugClock(_frameRate);
335 // The following should be uncommneted for timing tests. Release tests only include
336 // compliance with full sequence bit rate.
337 if (_frameCnt == _frameRate)// @ 1sec
339 totalBytesOneSec = _encodeCompleteCallback->EncodedBytes();//totalBytes;
341 TEST(_vcm->TimeUntilNextProcess() >= 0);
342 } // video seq. encode done
343 TEST(_vcm->TimeUntilNextProcess() == 0);
344 _vcm->Process(); // Let the module calculate its send bit rate estimate
347 // bit rate assumes input frame rate is as specified
348 totalBytes = _encodeCompleteCallback->EncodedBytes();
349 actualBitrate = (float)(8.0/1000)*(totalBytes / (_frameCnt / _frameRate));
351 printf("Complete Seq.: target bitrate: %.0f kbps, actual bitrate: %.1f kbps\n", _bitRate, actualBitrate);
352 TEST((fabs(actualBitrate - _bitRate) < FullReq * _bitRate) ||
353 (strncmp(_sendCodec.plName, "I420", 4) == 0));
356 actualBitrate = (float)(8.0/1000)*(totalBytesOneSec);
357 //actualBitrate = (float)(8.0*totalBytesOneSec)/(oneSecTime - startTime);
358 //printf("First 1Sec: target bitrate: %.0f kbps, actual bitrate: %.1f kbps\n", _bitRate, actualBitrate);
359 //TEST(fabs(actualBitrate - _bitRate) < OneSecReq * _bitRate);
362 //checking key/delta frame count
363 _vcm->SentFrameCount(frameCount);
364 printf("frame count: %d delta, %d key\n", frameCount.numDeltaFrames, frameCount.numKeyFrames);
367 } // end rate control test
368 /********************************/
369 /* Encoder Pipeline Delay Test */
370 /******************************/
371 _vcm->InitializeSender();
372 NumberOfCodecs = _vcm->NumberOfCodecs();
373 bool encodeComplete = false;
374 // going over all available codecs
375 for (int k = 0; k < NumberOfCodecs; k++)
377 _vcm->Codec(k, &_sendCodec);
378 _vcm->InitializeSender();
379 _sendCodec.maxBitrate = 8000;
380 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
381 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
384 encodeComplete = false;
385 while (encodeComplete == false)
387 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
389 sourceFrame.CreateFrame(size_y, tmpBuffer,
390 size_uv, tmpBuffer + size_y,
391 size_uv, tmpBuffer + size_y + size_uv,
393 _width, half_width, half_width);
394 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
395 sourceFrame.set_timestamp(_timeStamp);
396 _vcm->AddVideoFrame(sourceFrame);
397 encodeComplete = _encodeCompleteCallback->EncodeComplete();
398 } // first frame encoded
399 printf ("\n Codec type = %s \n", _sendCodec.plName);
400 printf(" Encoder pipeline delay = %d frames\n", _frameCnt - 1);
401 } // end for all codecs
403 /********************************/
404 /* Encoder Packet Size Test */
405 /********************************/
406 RTPSendCallback_SizeTest sendCallback;
408 RtpRtcp::Configuration configuration;
409 configuration.id = 1;
410 configuration.audio = false;
411 configuration.outgoing_transport = &sendCallback;
413 RtpRtcp& rtpModule = *RtpRtcp::CreateRtpRtcp(configuration);
415 VCMRTPEncodeCompleteCallback encCompleteCallback(&rtpModule);
416 _vcm->InitializeSender();
418 // Test temporal decimation settings
419 for (int k = 0; k < NumberOfCodecs; k++)
421 _vcm->Codec(k, &_sendCodec);
422 if (strncmp(_sendCodec.plName, "I420", 4) == 0)
424 // Only test with I420
428 TEST(strncmp(_sendCodec.plName, "I420", 4) == 0);
429 _vcm->InitializeSender();
430 _sendCodec.maxFramerate = static_cast<uint8_t>(_frameRate / 2.0 + 0.5f);
431 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
432 _vcm->SetChannelParameters(2000000, 0, 0);
433 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
435 _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 0, 20);
436 _encodeCompleteCallback->Initialize();
437 sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
438 sendStats.set_bitrate(1000 * _bitRate);
439 _vcm->RegisterSendStatisticsCallback(&sendStats);
441 while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) ==
442 _lengthSourceFrame) {
443 sourceFrame.CreateFrame(size_y, tmpBuffer,
444 size_uv, tmpBuffer + size_y,
445 size_uv, tmpBuffer + size_y + size_uv,
447 _width, half_width, half_width);
448 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
449 sourceFrame.set_timestamp(_timeStamp);
450 ret = _vcm->AddVideoFrame(sourceFrame);
451 if (_vcm->TimeUntilNextProcess() <= 0)
455 IncrementDebugClock(_frameRate);
456 } // first frame encoded
461 delete _decodeCallback;
462 delete _encodeCompleteCallback;
468 GenericCodecTest::Print()
470 printf(" \n\n VCM Generic Encoder Test: \n\n%i tests completed\n", vcmMacrosTests);
471 if (vcmMacrosErrors > 0)
473 printf("%i FAILED\n\n", vcmMacrosErrors);
477 printf("ALL PASSED\n\n");
482 GenericCodecTest::WaitForEncodedFrame() const
484 int64_t startTime = _clock->TimeInMilliseconds();
485 while (_clock->TimeInMilliseconds() - startTime < kMaxWaitEncTimeMs*10)
487 if (_encodeCompleteCallback->EncodeComplete())
489 return _encodeCompleteCallback->EncodedBytes();
496 GenericCodecTest::IncrementDebugClock(float frameRate)
498 _clock->AdvanceTimeMilliseconds(1000/frameRate);
502 RTPSendCallback_SizeTest::SendPacket(int channel, const void *data, int len)
505 _payloadSizeSum += len;
506 // Make sure no payloads (len - header size) are larger than maxPayloadSize
507 TEST(len > 0 && static_cast<uint32_t>(len - 12) <= _maxPayloadSize);
512 RTPSendCallback_SizeTest::SetMaxPayloadSize(uint32_t maxPayloadSize)
514 _maxPayloadSize = maxPayloadSize;
518 RTPSendCallback_SizeTest::Reset()
525 RTPSendCallback_SizeTest::AveragePayloadSize() const
529 return _payloadSizeSum / static_cast<float>(_nPackets);
535 VCMEncComplete_KeyReqTest::SendData(
536 const FrameType frameType,
537 const uint8_t payloadType,
538 const uint32_t timeStamp,
539 int64_t capture_time_ms,
540 const uint8_t* payloadData,
541 const uint32_t payloadSize,
542 const RTPFragmentationHeader& /*fragmentationHeader*/,
543 const webrtc::RTPVideoHeader* /*videoHdr*/)
545 WebRtcRTPHeader rtpInfo;
546 rtpInfo.header.markerBit = true; // end of frame
547 rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8();
548 rtpInfo.type.Video.codec = kRtpVideoVp8;
549 rtpInfo.header.payloadType = payloadType;
550 rtpInfo.header.sequenceNumber = _seqNo;
552 rtpInfo.header.ssrc = 0;
553 rtpInfo.header.timestamp = _timeStamp;
555 rtpInfo.type.Video.isFirstPacket = false;
556 rtpInfo.frameType = kVideoFrameKey;
557 return _vcm.IncomingPacket(payloadData, payloadSize, rtpInfo);