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 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++)
146 _vcm->Codec(i, &receiveCodec);
147 _vcm->RegisterReceiveCodec(&receiveCodec, 1);
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,
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);
166 /**************************************/
167 /* encoder/decoder individuality test */
168 /**************************************/
169 //Register both encoder and decoder, reset decoder - encode, set up decoder, reset encoder - decode.
171 _vcm->InitializeReceiver();
172 _vcm->InitializeSender();
173 NumberOfCodecs = _vcm->NumberOfCodecs();
175 _vcm->Codec(kVideoCodecVP8, &_sendCodec);
176 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
177 _vcm->SendCodec(&sendCodec);
178 sendCodec.startBitrate = 2000;
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
187 _decodeCallback = new VCMDecodeCompleteCallback(_decodedFile);
188 _encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile);
189 _vcm->RegisterReceiveCallback(_decodeCallback);
190 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
191 _encodeCompleteCallback->RegisterReceiverVCM(_vcm);
193 _vcm->RegisterSendCodec(&sendCodec, 4, 1440);
194 _encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName));
196 _vcm->InitializeReceiver();
199 //encoding 1 second of video
200 for (i = 0; i < _frameRate; i++)
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,
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);
214 sendCodec.maxFramerate = (uint8_t)_frameRate;
215 _vcm->InitializeSender();
216 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK); // same codec for encode and decode
219 while ((i < 25) && (ret == 0) )
221 ret = _vcm->Decode();
225 printf("error in frame # %d \n", i);
227 IncrementDebugClock(_frameRate);
230 //TEST((ret == 0) && (i = 50));
233 printf("Encoder/Decoder individuality test complete - View output files \n");
235 // last frame - not decoded
236 _vcm->InitializeReceiver();
237 TEST(_vcm->Decode() < 0); // frame to be encoded exists, decoder uninitialized
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);
261 printf("API tests complete \n");
263 /*******************/
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
272 double FullReq = 0.1;
273 //double OneSecReq = 0.15;
274 printf("\n RATE CONTROL TEST\n");
276 _vcm->InitializeSender();
277 _vcm->InitializeReceiver();
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);
285 float totalBytesOneSec;//, totalBytesTenSec;
286 float totalBytes, actualBitrate;
287 VCMFrameCount frameCount; // testing frame type counters
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
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++)
306 _bitRate = static_cast<float>(bitRate[i]);
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);
315 _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate),
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) ==
327 sourceFrame.CreateFrame(size_y, tmpBuffer,
328 size_uv, tmpBuffer + size_y,
329 size_uv, tmpBuffer + size_y + size_uv,
331 _width, (_width + 1) / 2,
333 _timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
334 sourceFrame.set_timestamp(_timeStamp);
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
342 totalBytesOneSec = _encodeCompleteCallback->EncodedBytes();//totalBytes;
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
350 // bit rate assumes input frame rate is as specified
351 totalBytes = _encodeCompleteCallback->EncodedBytes();
352 actualBitrate = (float)(8.0/1000)*(totalBytes / (_frameCnt / _frameRate));
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));
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);
365 //checking key/delta frame count
366 _vcm->SentFrameCount(frameCount);
367 printf("frame count: %d delta, %d key\n", frameCount.numDeltaFrames, frameCount.numKeyFrames);
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++)
380 _vcm->Codec(k, &_sendCodec);
381 _vcm->InitializeSender();
382 _sendCodec.maxBitrate = 8000;
383 _vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
384 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
387 encodeComplete = false;
388 while (encodeComplete == false)
390 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
392 sourceFrame.CreateFrame(size_y, tmpBuffer,
393 size_uv, tmpBuffer + size_y,
394 size_uv, tmpBuffer + size_y + size_uv,
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
406 /********************************/
407 /* Encoder Packet Size Test */
408 /********************************/
409 RTPSendCallback_SizeTest sendCallback;
411 RtpRtcp::Configuration configuration;
412 configuration.id = 1;
413 configuration.audio = false;
414 configuration.outgoing_transport = &sendCallback;
416 RtpRtcp& rtpModule = *RtpRtcp::CreateRtpRtcp(configuration);
418 VCMRTPEncodeCompleteCallback encCompleteCallback(&rtpModule);
419 _vcm->InitializeSender();
421 // Test temporal decimation settings
422 for (int k = 0; k < NumberOfCodecs; k++)
424 _vcm->Codec(k, &_sendCodec);
425 if (strncmp(_sendCodec.plName, "I420", 4) == 0)
427 // Only test with I420
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);
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);
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,
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)
458 IncrementDebugClock(_frameRate);
459 } // first frame encoded
464 delete _decodeCallback;
465 delete _encodeCompleteCallback;
471 GenericCodecTest::Print()
473 printf(" \n\n VCM Generic Encoder Test: \n\n%i tests completed\n", vcmMacrosTests);
474 if (vcmMacrosErrors > 0)
476 printf("%i FAILED\n\n", vcmMacrosErrors);
480 printf("ALL PASSED\n\n");
485 GenericCodecTest::WaitForEncodedFrame() const
487 int64_t startTime = _clock->TimeInMilliseconds();
488 while (_clock->TimeInMilliseconds() - startTime < kMaxWaitEncTimeMs*10)
490 if (_encodeCompleteCallback->EncodeComplete())
492 return _encodeCompleteCallback->EncodedBytes();
499 GenericCodecTest::IncrementDebugClock(float frameRate)
501 _clock->AdvanceTimeMilliseconds(1000/frameRate);
505 RTPSendCallback_SizeTest::SendPacket(int channel, const void *data, int len)
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);
515 RTPSendCallback_SizeTest::SetMaxPayloadSize(uint32_t maxPayloadSize)
517 _maxPayloadSize = maxPayloadSize;
521 RTPSendCallback_SizeTest::Reset()
528 RTPSendCallback_SizeTest::AveragePayloadSize() const
532 return _payloadSizeSum / static_cast<float>(_nPackets);
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*/)
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;
555 rtpInfo.header.ssrc = 0;
556 rtpInfo.header.timestamp = _timeStamp;
558 rtpInfo.type.Video.isFirstPacket = false;
559 rtpInfo.frameType = kVideoFrameKey;
560 return _vcm.IncomingPacket(payloadData, payloadSize, rtpInfo);