• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "Mpeg4H263EncoderTest"
19 #include <utils/Log.h>
20 
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/stat.h>
25 
26 #include "mp4enc_api.h"
27 
28 #include "Mpeg4H263EncoderTestEnvironment.h"
29 
30 #define ENCODED_FILE "/data/local/tmp/Mpeg4H263Output"
31 
32 // assuming a worst case compression of 2X
33 constexpr int16_t kCompressionRatio = 2;
34 constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;
35 
36 static Mpeg4H263EncoderTestEnvironment *gEnv = nullptr;
37 
38 class Mpeg4H263EncoderTest
39     : public ::testing::TestWithParam<tuple<string, bool, int32_t, int32_t, float, int32_t>> {
40   private:
41     void initEncoderParams();
42 
43   public:
Mpeg4H263EncoderTest()44     Mpeg4H263EncoderTest()
45         : mInputBuffer(nullptr),
46           mOutputBuffer(nullptr),
47           mFpInput(nullptr),
48           mFpOutput(nullptr),
49           mEncodeHandle(nullptr),
50           mEncodeControl(nullptr) {}
51 
~Mpeg4H263EncoderTest()52     ~Mpeg4H263EncoderTest() {
53         if(mFpInput) {
54             fclose(mFpInput);
55         }
56         if(mFpOutput) {
57             fclose(mFpOutput);
58         }
59         if(mInputBuffer) free(mInputBuffer);
60         if(mOutputBuffer) free(mOutputBuffer);
61         if(mEncodeHandle) free(mEncodeHandle);
62         if(mEncodeControl) free(mEncodeControl);
63     }
64 
SetUp()65     void SetUp() override {
66         tuple<string /* fileName */, bool /* isMpeg4 */, int32_t /* frameWidth */,
67           int32_t /* frameHeight */, float /* frameRate */, int32_t /* bitRate */>
68             params = GetParam();
69         mFileName = gEnv->getRes() + get<0>(params);
70         mIsMpeg4 = get<1>(params);
71         mFrameWidth = get<2>(params);
72         mFrameHeight = get<3>(params);
73         mFrameRate = get<4>(params);
74         mBitRate = get<5>(params);
75 
76         ASSERT_TRUE(mFrameWidth % 16 == 0) << "Frame Width should be multiple of 16";
77         ASSERT_TRUE(mFrameHeight % 16 == 0) << "Frame Height should be multiple of 16";
78         ASSERT_LE(mFrameWidth, (mIsMpeg4 ? 720 : 352))
79                 << "Frame Width <= 720 for Mpeg4 and <= 352 for H263";
80         ASSERT_LE(mFrameHeight, (mIsMpeg4 ? 480 : 288))
81                 << "Frame Height <= 480 for Mpeg4 and <= 288 for H263";
82         ASSERT_LE(mFrameRate, 30) << "Frame rate less than or equal to 30";
83         ASSERT_LE(mBitRate, 2048) << "Bit rate less than or equal to 2048 kbps";
84 
85         mOutputBufferSize = ( mFrameWidth * mFrameHeight * 3/2 ) / kCompressionRatio;
86         mEncodeHandle = new VideoEncOptions;
87         ASSERT_NE(mEncodeHandle, nullptr) << "Failed to get Video Encoding options object";
88         memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
89         mEncodeControl = new VideoEncControls;
90         ASSERT_NE(mEncodeControl, nullptr) << "Failed to get Video Encoding control object";
91         memset(mEncodeControl, 0, sizeof(VideoEncControls));
92         ASSERT_NO_FATAL_FAILURE(initEncoderParams())
93                 << "Failed to get the default Encoding parameters!";
94     }
95 
96     int64_t getTotalFrames();
97     void processEncoder(int32_t);
98     bool mIsMpeg4;
99     int32_t mFrameWidth, mFrameHeight, mBitRate;
100     int64_t mOutputBufferSize;
101     float mFrameRate;
102     string mFileName;
103     uint8_t *mInputBuffer, *mOutputBuffer;
104     FILE *mFpInput, *mFpOutput;
105     VideoEncOptions *mEncodeHandle;
106     VideoEncControls *mEncodeControl;
107 };
108 
initEncoderParams()109 void Mpeg4H263EncoderTest::initEncoderParams() {
110     bool status = PVGetDefaultEncOption(mEncodeHandle, 0);
111     ASSERT_TRUE(status);
112 
113     mEncodeHandle->rcType = VBR_1;
114     mEncodeHandle->vbvDelay = 5.0f;
115     mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
116     mEncodeHandle->packetSize = 32;
117     mEncodeHandle->rvlcEnable = PV_OFF;
118     mEncodeHandle->numLayers = 1;
119     mEncodeHandle->timeIncRes = 1000;
120     mEncodeHandle->iQuant[0] = 15;
121     mEncodeHandle->pQuant[0] = 12;
122     mEncodeHandle->quantType[0] = 0;
123     mEncodeHandle->noFrameSkipped = PV_OFF;
124     mEncodeHandle->numIntraMB = 0;
125     mEncodeHandle->sceneDetect = PV_ON;
126     mEncodeHandle->searchRange = 16;
127     mEncodeHandle->mv8x8Enable = PV_OFF;
128     mEncodeHandle->gobHeaderInterval = 0;
129     mEncodeHandle->useACPred = PV_ON;
130     mEncodeHandle->intraDCVlcTh = 0;
131     if(!mIsMpeg4) {
132         mEncodeHandle->encMode = H263_MODE;
133     } else {
134         mEncodeHandle->encMode = COMBINE_MODE_WITH_ERR_RES;
135     }
136     mEncodeHandle->encWidth[0] = mFrameWidth;
137     mEncodeHandle->encHeight[0] = mFrameHeight;
138     mEncodeHandle->encFrameRate[0] = mFrameRate;
139     mEncodeHandle->bitRate[0] = mBitRate * 1024;
140     mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
141     if (kIDRFrameRefreshIntervalInSec == 0) {
142         // All I frames.
143         mEncodeHandle->intraPeriod = 1;
144     } else {
145         mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
146     }
147 }
148 
getTotalFrames()149 int64_t Mpeg4H263EncoderTest::getTotalFrames() {
150     int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
151     struct stat buf;
152     stat(mFileName.c_str(), &buf);
153     size_t fileSize = buf.st_size;
154     int64_t totalFrames = (int64_t)(fileSize/frameSize);
155     return totalFrames;
156 }
157 
processEncoder(int32_t numFramesToEncode)158 void Mpeg4H263EncoderTest::processEncoder(int32_t numFramesToEncode) {
159     bool status;
160     int64_t numEncodedFrames = 0;
161     int32_t bytesRead;
162     int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
163     while(numFramesToEncode != 0) {
164         bytesRead = fread(mInputBuffer, 1, frameSize, mFpInput);
165         // End of file.
166         if (bytesRead != frameSize) {
167             break;
168         }
169 
170         VideoEncFrameIO videoIn, videoOut;
171         videoIn.height = mFrameHeight;
172         videoIn.pitch = mFrameWidth;
173         videoIn.timestamp = (numEncodedFrames * 1000) / mFrameRate;  // in ms.
174         videoIn.yChan = mInputBuffer;
175         videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
176         videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
177         uint32_t modTimeMs = 0;
178         int32_t dataLength = mOutputBufferSize;
179         int32_t nLayer = 0;
180         status = PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, mOutputBuffer,
181                                     &dataLength, &nLayer);
182         ASSERT_TRUE(status) << "Failed to Encode: " << mFileName;
183 
184         MP4HintTrack hintTrack;
185         status = PVGetHintTrack(mEncodeControl, &hintTrack);
186         ASSERT_TRUE(status) << "Failed to get hint track!";
187         UChar *overrunBuffer = PVGetOverrunBuffer(mEncodeControl);
188         ASSERT_EQ(overrunBuffer, nullptr) << "Overrun of buffer!";
189 
190         int64_t numBytes = fwrite(mOutputBuffer, 1, dataLength, mFpOutput);
191         ASSERT_EQ(numBytes, dataLength) << "Failed to write to the output file!";
192         numEncodedFrames++;
193         numFramesToEncode--;
194     }
195 }
196 
TEST_P(Mpeg4H263EncoderTest,EncodeTest)197 TEST_P(Mpeg4H263EncoderTest, EncodeTest) {
198     mInputBuffer = (uint8_t *)malloc((mFrameWidth * mFrameWidth * 3) / 2);
199     ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate the input buffer!";
200 
201     mOutputBuffer = (uint8_t *)malloc(mOutputBufferSize);
202     ASSERT_NE(mOutputBuffer, nullptr) << "Failed to allocate the output buffer!";
203 
204     mFpInput = fopen(mFileName.c_str(), "rb");
205     ASSERT_NE(mFpInput, nullptr) << "Failed to open the input file: " << mFileName;
206 
207     mFpOutput = fopen(ENCODED_FILE, "wb");
208     ASSERT_NE(mFpOutput, nullptr) << "Failed to open the output file:" << ENCODED_FILE;
209 
210     bool status = PVInitVideoEncoder(mEncodeControl, mEncodeHandle);
211     ASSERT_TRUE(status) << "Failed to initialize the encoder!";
212 
213     // Get VOL header.
214     int32_t size = mOutputBufferSize;
215     status = PVGetVolHeader(mEncodeControl, mOutputBuffer, &size, 0);
216     ASSERT_TRUE(status) << "Failed to get the VOL header!";
217 
218     // Write the VOL header on the first frame.
219     int32_t numBytes = fwrite(mOutputBuffer, 1, size, mFpOutput);
220     ASSERT_EQ(numBytes, size) << "Failed to write the VOL header!";
221 
222     int64_t totalFrames = getTotalFrames();
223     ASSERT_NO_FATAL_FAILURE(processEncoder(totalFrames)) << "Failed to Encode: " << mFileName;
224     status = PVCleanUpVideoEncoder(mEncodeControl);
225     ASSERT_TRUE(status) << "Failed to clean up the encoder resources!";
226 }
227 
228 INSTANTIATE_TEST_SUITE_P(
229         EncodeTest, Mpeg4H263EncoderTest,
230         ::testing::Values(
231                 make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 352, 288, 25, 1024),
232                 make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 352, 288, 25, 1024),
233                 make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 176, 144, 25, 1024),
234                 make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 176, 144, 25, 1024),
235                 make_tuple("football_qvga.yuv", false, 352, 288, 25, 1024),
236                 make_tuple("football_qvga.yuv", true, 352, 288, 25, 1024),
237                 make_tuple("football_qvga.yuv", false, 176, 144, 30, 1024),
238                 make_tuple("football_qvga.yuv", true, 176, 144, 30, 1024)));
239 
main(int argc,char ** argv)240 int32_t main(int argc, char **argv) {
241     gEnv = new Mpeg4H263EncoderTestEnvironment();
242     ::testing::AddGlobalTestEnvironment(gEnv);
243     ::testing::InitGoogleTest(&argc, argv);
244     uint8_t status = gEnv->initFromOptions(argc, argv);
245     if (status == 0) {
246         status = RUN_ALL_TESTS();
247         ALOGI("Encoder Test Result = %d\n", status);
248     }
249     return status;
250 }
251