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 codec data base test
12 // testing is done via the VCM module, no specific CodecDataBase module functionality.
14 #include "webrtc/modules/video_coding/main/test/codec_database_test.h"
19 #include "webrtc/engine_configurations.h"
20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
21 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
22 #include "webrtc/modules/video_coding/main/test/test_callbacks.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 CodecDataBaseTest::RunTest(CmdArgs& args)
32 VideoCodingModule* vcm = VideoCodingModule::Create();
33 CodecDataBaseTest* cdbt = new CodecDataBaseTest(vcm);
35 VideoCodingModule::Destroy(vcm);
41 CodecDataBaseTest::CodecDataBaseTest(VideoCodingModule* vcm):
45 _lengthSourceFrame(0),
50 CodecDataBaseTest::~CodecDataBaseTest()
55 CodecDataBaseTest::Setup(CmdArgs& args)
57 _inname= args.inputFile;
59 _height = args.height;
60 _frameRate = args.frameRate;
61 _lengthSourceFrame = 3*_width*_height/2;
62 if (args.outputFile.compare(""))
63 _outname = test::OutputPath() + "CDBtest_decoded.yuv";
65 _outname = args.outputFile;
66 _outname = args.outputFile;
67 _encodedName = test::OutputPath() + "CDBtest_encoded.vp8";
69 if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
71 printf("Cannot read file %s.\n", _inname.c_str());
75 if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
77 printf("Cannot write encoded file.\n");
81 if ((_decodedFile = fopen(_outname.c_str(), "wb")) == NULL)
83 printf("Cannot write file %s.\n", _outname.c_str());
93 CodecDataBaseTest::Perform(CmdArgs& args)
95 #ifndef VIDEOCODEC_VP8
99 EventWrapper* waitEvent = EventWrapper::Create();
101 /**************************/
102 /* General Sanity Checks */
103 /************************/
104 VideoCodec sendCodec, receiveCodec;
105 TEST(VideoCodingModule::NumberOfCodecs() > 0);
106 _vcm->InitializeReceiver();
107 _vcm->InitializeSender();
108 VCMDecodeCompleteCallback *_decodeCallback = new VCMDecodeCompleteCallback(_decodedFile);
109 VCMEncodeCompleteCallback *_encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile);
110 _vcm->RegisterReceiveCallback(_decodeCallback);
111 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
112 _encodeCompleteCallback->SetFrameDimensions(_width, _height);
113 // registering the callback - encode and decode with the same vcm (could be later changed)
114 _encodeCompleteCallback->RegisterReceiverVCM(_vcm);
115 // preparing a frame to be encoded
116 uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
117 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
118 I420VideoFrame sourceFrame;
119 int half_width = (_width + 1) / 2;
120 int half_height = (_height + 1) / 2;
121 int size_y = _width * _height;
122 int size_uv = half_width * half_height;
123 sourceFrame.CreateFrame(size_y, tmpBuffer,
124 size_uv, tmpBuffer + size_y,
125 size_uv, tmpBuffer + size_y + size_uv,
127 _width, half_width, half_width);
128 _timeStamp += (uint32_t)(9e4 / _frameRate);
129 sourceFrame.set_timestamp(_timeStamp);
130 // Encoder registration
131 TEST (VideoCodingModule::NumberOfCodecs() > 0);
132 TEST(VideoCodingModule::Codec(VideoCodingModule::NumberOfCodecs() + 1u,
134 VideoCodingModule::Codec(1, &sendCodec);
135 sendCodec.plType = 0; // random value
136 TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0);
137 _vcm->InitializeReceiver();
138 _vcm->InitializeSender();
139 _vcm->RegisterReceiveCallback(_decodeCallback);
140 _vcm->RegisterTransportCallback(_encodeCompleteCallback);
141 printf(" \nNumber of Registered Codecs: %d \n\n", VideoCodingModule::NumberOfCodecs());
142 printf("Registered codec names: ");
143 for (int i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
145 VideoCodingModule::Codec(i, &sendCodec);
146 printf("%s ", sendCodec.plName);
148 printf("\n\nVerify that all requested codecs are used\n \n \n");
151 VideoCodingModule::Codec(kVideoCodecVP8, &sendCodec);
152 _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
153 _encodeCompleteCallback->SetCodecType(kRtpVideoVp8);
154 _vcm->InitializeReceiver();
155 TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK );
156 _vcm->InitializeSender();
157 TEST (_vcm->AddVideoFrame(sourceFrame) < 0 );
159 // Test changing frame size while keeping the same payload type
160 VideoCodingModule::Codec(0, &sendCodec);
161 sendCodec.width = 352;
162 sendCodec.height = 288;
163 VideoCodec currentSendCodec;
164 _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
165 _vcm->SendCodec(¤tSendCodec);
166 TEST(currentSendCodec.width == sendCodec.width &&
167 currentSendCodec.height == sendCodec.height);
168 sendCodec.width = 352/2;
169 sendCodec.height = 288/2;
170 _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
171 _vcm->SendCodec(¤tSendCodec);
172 TEST(currentSendCodec.width == sendCodec.width &&
173 currentSendCodec.height == sendCodec.height);
175 delete _decodeCallback;
176 _decodeCallback = NULL;
177 delete _encodeCompleteCallback;
178 _encodeCompleteCallback = NULL;
180 VCMEncodeCompleteCallback *_encodeCallback = new VCMEncodeCompleteCallback(_encodedFile);
182 /*************************/
183 /* External codecs */
184 /*************************/
187 _vcm->InitializeReceiver();
188 VP8Decoder* decoder = VP8Decoder::Create();
189 VideoCodec vp8DecSettings;
190 VideoCodingModule::Codec(kVideoCodecVP8, &vp8DecSettings);
191 TEST(_vcm->RegisterExternalDecoder(decoder, vp8DecSettings.plType, false) == VCM_OK);
192 TEST(_vcm->RegisterReceiveCodec(&vp8DecSettings, 1, false) == VCM_OK);
193 VP8Encoder* encoder = VP8Encoder::Create();
194 VideoCodec vp8EncSettings;
195 VideoCodingModule::Codec(kVideoCodecVP8, &vp8EncSettings);
196 _vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
197 _encodeCallback->RegisterReceiverVCM(_vcm);
198 _encodeCallback->SetCodecType(kRtpVideoVp8);
199 TEST(_vcm->RegisterExternalEncoder(encoder, vp8EncSettings.plType) == VCM_OK);
200 TEST(_vcm->RegisterSendCodec(&vp8EncSettings, 4, 1440) == VCM_OK);
201 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
202 TEST(_vcm->Decode() == VCM_OK);
204 _timeStamp += (uint32_t)(9e4 / _frameRate);
205 sourceFrame.set_timestamp(_timeStamp);
206 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
207 TEST(_vcm->Decode() == VCM_OK);
209 // De-register and try again.
210 TEST(_vcm->RegisterExternalDecoder(NULL, vp8DecSettings.plType, false) == VCM_OK);
211 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
212 TEST(_vcm->Decode() < 0); // Expect an error since we have de-registered the decoder
213 TEST(_vcm->RegisterExternalEncoder(NULL, vp8DecSettings.plType) == VCM_OK);
214 TEST(_vcm->AddVideoFrame(sourceFrame) < 0); // No send codec registered
221 /***************************************
222 * Test the "require key frame" setting*
223 ***************************************/
225 TEST(_vcm->InitializeSender() == VCM_OK);
226 TEST(_vcm->InitializeReceiver() == VCM_OK);
227 VideoCodingModule::Codec(kVideoCodecVP8, &receiveCodec);
228 receiveCodec.height = _height;
229 receiveCodec.width = _width;
230 TEST(_vcm->RegisterSendCodec(&receiveCodec, 4, 1440) == VCM_OK);
231 TEST(_vcm->RegisterReceiveCodec(&receiveCodec, 1, true) == VCM_OK); // Require key frame
232 _vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
233 _encodeCallback->RegisterReceiverVCM(_vcm);
234 _encodeCallback->SetCodecType(kRtpVideoVp8);
235 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
236 TEST(_vcm->Decode() == VCM_OK);
237 TEST(_vcm->ResetDecoder() == VCM_OK);
239 _timeStamp += (uint32_t)(9e4 / _frameRate);
240 sourceFrame.set_timestamp(_timeStamp);
241 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
242 // Try to decode a delta frame. Should get a warning since we have enabled the "require key frame" setting
243 // and because no frame type request callback has been registered.
244 TEST(_vcm->Decode() == VCM_MISSING_CALLBACK);
245 TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
246 _timeStamp += (uint32_t)(9e4 / _frameRate);
247 sourceFrame.set_timestamp(_timeStamp);
248 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
249 TEST(_vcm->Decode() == VCM_OK);
251 // Make sure we can register another codec with the same
252 // payload type without crash.
253 _vcm->InitializeReceiver();
254 sendCodec.width = _width;
255 sendCodec.height = _height;
256 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
257 TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
259 _timeStamp += (uint32_t)(9e4 / _frameRate);
260 sourceFrame.set_timestamp(_timeStamp);
261 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
262 TEST(_vcm->Decode() == VCM_OK);
263 TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
265 _timeStamp += (uint32_t)(9e4 / _frameRate);
266 sourceFrame.set_timestamp(_timeStamp);
267 TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
268 TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
269 TEST(_vcm->Decode() == VCM_OK);
270 TEST(_vcm->ResetDecoder() == VCM_OK);
272 delete _encodeCallback;
274 /*************************/
275 /* Send/Receive Control */
276 /***********************/
278 1. check available codecs (N)
279 2. register all corresponding decoders
280 3. encode 300/N frames with each encoder, and hope to properly decode
281 4. encode without a matching decoder - expect an error
284 _vcm->InitializeReceiver();
285 _vcm->InitializeSender();
286 VCMDecodeCompleteCallback* decodeCallCDT = new VCMDecodeCompleteCallback(_decodedFile);
287 VCMEncodeCompleteCallback* encodeCallCDT = new VCMEncodeCompleteCallback(_encodedFile);
288 _vcm->RegisterReceiveCallback(decodeCallCDT);
289 _vcm->RegisterTransportCallback(encodeCallCDT);
290 encodeCallCDT->RegisterReceiverVCM(_vcm);
291 if (VideoCodingModule::NumberOfCodecs() > 0)
293 // Register all available decoders.
295 sourceFrame.CreateEmptyFrame(_width, _height, _width,
296 (_width + 1) / 2, (_width + 1) / 2);
297 _vcm->RegisterReceiveCallback(decodeCallCDT);
298 for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
300 VideoCodingModule::Codec(i, &receiveCodec);
301 if (strcmp(receiveCodec.plName, "I420") == 0)
303 receiveCodec.height = _height;
304 receiveCodec.width = _width;
306 _vcm->RegisterReceiveCodec(&receiveCodec, 1);
308 // start encoding - iterating over available encoders
309 _vcm->RegisterTransportCallback(encodeCallCDT);
310 encodeCallCDT->RegisterReceiverVCM(_vcm);
311 encodeCallCDT->Initialize();
313 for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
315 encodeCallCDT->ResetByteCount();
316 VideoCodingModule::Codec(i, &sendCodec);
317 sendCodec.height = _height;
318 sendCodec.width = _width;
319 sendCodec.startBitrate = 1000;
320 sendCodec.maxBitrate = 8000;
321 encodeCallCDT->SetFrameDimensions(_width, _height);
322 encodeCallCDT->SetCodecType(ConvertCodecType(sendCodec.plName));
323 TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) == VCM_OK);
325 // We disable the frame dropper to avoid dropping frames due to
326 // bad rate control. This isn't a codec performance test, and the
327 // I420 codec is expected to produce too many bits.
328 _vcm->EnableFrameDropper(false);
330 printf("Encoding with %s \n\n", sendCodec.plName);
331 // Assuming 300 frames, NumberOfCodecs <= 10.
332 for (j=0; j < int(300/VideoCodingModule::NumberOfCodecs()); j++)
335 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
336 sourceFrame.CreateFrame(size_y, tmpBuffer,
337 size_uv, tmpBuffer + size_y,
338 size_uv, tmpBuffer + size_y + size_uv,
340 _width, half_width, half_width);
341 _timeStamp += (uint32_t)(9e4 / _frameRate);
342 sourceFrame.set_timestamp(_timeStamp);
343 // send frame to the encoder
344 TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
345 waitEvent->Wait(33); // was 100
347 int ret =_vcm->Decode();
351 printf("Error #%d in frame number %d \n",ret, frameCnt);
353 // verifying matching payload types:
354 _vcm->SendCodec(&sendCodec);
355 _vcm->ReceiveCodec(&receiveCodec);
356 TEST(sendCodec.plType == receiveCodec.plType);
357 if (sendCodec.plType != receiveCodec.plType)
359 printf("frame number:%d\n",frameCnt);
361 } // end for:encode-decode
362 // byte count for codec specific
364 printf("Total bytes encoded: %f \n\n",(8.0/1000)*(encodeCallCDT->EncodedBytes()/((int)10/VideoCodingModule::NumberOfCodecs())));
365 // decode what's left in the buffer....
368 // Don't measure PSNR for I420 since it will be perfect.
369 if (sendCodec.codecType != kVideoCodecI420) {
370 webrtc::test::QualityMetricsResult psnr;
371 I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width,
373 printf("\n @ %d KBPS: ", sendCodec.startBitrate);
374 printf("PSNR from encoder-decoder send-receive control test"
375 "is %f\n\n", psnr.average);
377 } // end: iterate codecs
380 delete decodeCallCDT;
381 delete encodeCallCDT;
382 // closing and calculating PSNR for prior encoder-decoder test
383 TearDown(); // closing open files
384 } // end of #codecs >1
391 CodecDataBaseTest::Print()
393 printf("\nVCM Codec DataBase Test: \n\n%i tests completed\n", vcmMacrosTests);
394 if (vcmMacrosErrors > 0)
396 printf("%i FAILED\n\n", vcmMacrosErrors);
400 printf("ALL PASSED\n\n");
405 CodecDataBaseTest::TearDown()
408 fclose(_decodedFile);
409 fclose(_encodedFile);