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_test.h"
12
13#include <sstream>
14#include <string.h>
15#include <time.h>
16
17#include "testing/gtest/include/gtest/gtest.h"
18#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19#include "webrtc/test/testsupport/fileutils.h"
20
21NormalTest::NormalTest()
22:
23CodecTest("Normal Test 1", "A test of normal execution of the codec"),
24_testNo(1),
25_lengthEncFrame(0),
26_appendNext(false)
27{
28}
29
30NormalTest::NormalTest(std::string name, std::string description,
31                       unsigned int testNo)
32:
33CodecTest(name, description),
34_requestKeyFrame(false),
35_testNo(testNo),
36_lengthEncFrame(0),
37_appendNext(false)
38{
39}
40
41NormalTest::NormalTest(std::string name, std::string description,
42                       uint32_t bitRate, unsigned int testNo)
43:
44CodecTest(name, description, bitRate),
45_requestKeyFrame(false),
46_testNo(testNo),
47_lengthEncFrame(0),
48_appendNext(false)
49{
50}
51
52void
53NormalTest::Setup()
54{
55    CodecTest::Setup();
56    std::stringstream ss;
57    std::string strTestNo;
58    ss << _testNo;
59    ss >> strTestNo;
60
61    // Check if settings exist. Otherwise use defaults.
62    if (_outname == "")
63    {
64        _outname = webrtc::test::OutputPath() + "out_normaltest" + strTestNo +
65            ".yuv";
66    }
67
68    if (_encodedName == "")
69    {
70        _encodedName = webrtc::test::OutputPath() + "encoded_normaltest" +
71            strTestNo + ".yuv";
72    }
73
74    if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
75    {
76        printf("Cannot read file %s.\n", _inname.c_str());
77        exit(1);
78    }
79
80    if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
81    {
82        printf("Cannot write encoded file.\n");
83        exit(1);
84    }
85
86    char mode[3] = "wb";
87    if (_appendNext)
88    {
89        strncpy(mode, "ab", 3);
90    }
91
92    if ((_decodedFile = fopen(_outname.c_str(), mode)) == NULL)
93    {
94        printf("Cannot write file %s.\n", _outname.c_str());
95        exit(1);
96    }
97
98    _appendNext = true;
99}
100
101void
102NormalTest::Teardown()
103{
104    CodecTest::Teardown();
105    fclose(_sourceFile);
106    fclose(_decodedFile);
107}
108
109void
110NormalTest::Perform()
111{
112    _width = 352;
113    _halfWidth = (_width + 1) / 2;
114    _height = 288;
115    _halfHeight = (_height + 1) / 2;
116    _sizeY = _width * _height;
117    _sizeUv = _halfWidth * _halfHeight;
118    _inname = webrtc::test::ProjectRootPath() + "resources/foreman_cif.yuv";
119    CodecSettings(_width, _height, 30, _bitRate);
120    Setup();
121
122    _inputVideoBuffer.CreateEmptyFrame(_width, _height,
123                                       _width, _halfWidth, _halfWidth);
124    _decodedVideoBuffer.CreateEmptyFrame(_width, _height,
125                                         _width, _halfWidth, _halfWidth);
126    _encodedVideoBuffer.VerifyAndAllocate(_lengthSourceFrame);
127
128    _encoder->InitEncode(&_inst, 1, 1460);
129    CodecSpecific_InitBitrate();
130    _decoder->InitDecode(&_inst,1);
131
132    _totalEncodeTime = _totalDecodeTime = 0;
133    _framecnt = 0;
134    _sumEncBytes = 0;
135    _lengthEncFrame = 0;
136    int decodeLength = 0;
137    while (!Encode())
138    {
139        DoPacketLoss();
140        _encodedVideoBuffer.SetLength(_encodedVideoBuffer.Length());
141        if (fwrite(_encodedVideoBuffer.Buffer(), 1,
142                   _encodedVideoBuffer.Length(),
143                   _encodedFile) !=  _encodedVideoBuffer.Length()) {
144          return;
145        }
146        decodeLength = Decode();
147        if (decodeLength < 0)
148        {
149            fprintf(stderr,"\n\nError in decoder: %d\n\n", decodeLength);
150            exit(EXIT_FAILURE);
151        }
152        if (PrintI420VideoFrame(_decodedVideoBuffer, _decodedFile) < 0) {
153          return;
154        }
155        CodecSpecific_InitBitrate();
156        _framecnt++;
157    }
158
159    // Ensure we empty the decoding queue.
160    while (decodeLength > 0)
161    {
162        decodeLength = Decode();
163        if (decodeLength < 0)
164        {
165            fprintf(stderr,"\n\nError in decoder: %d\n\n", decodeLength);
166            exit(EXIT_FAILURE);
167        }
168        if (PrintI420VideoFrame(_decodedVideoBuffer, _decodedFile) < 0) {
169          return;
170        }
171    }
172
173    double actualBitRate = ActualBitRate(_framecnt) / 1000.0;
174    double avgEncTime = _totalEncodeTime / _framecnt;
175    double avgDecTime = _totalDecodeTime / _framecnt;
176    printf("Actual bitrate: %f kbps\n", actualBitRate);
177    printf("Average encode time: %f s\n", avgEncTime);
178    printf("Average decode time: %f s\n", avgDecTime);
179    (*_log) << "Actual bitrate: " << actualBitRate << " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
180    (*_log) << "Average encode time: " << avgEncTime << " s" << std::endl;
181    (*_log) << "Average decode time: " << avgDecTime << " s" << std::endl;
182
183    _encoder->Release();
184    _decoder->Release();
185
186    Teardown();
187}
188
189bool
190NormalTest::Encode()
191{
192    _lengthEncFrame = 0;
193    EXPECT_GT(fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile), 0u);
194    if (feof(_sourceFile) != 0)
195    {
196        return true;
197    }
198        _inputVideoBuffer.CreateFrame(_sizeY, _sourceBuffer,
199                                      _sizeUv, _sourceBuffer + _sizeY,
200                                      _sizeUv, _sourceBuffer + _sizeY +
201                                      _sizeUv,
202                                      _width, _height,
203                                      _width, _halfWidth, _halfWidth);
204    _inputVideoBuffer.set_timestamp(_framecnt);
205
206    // This multiple attempt ridiculousness is to accomodate VP7:
207    // 1. The wrapper can unilaterally reduce the framerate for low bitrates.
208    // 2. The codec inexplicably likes to reject some frames. Perhaps there
209    //    is a good reason for this...
210    int encodingAttempts = 0;
211    double starttime = 0;
212    double endtime = 0;
213    while (_lengthEncFrame == 0)
214    {
215        starttime = clock()/(double)CLOCKS_PER_SEC;
216
217        _inputVideoBuffer.set_width(_inst.width);
218        _inputVideoBuffer.set_height(_inst.height);
219        endtime = clock()/(double)CLOCKS_PER_SEC;
220
221        _encodedVideoBuffer.SetHeight(_inst.height);
222        _encodedVideoBuffer.SetWidth(_inst.width);
223        if (_lengthEncFrame < 0)
224        {
225            (*_log) << "Error in encoder: " << _lengthEncFrame << std::endl;
226            fprintf(stderr,"\n\nError in encoder: %d\n\n", _lengthEncFrame);
227            exit(EXIT_FAILURE);
228        }
229        _sumEncBytes += _lengthEncFrame;
230
231        encodingAttempts++;
232        if (encodingAttempts > 50)
233        {
234            (*_log) << "Unable to encode frame: " << _framecnt << std::endl;
235            fprintf(stderr,"\n\nUnable to encode frame: %d\n\n", _framecnt);
236            exit(EXIT_FAILURE);
237        }
238    }
239    _totalEncodeTime += endtime - starttime;
240
241    if (encodingAttempts > 1)
242    {
243        (*_log) << encodingAttempts << " attempts required to encode frame: " <<
244            _framecnt + 1 << std::endl;
245        fprintf(stderr,"\n%d attempts required to encode frame: %d\n", encodingAttempts,
246            _framecnt + 1);
247    }
248
249    return false;
250}
251
252int
253NormalTest::Decode(int lossValue)
254{
255    _encodedVideoBuffer.SetWidth(_inst.width);
256    _encodedVideoBuffer.SetHeight(_inst.height);
257    int lengthDecFrame = 0;
258    if (lengthDecFrame < 0)
259    {
260        return lengthDecFrame;
261    }
262    _encodedVideoBuffer.SetLength(0);
263    return lengthDecFrame;
264}
265