• 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 #include "webrtc/modules/video_coding/codecs/test_framework/normal_async_test.h"
12 
13 #include <assert.h>
14 #include <queue>
15 #include <sstream>
16 #include <string.h>
17 #include <vector>
18 
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
21 #include "webrtc/system_wrappers/interface/tick_util.h"
22 #include "webrtc/test/testsupport/fileutils.h"
23 #include "webrtc/typedefs.h"
24 
25 using namespace webrtc;
26 
NormalAsyncTest()27 NormalAsyncTest::NormalAsyncTest()
28 :
29 NormalTest("Async Normal Test 1", "A test of normal execution of the codec", 1),
30 _decodeCompleteTime(0),
31 _encodeCompleteTime(0),
32 _encFrameCnt(0),
33 _decFrameCnt(0),
34 _requestKeyFrame(false),
35 _appendNext(false),
36 _missingFrames(false),
37 _rttFrames(0),
38 _hasReceivedSLI(false),
39 _hasReceivedRPSI(false),
40 _hasReceivedPLI(false),
41 _waitForKey(false)
42 {
43 }
44 
NormalAsyncTest(uint32_t bitRate)45 NormalAsyncTest::NormalAsyncTest(uint32_t bitRate)
46 :
47 NormalTest("Async Normal Test 1", "A test of normal execution of the codec",
48            bitRate,
49            1),
50 _decodeCompleteTime(0),
51 _encodeCompleteTime(0),
52 _encFrameCnt(0),
53 _decFrameCnt(0),
54 _requestKeyFrame(false),
55 _appendNext(false),
56 _missingFrames(false),
57 _rttFrames(0),
58 _hasReceivedSLI(false),
59 _hasReceivedRPSI(false),
60 _hasReceivedPLI(false),
61 _waitForKey(false)
62 {
63 }
64 
NormalAsyncTest(std::string name,std::string description,unsigned int testNo)65 NormalAsyncTest::NormalAsyncTest(std::string name, std::string description,
66                                  unsigned int testNo)
67 :
68 NormalTest(name, description, testNo),
69 _decodeCompleteTime(0),
70 _encodeCompleteTime(0),
71 _encFrameCnt(0),
72 _decFrameCnt(0),
73 _requestKeyFrame(false),
74 _lengthEncFrame(0),
75 _appendNext(false),
76 _missingFrames(false),
77 _rttFrames(0),
78 _hasReceivedSLI(false),
79 _hasReceivedRPSI(false),
80 _hasReceivedPLI(false),
81 _waitForKey(false)
82 {
83 }
84 
NormalAsyncTest(std::string name,std::string description,uint32_t bitRate,unsigned int testNo)85 NormalAsyncTest::NormalAsyncTest(std::string name, std::string description,
86                                  uint32_t bitRate, unsigned int testNo)
87 :
88 NormalTest(name, description, bitRate, testNo),
89 _decodeCompleteTime(0),
90 _encodeCompleteTime(0),
91 _encFrameCnt(0),
92 _decFrameCnt(0),
93 _requestKeyFrame(false),
94 _lengthEncFrame(0),
95 _appendNext(false),
96 _missingFrames(false),
97 _rttFrames(0),
98 _hasReceivedSLI(false),
99 _hasReceivedRPSI(false),
100 _hasReceivedPLI(false),
101 _waitForKey(false)
102 {
103 }
104 
NormalAsyncTest(std::string name,std::string description,uint32_t bitRate,unsigned int testNo,unsigned int rttFrames)105 NormalAsyncTest::NormalAsyncTest(std::string name, std::string description,
106                                  uint32_t bitRate, unsigned int testNo,
107                                  unsigned int rttFrames)
108 :
109 NormalTest(name, description, bitRate, testNo),
110 _decodeCompleteTime(0),
111 _encodeCompleteTime(0),
112 _encFrameCnt(0),
113 _decFrameCnt(0),
114 _requestKeyFrame(false),
115 _lengthEncFrame(0),
116 _appendNext(false),
117 _missingFrames(false),
118 _rttFrames(rttFrames),
119 _hasReceivedSLI(false),
120 _hasReceivedRPSI(false),
121 _hasReceivedPLI(false),
122 _waitForKey(false)
123 {
124 }
125 
126 void
Setup()127 NormalAsyncTest::Setup()
128 {
129     CodecTest::Setup();
130     std::stringstream ss;
131     std::string strTestNo;
132     ss << _testNo;
133     ss >> strTestNo;
134 
135     // Check if settings exist. Otherwise use defaults.
136     if (_outname == "")
137     {
138         _outname = webrtc::test::OutputPath() + "out_normaltest" + strTestNo +
139             ".yuv";
140     }
141 
142     if (_encodedName == "")
143     {
144         _encodedName = webrtc::test::OutputPath() + "encoded_normaltest" +
145             strTestNo + ".yuv";
146     }
147 
148     if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
149     {
150         printf("Cannot read file %s.\n", _inname.c_str());
151         exit(1);
152     }
153 
154     if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
155     {
156         printf("Cannot write encoded file.\n");
157         exit(1);
158     }
159 
160     char mode[3] = "wb";
161     if (_appendNext)
162     {
163         strncpy(mode, "ab", 3);
164     }
165 
166     if ((_decodedFile = fopen(_outname.c_str(), mode)) == NULL)
167     {
168         printf("Cannot write file %s.\n", _outname.c_str());
169         exit(1);
170     }
171 
172     _appendNext = true;
173 }
174 
175 void
Teardown()176 NormalAsyncTest::Teardown()
177 {
178     CodecTest::Teardown();
179     fclose(_sourceFile);
180     fclose(_encodedFile);
181     fclose(_decodedFile);
182 }
183 
~FrameQueueTuple()184 FrameQueueTuple::~FrameQueueTuple()
185 {
186     if (_codecSpecificInfo != NULL)
187     {
188         delete _codecSpecificInfo;
189     }
190     if (_frame != NULL)
191     {
192         delete _frame;
193     }
194 }
195 
PushFrame(VideoFrame * frame,webrtc::CodecSpecificInfo * codecSpecificInfo)196 void FrameQueue::PushFrame(VideoFrame *frame,
197                            webrtc::CodecSpecificInfo* codecSpecificInfo)
198 {
199     WriteLockScoped cs(_queueRWLock);
200     _frameBufferQueue.push(new FrameQueueTuple(frame, codecSpecificInfo));
201 }
202 
PopFrame()203 FrameQueueTuple* FrameQueue::PopFrame()
204 {
205     WriteLockScoped cs(_queueRWLock);
206     if (_frameBufferQueue.empty())
207     {
208         return NULL;
209     }
210     FrameQueueTuple* tuple = _frameBufferQueue.front();
211     _frameBufferQueue.pop();
212     return tuple;
213 }
214 
Empty()215 bool FrameQueue::Empty()
216 {
217     ReadLockScoped cs(_queueRWLock);
218     return _frameBufferQueue.empty();
219 }
220 
EncodedBytes()221 uint32_t VideoEncodeCompleteCallback::EncodedBytes()
222 {
223     return _encodedBytes;
224 }
225 
226 int32_t
Encoded(EncodedImage & encodedImage,const webrtc::CodecSpecificInfo * codecSpecificInfo,const webrtc::RTPFragmentationHeader * fragmentation)227 VideoEncodeCompleteCallback::Encoded(EncodedImage& encodedImage,
228                                      const webrtc::CodecSpecificInfo* codecSpecificInfo,
229                                      const webrtc::RTPFragmentationHeader*
230                                      fragmentation)
231 {
232     _test.Encoded(encodedImage);
233     VideoFrame *newBuffer = new VideoFrame();
234     newBuffer->VerifyAndAllocate(encodedImage._size);
235     _encodedBytes += encodedImage._length;
236     // If _frameQueue would have been a fixed sized buffer we could have asked
237     // it for an empty frame and then just do:
238     // emptyFrame->SwapBuffers(encodedBuffer);
239     // This is how it should be done in Video Engine to save in on memcpys
240     webrtc::CodecSpecificInfo* codecSpecificInfoCopy =
241         _test.CopyCodecSpecificInfo(codecSpecificInfo);
242     _test.CopyEncodedImage(*newBuffer, encodedImage, codecSpecificInfoCopy);
243     if (_encodedFile != NULL)
244     {
245       if (fwrite(newBuffer->Buffer(), 1, newBuffer->Length(),
246                  _encodedFile) !=  newBuffer->Length()) {
247         return -1;
248       }
249     }
250     _frameQueue->PushFrame(newBuffer, codecSpecificInfoCopy);
251     return 0;
252 }
253 
DecodedBytes()254 uint32_t VideoDecodeCompleteCallback::DecodedBytes()
255 {
256     return _decodedBytes;
257 }
258 
259 int32_t
Decoded(I420VideoFrame & image)260 VideoDecodeCompleteCallback::Decoded(I420VideoFrame& image)
261 {
262     _test.Decoded(image);
263     _decodedBytes += CalcBufferSize(kI420, image.width(), image.height());
264     if (_decodedFile != NULL)
265     {
266        return PrintI420VideoFrame(image, _decodedFile);
267     }
268     return 0;
269 }
270 
271 int32_t
ReceivedDecodedReferenceFrame(const uint64_t pictureId)272 VideoDecodeCompleteCallback::ReceivedDecodedReferenceFrame(
273     const uint64_t pictureId)
274 {
275     return _test.ReceivedDecodedReferenceFrame(pictureId);
276 }
277 
278 int32_t
ReceivedDecodedFrame(const uint64_t pictureId)279 VideoDecodeCompleteCallback::ReceivedDecodedFrame(
280     const uint64_t pictureId)
281 {
282     return _test.ReceivedDecodedFrame(pictureId);
283 }
284 
285 void
Encoded(const EncodedImage & encodedImage)286 NormalAsyncTest::Encoded(const EncodedImage& encodedImage)
287 {
288     _encodeCompleteTime = tGetTime();
289     _encFrameCnt++;
290     _totalEncodePipeTime += _encodeCompleteTime -
291         _encodeTimes[encodedImage._timeStamp];
292 }
293 
294 void
Decoded(const I420VideoFrame & decodedImage)295 NormalAsyncTest::Decoded(const I420VideoFrame& decodedImage)
296 {
297     _decodeCompleteTime = tGetTime();
298     _decFrameCnt++;
299     _totalDecodePipeTime += _decodeCompleteTime -
300         _decodeTimes[decodedImage.timestamp()];
301     _decodedWidth = decodedImage.width();
302     _decodedHeight = decodedImage.height();
303 }
304 
305 void
Perform()306 NormalAsyncTest::Perform()
307 {
308     _inname = webrtc::test::ProjectRootPath() + "resources/foreman_cif.yuv";
309     CodecSettings(352, 288, 30, _bitRate);
310     Setup();
311     if(_encoder->InitEncode(&_inst, 1, 1440) < 0)
312     {
313         exit(EXIT_FAILURE);
314     }
315     _decoder->InitDecode(&_inst, 1);
316     FrameQueue frameQueue;
317     VideoEncodeCompleteCallback encCallback(_encodedFile, &frameQueue, *this);
318     VideoDecodeCompleteCallback decCallback(_decodedFile, *this);
319     _encoder->RegisterEncodeCompleteCallback(&encCallback);
320     _decoder->RegisterDecodeCompleteCallback(&decCallback);
321     if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK)
322     {
323         exit(EXIT_FAILURE);
324     }
325     _totalEncodeTime = _totalDecodeTime = 0;
326     _totalEncodePipeTime = _totalDecodePipeTime = 0;
327     bool complete = false;
328     _framecnt = 0;
329     _encFrameCnt = 0;
330     _decFrameCnt = 0;
331     _sumEncBytes = 0;
332     _lengthEncFrame = 0;
333     double starttime = tGetTime();
334     while (!complete)
335     {
336         CodecSpecific_InitBitrate();
337         complete = Encode();
338         if (!frameQueue.Empty() || complete)
339         {
340             while (!frameQueue.Empty())
341             {
342                 _frameToDecode =
343                     static_cast<FrameQueueTuple *>(frameQueue.PopFrame());
344                 int lost = DoPacketLoss();
345                 if (lost == 2)
346                 {
347                     // Lost the whole frame, continue
348                     _missingFrames = true;
349                     delete _frameToDecode;
350                     _frameToDecode = NULL;
351                     continue;
352                 }
353                 int ret = Decode(lost);
354                 delete _frameToDecode;
355                 _frameToDecode = NULL;
356                 if (ret < 0)
357                 {
358                     fprintf(stderr,"\n\nError in decoder: %d\n\n", ret);
359                     exit(EXIT_FAILURE);
360                 }
361                 else if (ret == 0)
362                 {
363                     _framecnt++;
364                 }
365                 else
366                 {
367                     fprintf(stderr,
368                         "\n\nPositive return value from decode!\n\n");
369                 }
370             }
371         }
372     }
373     double endtime = tGetTime();
374     double totalExecutionTime = endtime - starttime;
375     printf("Total execution time: %.1f s\n", totalExecutionTime);
376     _sumEncBytes = encCallback.EncodedBytes();
377     double actualBitRate = ActualBitRate(_encFrameCnt) / 1000.0;
378     double avgEncTime = _totalEncodeTime / _encFrameCnt;
379     double avgDecTime = _totalDecodeTime / _decFrameCnt;
380     printf("Actual bitrate: %f kbps\n", actualBitRate);
381     printf("Average encode time: %.1f ms\n", 1000 * avgEncTime);
382     printf("Average decode time: %.1f ms\n", 1000 * avgDecTime);
383     printf("Average encode pipeline time: %.1f ms\n",
384            1000 * _totalEncodePipeTime / _encFrameCnt);
385     printf("Average decode pipeline  time: %.1f ms\n",
386            1000 * _totalDecodePipeTime / _decFrameCnt);
387     printf("Number of encoded frames: %u\n", _encFrameCnt);
388     printf("Number of decoded frames: %u\n", _decFrameCnt);
389     (*_log) << "Actual bitrate: " << actualBitRate << " kbps\tTarget: " <<
390         _bitRate << " kbps" << std::endl;
391     (*_log) << "Average encode time: " << avgEncTime << " s" << std::endl;
392     (*_log) << "Average decode time: " << avgDecTime << " s" << std::endl;
393     _encoder->Release();
394     _decoder->Release();
395     Teardown();
396 }
397 
398 bool
Encode()399 NormalAsyncTest::Encode()
400 {
401     _lengthEncFrame = 0;
402     if (feof(_sourceFile) != 0)
403     {
404         return true;
405     }
406     EXPECT_GT(fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile), 0u);
407     EXPECT_EQ(0, _inputVideoBuffer.CreateFrame(_sizeY, _sourceBuffer,
408                                   _sizeUv, _sourceBuffer + _sizeY,
409                                   _sizeUv, _sourceBuffer + _sizeY + _sizeUv,
410                                   _width, _height,
411                                   _width, _halfWidth, _halfWidth));
412     _inputVideoBuffer.set_timestamp((unsigned int)
413         (_encFrameCnt * 9e4 / _inst.maxFramerate));
414     _encodeCompleteTime = 0;
415     _encodeTimes[_inputVideoBuffer.timestamp()] = tGetTime();
416     std::vector<VideoFrameType> frame_types(1, kDeltaFrame);
417 
418     // check SLI queue
419     _hasReceivedSLI = false;
420     while (!_signalSLI.empty() && _signalSLI.front().delay == 0)
421     {
422         // SLI message has arrived at sender side
423         _hasReceivedSLI = true;
424         _pictureIdSLI = _signalSLI.front().id;
425         _signalSLI.pop_front();
426     }
427     // decrement SLI queue times
428     for (std::list<fbSignal>::iterator it = _signalSLI.begin();
429         it !=_signalSLI.end(); it++)
430     {
431         (*it).delay--;
432     }
433 
434     // check PLI queue
435     _hasReceivedPLI = false;
436     while (!_signalPLI.empty() && _signalPLI.front().delay == 0)
437     {
438         // PLI message has arrived at sender side
439         _hasReceivedPLI = true;
440         _signalPLI.pop_front();
441     }
442     // decrement PLI queue times
443     for (std::list<fbSignal>::iterator it = _signalPLI.begin();
444         it != _signalPLI.end(); it++)
445     {
446         (*it).delay--;
447     }
448 
449     if (_hasReceivedPLI)
450     {
451         // respond to PLI by encoding a key frame
452         frame_types[0] = kKeyFrame;
453         _hasReceivedPLI = false;
454         _hasReceivedSLI = false; // don't trigger both at once
455     }
456 
457     webrtc::CodecSpecificInfo* codecSpecificInfo = CreateEncoderSpecificInfo();
458     int ret = _encoder->Encode(_inputVideoBuffer,
459                                codecSpecificInfo, &frame_types);
460     EXPECT_EQ(ret, WEBRTC_VIDEO_CODEC_OK);
461     if (codecSpecificInfo != NULL)
462     {
463         delete codecSpecificInfo;
464         codecSpecificInfo = NULL;
465     }
466     if (_encodeCompleteTime > 0)
467     {
468         _totalEncodeTime += _encodeCompleteTime -
469             _encodeTimes[_inputVideoBuffer.timestamp()];
470     }
471     else
472     {
473         _totalEncodeTime += tGetTime() -
474             _encodeTimes[_inputVideoBuffer.timestamp()];
475     }
476     assert(ret >= 0);
477     return false;
478 }
479 
480 int
Decode(int lossValue)481 NormalAsyncTest::Decode(int lossValue)
482 {
483     _sumEncBytes += _frameToDecode->_frame->Length();
484     EncodedImage encodedImage;
485     VideoEncodedBufferToEncodedImage(*(_frameToDecode->_frame), encodedImage);
486     encodedImage._completeFrame = !lossValue;
487     _decodeCompleteTime = 0;
488     _decodeTimes[encodedImage._timeStamp] = tGetTime();
489     int ret = WEBRTC_VIDEO_CODEC_OK;
490     // TODO(mikhal):  Update frame type.
491     //if (!_waitForKey || encodedImage._frameType == kKeyFrame)
492     {
493         _waitForKey = false;
494         ret = _decoder->Decode(encodedImage, _missingFrames, NULL,
495                                _frameToDecode->_codecSpecificInfo);
496 
497         if (ret >= 0)
498         {
499             _missingFrames = false;
500         }
501     }
502 
503     // check for SLI
504     if (ret == WEBRTC_VIDEO_CODEC_REQUEST_SLI)
505     {
506         // add an SLI feedback to the feedback "queue"
507         // to be delivered to encoder with _rttFrames delay
508         _signalSLI.push_back(fbSignal(_rttFrames,
509             static_cast<uint8_t>((_lastDecPictureId) & 0x3f))); // 6 lsb
510 
511         ret = WEBRTC_VIDEO_CODEC_OK;
512     }
513     else if (ret == WEBRTC_VIDEO_CODEC_ERR_REQUEST_SLI)
514     {
515         // add an SLI feedback to the feedback "queue"
516         // to be delivered to encoder with _rttFrames delay
517         _signalSLI.push_back(fbSignal(_rttFrames,
518             static_cast<uint8_t>((_lastDecPictureId + 1) & 0x3f)));//6 lsb
519 
520         ret = WEBRTC_VIDEO_CODEC_OK;
521     }
522     else if (ret == WEBRTC_VIDEO_CODEC_ERROR)
523     {
524         // wait for new key frame
525         // add an PLI feedback to the feedback "queue"
526         // to be delivered to encoder with _rttFrames delay
527         _signalPLI.push_back(fbSignal(_rttFrames, 0 /* picId not used*/));
528         _waitForKey = true;
529 
530         ret = WEBRTC_VIDEO_CODEC_OK;
531     }
532 
533     if (_decodeCompleteTime > 0)
534     {
535         _totalDecodeTime += _decodeCompleteTime -
536             _decodeTimes[encodedImage._timeStamp];
537     }
538     else
539     {
540         _totalDecodeTime += tGetTime() - _decodeTimes[encodedImage._timeStamp];
541     }
542     return ret;
543 }
544 
545 webrtc::CodecSpecificInfo*
CopyCodecSpecificInfo(const webrtc::CodecSpecificInfo * codecSpecificInfo) const546 NormalAsyncTest::CopyCodecSpecificInfo(
547         const webrtc::CodecSpecificInfo* codecSpecificInfo) const
548 {
549     webrtc::CodecSpecificInfo* info = new webrtc::CodecSpecificInfo;
550     *info = *codecSpecificInfo;
551     return info;
552 }
553 
CodecSpecific_InitBitrate()554 void NormalAsyncTest::CodecSpecific_InitBitrate()
555 {
556     if (_bitRate == 0)
557     {
558         _encoder->SetRates(600, _inst.maxFramerate);
559     }
560     else
561     {
562         _encoder->SetRates(_bitRate, _inst.maxFramerate);
563     }
564 }
565 
CopyEncodedImage(VideoFrame & dest,EncodedImage & src,void *) const566 void NormalAsyncTest::CopyEncodedImage(VideoFrame& dest,
567                                        EncodedImage& src,
568                                        void* /*codecSpecificInfo*/) const
569 {
570     dest.CopyFrame(src._length, src._buffer);
571     //dest.SetFrameType(src._frameType);
572     dest.SetWidth((uint16_t)src._encodedWidth);
573     dest.SetHeight((uint16_t)src._encodedHeight);
574     dest.SetTimeStamp(src._timeStamp);
575 }
576 
ReceivedDecodedReferenceFrame(const uint64_t pictureId)577 int32_t NormalAsyncTest::ReceivedDecodedReferenceFrame(
578     const uint64_t pictureId) {
579   _lastDecRefPictureId = pictureId;
580   return 0;
581 }
582 
ReceivedDecodedFrame(const uint64_t pictureId)583 int32_t NormalAsyncTest::ReceivedDecodedFrame(
584     const uint64_t pictureId) {
585   _lastDecPictureId = pictureId;
586   return 0;
587 }
588 
589 double
tGetTime()590 NormalAsyncTest::tGetTime()
591 {// return time in sec
592     return ((double) (TickTime::MillisecondTimestamp())/1000);
593  }
594