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