Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_coding / main / test / normal_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 #include "webrtc/modules/video_coding/main/test/normal_test.h"
12
13 #include <assert.h>
14 #include <iostream>
15 #include <sstream>
16 #include <time.h>
17
18 #include "webrtc/common_types.h"
19 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
20 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
21 #include "webrtc/modules/video_coding/main/test/test_callbacks.h"
22 #include "webrtc/modules/video_coding/main/test/test_macros.h"
23 #include "webrtc/modules/video_coding/main/test/test_util.h"
24 #include "webrtc/system_wrappers/interface/clock.h"
25 #include "webrtc/system_wrappers/interface/trace.h"
26 #include "webrtc/test/testsupport/fileutils.h"
27 #include "webrtc/test/testsupport/metrics/video_metrics.h"
28
29 using namespace webrtc;
30
31 int NormalTest::RunTest(const CmdArgs& args)
32 {
33     SimulatedClock sim_clock(0);
34     SimulatedClock* clock = &sim_clock;
35     NullEventFactory event_factory;
36     Trace::CreateTrace();
37     Trace::SetTraceFile(
38         (test::OutputPath() + "VCMNormalTestTrace.txt").c_str());
39     Trace::set_level_filter(webrtc::kTraceAll);
40     VideoCodingModule* vcm = VideoCodingModule::Create(clock, &event_factory);
41     NormalTest VCMNTest(vcm, clock);
42     VCMNTest.Perform(args);
43     VideoCodingModule::Destroy(vcm);
44     Trace::ReturnTrace();
45     return 0;
46 }
47
48 ////////////////
49 // Callback Implementation
50 //////////////
51
52 VCMNTEncodeCompleteCallback::VCMNTEncodeCompleteCallback(FILE* encodedFile,
53                                                          NormalTest& test):
54     _encodedFile(encodedFile),
55     _encodedBytes(0),
56     _skipCnt(0),
57     _VCMReceiver(NULL),
58     _seqNo(0),
59     _test(test)
60 {
61     //
62 }
63 VCMNTEncodeCompleteCallback::~VCMNTEncodeCompleteCallback()
64 {
65 }
66
67 void VCMNTEncodeCompleteCallback::RegisterTransportCallback(
68     VCMPacketizationCallback* transport)
69 {
70 }
71
72 int32_t
73 VCMNTEncodeCompleteCallback::SendData(
74         const FrameType frameType,
75         const uint8_t  payloadType,
76         const uint32_t timeStamp,
77         int64_t capture_time_ms,
78         const uint8_t* payloadData,
79         const uint32_t payloadSize,
80         const RTPFragmentationHeader& /*fragmentationHeader*/,
81         const webrtc::RTPVideoHeader* videoHdr)
82
83 {
84   // will call the VCMReceiver input packet
85   _frameType = frameType;
86   // writing encodedData into file
87   if (fwrite(payloadData, 1, payloadSize, _encodedFile) !=  payloadSize) {
88     return -1;
89   }
90   WebRtcRTPHeader rtpInfo;
91   rtpInfo.header.markerBit = true;
92   rtpInfo.type.Video.width = 0;
93   rtpInfo.type.Video.height = 0;
94   switch (_test.VideoType())
95   {
96   case kVideoCodecVP8:
97     rtpInfo.type.Video.codec = kRtpVideoVp8;
98     rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8();
99     rtpInfo.type.Video.codecHeader.VP8.nonReference =
100         videoHdr->codecHeader.VP8.nonReference;
101     rtpInfo.type.Video.codecHeader.VP8.pictureId =
102         videoHdr->codecHeader.VP8.pictureId;
103     break;
104   case kVideoCodecVP9:
105     // Leave for now, until we add kRtpVideoVp9 to RTP.
106     break;
107   default:
108     assert(false);
109     return -1;
110   }
111   rtpInfo.header.payloadType = payloadType;
112   rtpInfo.header.sequenceNumber = _seqNo++;
113   rtpInfo.header.ssrc = 0;
114   rtpInfo.header.timestamp = timeStamp;
115   rtpInfo.frameType = frameType;
116   rtpInfo.type.Video.isFirstPacket = true;
117   // Size should also be received from that table, since the payload type
118   // defines the size.
119
120   _encodedBytes += payloadSize;
121   if (payloadSize < 20)
122   {
123       _skipCnt++;
124   }
125   _VCMReceiver->IncomingPacket(payloadData, payloadSize, rtpInfo);
126   return 0;
127 }
128 void
129 VCMNTEncodeCompleteCallback::RegisterReceiverVCM(VideoCodingModule *vcm)
130 {
131   _VCMReceiver = vcm;
132   return;
133 }
134  int32_t
135 VCMNTEncodeCompleteCallback::EncodedBytes()
136 {
137   return _encodedBytes;
138 }
139
140 uint32_t
141 VCMNTEncodeCompleteCallback::SkipCnt()
142 {
143   return _skipCnt;
144 }
145
146 // Decoded Frame Callback Implementation
147 VCMNTDecodeCompleCallback::~VCMNTDecodeCompleCallback()
148 {
149   if (_decodedFile)
150   fclose(_decodedFile);
151 }
152  int32_t
153 VCMNTDecodeCompleCallback::FrameToRender(webrtc::I420VideoFrame& videoFrame)
154 {
155     if (videoFrame.width() != _currentWidth ||
156         videoFrame.height() != _currentHeight)
157     {
158         _currentWidth = videoFrame.width();
159         _currentHeight = videoFrame.height();
160         if (_decodedFile != NULL)
161         {
162             fclose(_decodedFile);
163             _decodedFile = NULL;
164         }
165         _decodedFile = fopen(_outname.c_str(), "wb");
166     }
167     if (PrintI420VideoFrame(videoFrame, _decodedFile) < 0) {
168       return -1;
169     }
170     _decodedBytes+= webrtc::CalcBufferSize(webrtc::kI420,
171                                    videoFrame.width(), videoFrame.height());
172     return VCM_OK;
173 }
174
175  int32_t
176 VCMNTDecodeCompleCallback::DecodedBytes()
177 {
178   return _decodedBytes;
179 }
180
181  //VCM Normal Test Class implementation
182
183 NormalTest::NormalTest(VideoCodingModule* vcm, Clock* clock)
184 :
185 _clock(clock),
186 _vcm(vcm),
187 _sumEncBytes(0),
188 _timeStamp(0),
189 _totalEncodeTime(0),
190 _totalDecodeTime(0),
191 _decodeCompleteTime(0),
192 _encodeCompleteTime(0),
193 _totalEncodePipeTime(0),
194 _totalDecodePipeTime(0),
195 _frameCnt(0),
196 _encFrameCnt(0),
197 _decFrameCnt(0)
198 {
199     //
200 }
201
202 NormalTest::~NormalTest()
203 {
204     //
205 }
206 void
207 NormalTest::Setup(const CmdArgs& args)
208 {
209   _inname = args.inputFile;
210   _encodedName = test::OutputPath() + "encoded_normaltest.yuv";
211   _width = args.width;
212   _height = args.height;
213   _frameRate = args.frameRate;
214   _bitRate = args.bitRate;
215   if (args.outputFile == "")
216   {
217       std::ostringstream filename;
218       filename << test::OutputPath() << "NormalTest_" <<
219           _width << "x" << _height << "_" << _frameRate << "Hz_P420.yuv";
220       _outname = filename.str();
221   }
222   else
223   {
224       _outname = args.outputFile;
225   }
226   _lengthSourceFrame  = 3*_width*_height/2;
227   _videoType = args.codecType;
228
229   if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
230   {
231       printf("Cannot read file %s.\n", _inname.c_str());
232       exit(1);
233   }
234   if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
235   {
236       printf("Cannot write encoded file.\n");
237       exit(1);
238   }
239
240   _log.open((test::OutputPath() + "TestLog.txt").c_str(),
241             std::fstream::out | std::fstream::app);
242 }
243
244 int32_t
245 NormalTest::Perform(const CmdArgs& args)
246 {
247   Setup(args);
248   EventWrapper* waitEvent = EventWrapper::Create();
249   VideoCodec _sendCodec;
250   _vcm->InitializeReceiver();
251   _vcm->InitializeSender();
252   TEST(VideoCodingModule::Codec(_videoType, &_sendCodec) == VCM_OK);
253   // should be later on changed via the API
254   _sendCodec.startBitrate = (int)_bitRate;
255   _sendCodec.width = static_cast<uint16_t>(_width);
256   _sendCodec.height = static_cast<uint16_t>(_height);
257   _sendCodec.maxFramerate = _frameRate;
258   // will also set and init the desired codec
259   TEST(_vcm->RegisterSendCodec(&_sendCodec, 4, 1400) == VCM_OK);
260   // register a decoder (same codec for decoder and encoder )
261   TEST(_vcm->RegisterReceiveCodec(&_sendCodec, 1) == VCM_OK);
262   /* Callback Settings */
263   VCMNTDecodeCompleCallback _decodeCallback(_outname);
264   _vcm->RegisterReceiveCallback(&_decodeCallback);
265   VCMNTEncodeCompleteCallback _encodeCompleteCallback(_encodedFile, *this);
266   _vcm->RegisterTransportCallback(&_encodeCompleteCallback);
267   // encode and decode with the same vcm
268   _encodeCompleteCallback.RegisterReceiverVCM(_vcm);
269   ///////////////////////
270   /// Start Test
271   ///////////////////////
272   I420VideoFrame sourceFrame;
273   int size_y = _width * _height;
274   int half_width = (_width + 1) / 2;
275   int half_height = (_height + 1) / 2;
276   int size_uv = half_width * half_height;
277   sourceFrame.CreateEmptyFrame(_width, _height,
278                                _width, half_width, half_width);
279   uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
280   double startTime = clock()/(double)CLOCKS_PER_SEC;
281   _vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 0, 0);
282
283   SendStatsTest sendStats;
284   sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
285   sendStats.set_bitrate(1000 * _bitRate);
286   _vcm->RegisterSendStatisticsCallback(&sendStats);
287
288   while (feof(_sourceFile) == 0) {
289     TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0 ||
290          feof(_sourceFile));
291     _frameCnt++;
292     sourceFrame.CreateFrame(size_y, tmpBuffer,
293                             size_uv, tmpBuffer + size_y,
294                             size_uv, tmpBuffer + size_y + size_uv,
295                             _width, _height,
296                             _width, half_width, half_width);
297     _timeStamp +=
298         (uint32_t)(9e4 / static_cast<float>(_sendCodec.maxFramerate));
299     sourceFrame.set_timestamp(_timeStamp);
300     _encodeTimes[int(sourceFrame.timestamp())] =
301         clock()/(double)CLOCKS_PER_SEC;
302     int32_t ret = _vcm->AddVideoFrame(sourceFrame);
303     double encodeTime = clock()/(double)CLOCKS_PER_SEC -
304                         _encodeTimes[int(sourceFrame.timestamp())];
305     _totalEncodeTime += encodeTime;
306     if (ret < 0)
307     {
308         printf("Error in AddFrame: %d\n", ret);
309         //exit(1);
310     }
311     _decodeTimes[int(sourceFrame.timestamp())] =
312         clock()/(double)CLOCKS_PER_SEC;
313     ret = _vcm->Decode();
314     _totalDecodeTime += clock()/(double)CLOCKS_PER_SEC -
315                         _decodeTimes[int(sourceFrame.timestamp())];
316     if (ret < 0)
317     {
318         printf("Error in Decode: %d\n", ret);
319         //exit(1);
320     }
321     if (_vcm->TimeUntilNextProcess() <= 0)
322     {
323         _vcm->Process();
324     }
325     uint32_t framePeriod =
326         static_cast<uint32_t>(
327             1000.0f / static_cast<float>(_sendCodec.maxFramerate) + 0.5f);
328     static_cast<SimulatedClock*>(_clock)->AdvanceTimeMilliseconds(framePeriod);
329   }
330   double endTime = clock()/(double)CLOCKS_PER_SEC;
331   _testTotalTime = endTime - startTime;
332   _sumEncBytes = _encodeCompleteCallback.EncodedBytes();
333
334   delete [] tmpBuffer;
335   delete waitEvent;
336   Teardown();
337   Print();
338   return 0;
339 }
340
341 void
342 NormalTest::FrameEncoded(uint32_t timeStamp)
343 {
344   _encodeCompleteTime = clock()/(double)CLOCKS_PER_SEC;
345   _encFrameCnt++;
346   _totalEncodePipeTime += _encodeCompleteTime - _encodeTimes[int(timeStamp)];
347
348 }
349
350 void
351 NormalTest::FrameDecoded(uint32_t timeStamp)
352 {
353   _decodeCompleteTime = clock()/(double)CLOCKS_PER_SEC;
354   _decFrameCnt++;
355   _totalDecodePipeTime += _decodeCompleteTime - _decodeTimes[timeStamp];
356 }
357
358 void
359 NormalTest::Print()
360 {
361   std::cout << "Normal Test Completed!" << std::endl;
362   (_log) << "Normal Test Completed!" << std::endl;
363   (_log) << "Input file: " << _inname << std::endl;
364   (_log) << "Output file: " << _outname << std::endl;
365   (_log) << "Total run time: " << _testTotalTime << std::endl;
366   printf("Total run time: %f s \n", _testTotalTime);
367   double ActualBitRate =  8.0 *( _sumEncBytes / (_frameCnt / _frameRate));
368   double actualBitRate = ActualBitRate / 1000.0;
369   double avgEncTime = _totalEncodeTime / _frameCnt;
370   double avgDecTime = _totalDecodeTime / _frameCnt;
371   webrtc::test::QualityMetricsResult psnr, ssim;
372   I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width, _height,
373                     &psnr);
374   I420SSIMFromFiles(_inname.c_str(), _outname.c_str(), _width, _height,
375                     &ssim);
376   printf("Actual bitrate: %f kbps\n", actualBitRate);
377   printf("Target bitrate: %f kbps\n", _bitRate);
378   ( _log) << "Actual bitrate: " << actualBitRate <<
379       " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
380   printf("Average encode time: %f s\n", avgEncTime);
381   ( _log) << "Average encode time: " << avgEncTime << " s" << std::endl;
382   printf("Average decode time: %f s\n", avgDecTime);
383   ( _log) << "Average decode time: " << avgDecTime << " s" << std::endl;
384   printf("PSNR: %f \n", psnr.average);
385   ( _log) << "PSNR: " << psnr.average << std::endl;
386   printf("SSIM: %f \n", ssim.average);
387   ( _log) << "SSIM: " << ssim.average << std::endl;
388   (_log) << std::endl;
389
390   printf("\nVCM Normal Test: \n\n%i tests completed\n", vcmMacrosTests);
391   if (vcmMacrosErrors > 0)
392   {
393       printf("%i FAILED\n\n", vcmMacrosErrors);
394   }
395   else
396   {
397       printf("ALL PASSED\n\n");
398   }
399 }
400 void
401 NormalTest::Teardown()
402 {
403   //_log.close();
404   fclose(_sourceFile);
405   fclose(_encodedFile);
406   return;
407 }