Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_coding / main / test / codec_database_test.cc
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
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
41 CodecDataBaseTest::CodecDataBaseTest(VideoCodingModule* vcm):
42 _vcm(vcm),
43 _width(0),
44 _height(0),
45 _lengthSourceFrame(0),
46 _timeStamp(0)
47 {
48     //
49 }
50 CodecDataBaseTest::~CodecDataBaseTest()
51 {
52     //
53 }
54 void
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
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(VideoCodingModule::NumberOfCodecs() + 1u,
133                                   &sendCodec) < 0);
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++)
144     {
145         VideoCodingModule::Codec(i, &sendCodec);
146         printf("%s   ", sendCodec.plName);
147     }
148     printf("\n\nVerify that all requested codecs are used\n \n \n");
149
150     // Testing with VP8.
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 );
158
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(&currentSendCodec);
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(&currentSendCodec);
172     TEST(currentSendCodec.width == sendCodec.width &&
173         currentSendCodec.height == sendCodec.height);
174
175     delete _decodeCallback;
176     _decodeCallback = NULL;
177     delete _encodeCompleteCallback;
178     _encodeCompleteCallback = NULL;
179
180     VCMEncodeCompleteCallback *_encodeCallback = new VCMEncodeCompleteCallback(_encodedFile);
181
182     /*************************/
183     /* External codecs       */
184     /*************************/
185
186
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);
203     waitEvent->Wait(33);
204     _timeStamp += (uint32_t)(9e4 / _frameRate);
205     sourceFrame.set_timestamp(_timeStamp);
206     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
207     TEST(_vcm->Decode() == VCM_OK);
208
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
215
216     delete decoder;
217     decoder = NULL;
218     delete encoder;
219     encoder = NULL;
220
221     /***************************************
222      * Test the "require key frame" setting*
223      ***************************************/
224
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);
238     waitEvent->Wait(33);
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);
250
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);
258     waitEvent->Wait(33);
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);
264     waitEvent->Wait(33);
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);
271
272     delete _encodeCallback;
273
274     /*************************/
275     /* Send/Receive Control */
276     /***********************/
277     /*
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
282     */
283     rewind(_sourceFile);
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)
292     {
293         // Register all available decoders.
294         int i, j;
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++)
299         {
300             VideoCodingModule::Codec(i, &receiveCodec);
301             if (strcmp(receiveCodec.plName, "I420") == 0)
302             {
303                 receiveCodec.height = _height;
304                 receiveCodec.width = _width;
305             }
306             _vcm->RegisterReceiveCodec(&receiveCodec, 1);
307         }
308         // start encoding - iterating over available encoders
309         _vcm->RegisterTransportCallback(encodeCallCDT);
310         encodeCallCDT->RegisterReceiverVCM(_vcm);
311         encodeCallCDT->Initialize();
312         int frameCnt = 0;
313         for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
314         {
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);
324
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);
329
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++)
333             {
334                 frameCnt++;
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,
339                                         _width, _height,
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
346
347                 int ret =_vcm->Decode();
348                 TEST(ret >= 0);
349                 if (ret < 0)
350                 {
351                     printf("Error #%d in frame number %d \n",ret, frameCnt);
352                 }
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)
358                 {
359                     printf("frame number:%d\n",frameCnt);
360                 }
361             }  // end for:encode-decode
362            // byte count for codec specific
363
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....
366             _vcm->Decode();
367             _vcm->Decode();
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,
372                                   _height, &psnr);
373                 printf("\n @ %d KBPS:  ", sendCodec.startBitrate);
374                 printf("PSNR from encoder-decoder send-receive control test"
375                        "is %f\n\n", psnr.average);
376             }
377         }  // end: iterate codecs
378         rewind(_sourceFile);
379         delete [] tmpBuffer;
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
385
386     delete waitEvent;
387     Print();
388     return 0;
389 }
390 void
391 CodecDataBaseTest::Print()
392 {
393     printf("\nVCM Codec DataBase Test: \n\n%i tests completed\n", vcmMacrosTests);
394     if (vcmMacrosErrors > 0)
395     {
396         printf("%i FAILED\n\n", vcmMacrosErrors);
397     }
398     else
399     {
400         printf("ALL PASSED\n\n");
401     }
402 }
403
404 void
405 CodecDataBaseTest::TearDown()
406 {
407     fclose(_sourceFile);
408     fclose(_decodedFile);
409     fclose(_encodedFile);
410     return;
411 }