• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Implementation of codec data base test
12 // testing is done via the VCM module, no specific CodecDataBase module functionality.
13 
14 #include "webrtc/modules/video_coding/main/test/codec_database_test.h"
15 
16 #include <assert.h>
17 #include <stdio.h>
18 
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"
27 
28 using namespace webrtc;
29 
RunTest(CmdArgs & args)30 int CodecDataBaseTest::RunTest(CmdArgs& args)
31 {
32     VideoCodingModule* vcm = VideoCodingModule::Create();
33     CodecDataBaseTest* cdbt = new CodecDataBaseTest(vcm);
34     cdbt->Perform(args);
35     VideoCodingModule::Destroy(vcm);
36     delete cdbt;
37     return 0;
38 
39 }
40 
CodecDataBaseTest(VideoCodingModule * vcm)41 CodecDataBaseTest::CodecDataBaseTest(VideoCodingModule* vcm):
42 _vcm(vcm),
43 _width(0),
44 _height(0),
45 _lengthSourceFrame(0),
46 _timeStamp(0)
47 {
48     //
49 }
~CodecDataBaseTest()50 CodecDataBaseTest::~CodecDataBaseTest()
51 {
52     //
53 }
54 void
Setup(CmdArgs & args)55 CodecDataBaseTest::Setup(CmdArgs& args)
56 {
57     _inname= args.inputFile;
58     _width = args.width;
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";
64     else
65         _outname = args.outputFile;
66     _outname = args.outputFile;
67     _encodedName = test::OutputPath() + "CDBtest_encoded.vp8";
68 
69     if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
70     {
71         printf("Cannot read file %s.\n", _inname.c_str());
72         exit(1);
73     }
74 
75     if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
76     {
77         printf("Cannot write encoded file.\n");
78         exit(1);
79     }
80 
81     if ((_decodedFile = fopen(_outname.c_str(),  "wb")) == NULL)
82     {
83         printf("Cannot write file %s.\n", _outname.c_str());
84         exit(1);
85     }
86 
87     return;
88 }
89 
90 
91 
92 int32_t
Perform(CmdArgs & args)93 CodecDataBaseTest::Perform(CmdArgs& args)
94 {
95 #ifndef VIDEOCODEC_VP8
96     assert(false);
97 #endif
98     Setup(args);
99     EventWrapper* waitEvent = EventWrapper::Create();
100 
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,
126                             _width, _height,
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(-1, &sendCodec) < 0);
133     TEST(VideoCodingModule::Codec(VideoCodingModule::NumberOfCodecs() + 1,
134                                   &sendCodec) < 0);
135     VideoCodingModule::Codec(1, &sendCodec);
136     sendCodec.plType = 0; // random value
137     TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0);
138     _vcm->InitializeReceiver();
139     _vcm->InitializeSender();
140     _vcm->RegisterReceiveCallback(_decodeCallback);
141     _vcm->RegisterTransportCallback(_encodeCompleteCallback);
142     printf(" \nNumber of Registered Codecs: %d \n\n", VideoCodingModule::NumberOfCodecs());
143     printf("Registered codec names: ");
144     for (int i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
145     {
146         VideoCodingModule::Codec(i, &sendCodec);
147         printf("%s   ", sendCodec.plName);
148     }
149     printf("\n\nVerify that all requested codecs are used\n \n \n");
150 
151     // Testing with VP8.
152     VideoCodingModule::Codec(kVideoCodecVP8, &sendCodec);
153     _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
154     _encodeCompleteCallback->SetCodecType(kRtpVideoVp8);
155     _vcm->InitializeReceiver();
156     TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK );
157     _vcm->InitializeSender();
158     TEST (_vcm->AddVideoFrame(sourceFrame) < 0 );
159 
160     // Test changing frame size while keeping the same payload type
161     VideoCodingModule::Codec(0, &sendCodec);
162     sendCodec.width = 352;
163     sendCodec.height = 288;
164     VideoCodec currentSendCodec;
165     _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
166     _vcm->SendCodec(&currentSendCodec);
167     TEST(currentSendCodec.width == sendCodec.width &&
168         currentSendCodec.height == sendCodec.height);
169     sendCodec.width = 352/2;
170     sendCodec.height = 288/2;
171     _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
172     _vcm->SendCodec(&currentSendCodec);
173     TEST(currentSendCodec.width == sendCodec.width &&
174         currentSendCodec.height == sendCodec.height);
175 
176     delete _decodeCallback;
177     _decodeCallback = NULL;
178     delete _encodeCompleteCallback;
179     _encodeCompleteCallback = NULL;
180 
181     VCMEncodeCompleteCallback *_encodeCallback = new VCMEncodeCompleteCallback(_encodedFile);
182 
183     /*************************/
184     /* External codecs       */
185     /*************************/
186 
187 
188     _vcm->InitializeReceiver();
189     VP8Decoder* decoder = VP8Decoder::Create();
190     VideoCodec vp8DecSettings;
191     VideoCodingModule::Codec(kVideoCodecVP8, &vp8DecSettings);
192     TEST(_vcm->RegisterExternalDecoder(decoder, vp8DecSettings.plType, false) == VCM_OK);
193     TEST(_vcm->RegisterReceiveCodec(&vp8DecSettings, 1, false) == VCM_OK);
194     VP8Encoder* encoder = VP8Encoder::Create();
195     VideoCodec vp8EncSettings;
196     VideoCodingModule::Codec(kVideoCodecVP8, &vp8EncSettings);
197     _vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
198     _encodeCallback->RegisterReceiverVCM(_vcm);
199     _encodeCallback->SetCodecType(kRtpVideoVp8);
200     TEST(_vcm->RegisterExternalEncoder(encoder, vp8EncSettings.plType) == VCM_OK);
201     TEST(_vcm->RegisterSendCodec(&vp8EncSettings, 4, 1440) == VCM_OK);
202     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
203     TEST(_vcm->Decode() == VCM_OK);
204     waitEvent->Wait(33);
205     _timeStamp += (uint32_t)(9e4 / _frameRate);
206     sourceFrame.set_timestamp(_timeStamp);
207     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
208     TEST(_vcm->Decode() == VCM_OK);
209 
210     // De-register and try again.
211     TEST(_vcm->RegisterExternalDecoder(NULL, vp8DecSettings.plType, false) == VCM_OK);
212     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
213     TEST(_vcm->Decode() < 0); // Expect an error since we have de-registered the decoder
214     TEST(_vcm->RegisterExternalEncoder(NULL, vp8DecSettings.plType) == VCM_OK);
215     TEST(_vcm->AddVideoFrame(sourceFrame) < 0); // No send codec registered
216 
217     delete decoder;
218     decoder = NULL;
219     delete encoder;
220     encoder = NULL;
221 
222     /***************************************
223      * Test the "require key frame" setting*
224      ***************************************/
225 
226     TEST(_vcm->InitializeSender() == VCM_OK);
227     TEST(_vcm->InitializeReceiver() == VCM_OK);
228     VideoCodingModule::Codec(kVideoCodecVP8, &receiveCodec);
229     receiveCodec.height = _height;
230     receiveCodec.width = _width;
231     TEST(_vcm->RegisterSendCodec(&receiveCodec, 4, 1440) == VCM_OK);
232     TEST(_vcm->RegisterReceiveCodec(&receiveCodec, 1, true) == VCM_OK); // Require key frame
233     _vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
234     _encodeCallback->RegisterReceiverVCM(_vcm);
235     _encodeCallback->SetCodecType(kRtpVideoVp8);
236     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
237     TEST(_vcm->Decode() == VCM_OK);
238     TEST(_vcm->ResetDecoder() == VCM_OK);
239     waitEvent->Wait(33);
240     _timeStamp += (uint32_t)(9e4 / _frameRate);
241     sourceFrame.set_timestamp(_timeStamp);
242     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
243     // Try to decode a delta frame. Should get a warning since we have enabled the "require key frame" setting
244     // and because no frame type request callback has been registered.
245     TEST(_vcm->Decode() == VCM_MISSING_CALLBACK);
246     TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
247     _timeStamp += (uint32_t)(9e4 / _frameRate);
248     sourceFrame.set_timestamp(_timeStamp);
249     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
250     TEST(_vcm->Decode() == VCM_OK);
251 
252     // Make sure we can register another codec with the same
253     // payload type without crash.
254     _vcm->InitializeReceiver();
255     sendCodec.width = _width;
256     sendCodec.height = _height;
257     TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
258     TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
259     waitEvent->Wait(33);
260     _timeStamp += (uint32_t)(9e4 / _frameRate);
261     sourceFrame.set_timestamp(_timeStamp);
262     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
263     TEST(_vcm->Decode() == VCM_OK);
264     TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
265     waitEvent->Wait(33);
266     _timeStamp += (uint32_t)(9e4 / _frameRate);
267     sourceFrame.set_timestamp(_timeStamp);
268     TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
269     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
270     TEST(_vcm->Decode() == VCM_OK);
271     TEST(_vcm->ResetDecoder() == VCM_OK);
272 
273     delete _encodeCallback;
274 
275     /*************************/
276     /* Send/Receive Control */
277     /***********************/
278     /*
279     1. check available codecs (N)
280     2. register all corresponding decoders
281     3. encode 300/N frames with each encoder, and hope to properly decode
282     4. encode without a matching decoder - expect an error
283     */
284     rewind(_sourceFile);
285     _vcm->InitializeReceiver();
286     _vcm->InitializeSender();
287     VCMDecodeCompleteCallback* decodeCallCDT = new VCMDecodeCompleteCallback(_decodedFile);
288     VCMEncodeCompleteCallback* encodeCallCDT = new VCMEncodeCompleteCallback(_encodedFile);
289     _vcm->RegisterReceiveCallback(decodeCallCDT);
290     _vcm->RegisterTransportCallback(encodeCallCDT);
291     encodeCallCDT->RegisterReceiverVCM(_vcm);
292     if (VideoCodingModule::NumberOfCodecs() > 0)
293     {
294         // Register all available decoders.
295         int i, j;
296         sourceFrame.CreateEmptyFrame(_width, _height, _width,
297                                      (_width + 1) / 2, (_width + 1) / 2);
298         _vcm->RegisterReceiveCallback(decodeCallCDT);
299         for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
300         {
301             VideoCodingModule::Codec(i, &receiveCodec);
302             if (strcmp(receiveCodec.plName, "I420") == 0)
303             {
304                 receiveCodec.height = _height;
305                 receiveCodec.width = _width;
306             }
307             _vcm->RegisterReceiveCodec(&receiveCodec, 1);
308         }
309         // start encoding - iterating over available encoders
310         _vcm->RegisterTransportCallback(encodeCallCDT);
311         encodeCallCDT->RegisterReceiverVCM(_vcm);
312         encodeCallCDT->Initialize();
313         int frameCnt = 0;
314         for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
315         {
316             encodeCallCDT->ResetByteCount();
317             VideoCodingModule::Codec(i, &sendCodec);
318             sendCodec.height = _height;
319             sendCodec.width = _width;
320             sendCodec.startBitrate = 1000;
321             sendCodec.maxBitrate = 8000;
322             encodeCallCDT->SetFrameDimensions(_width, _height);
323             encodeCallCDT->SetCodecType(ConvertCodecType(sendCodec.plName));
324             TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) == VCM_OK);
325 
326             // We disable the frame dropper to avoid dropping frames due to
327             // bad rate control. This isn't a codec performance test, and the
328             // I420 codec is expected to produce too many bits.
329             _vcm->EnableFrameDropper(false);
330 
331             printf("Encoding with %s \n\n", sendCodec.plName);
332             // Assuming 300 frames, NumberOfCodecs <= 10.
333             for (j=0; j < int(300/VideoCodingModule::NumberOfCodecs()); j++)
334             {
335                 frameCnt++;
336                 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
337                 sourceFrame.CreateFrame(size_y, tmpBuffer,
338                                         size_uv, tmpBuffer + size_y,
339                                         size_uv, tmpBuffer + size_y + size_uv,
340                                         _width, _height,
341                                         _width, half_width, half_width);
342                 _timeStamp += (uint32_t)(9e4 / _frameRate);
343                 sourceFrame.set_timestamp(_timeStamp);
344                 // send frame to the encoder
345                 TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
346                 waitEvent->Wait(33); // was 100
347 
348                 int ret =_vcm->Decode();
349                 TEST(ret >= 0);
350                 if (ret < 0)
351                 {
352                     printf("Error #%d in frame number %d \n",ret, frameCnt);
353                 }
354                  // verifying matching payload types:
355                 _vcm->SendCodec(&sendCodec);
356                 _vcm->ReceiveCodec(&receiveCodec);
357                 TEST(sendCodec.plType == receiveCodec.plType);
358                 if (sendCodec.plType != receiveCodec.plType)
359                 {
360                     printf("frame number:%d\n",frameCnt);
361                 }
362             }  // end for:encode-decode
363            // byte count for codec specific
364 
365             printf("Total bytes encoded: %f \n\n",(8.0/1000)*(encodeCallCDT->EncodedBytes()/((int)10/VideoCodingModule::NumberOfCodecs())));
366             // decode what's left in the buffer....
367             _vcm->Decode();
368             _vcm->Decode();
369             // Don't measure PSNR for I420 since it will be perfect.
370             if (sendCodec.codecType != kVideoCodecI420) {
371                 webrtc::test::QualityMetricsResult psnr;
372                 I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width,
373                                   _height, &psnr);
374                 printf("\n @ %d KBPS:  ", sendCodec.startBitrate);
375                 printf("PSNR from encoder-decoder send-receive control test"
376                        "is %f\n\n", psnr.average);
377             }
378         }  // end: iterate codecs
379         rewind(_sourceFile);
380         delete [] tmpBuffer;
381         delete decodeCallCDT;
382         delete encodeCallCDT;
383         // closing and calculating PSNR for prior encoder-decoder test
384         TearDown(); // closing open files
385     }  // end of #codecs >1
386 
387     delete waitEvent;
388     Print();
389     return 0;
390 }
391 void
Print()392 CodecDataBaseTest::Print()
393 {
394     printf("\nVCM Codec DataBase Test: \n\n%i tests completed\n", vcmMacrosTests);
395     if (vcmMacrosErrors > 0)
396     {
397         printf("%i FAILED\n\n", vcmMacrosErrors);
398     }
399     else
400     {
401         printf("ALL PASSED\n\n");
402     }
403 }
404 
405 void
TearDown()406 CodecDataBaseTest::TearDown()
407 {
408     fclose(_sourceFile);
409     fclose(_decodedFile);
410     fclose(_encodedFile);
411     return;
412 }
413