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 "Mpeg4H263DecoderTest"
19 #include <utils/Log.h>
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <utils/String8.h>
24 #include <fstream>
25 
26 #include <media/stagefright/foundation/AUtils.h>
27 #include "mp4dec_api.h"
28 
29 #include "Mpeg4H263DecoderTestEnvironment.h"
30 
31 using namespace android;
32 
33 #define OUTPUT_FILE_NAME "/data/local/tmp/Output.yuv"
34 #define CODEC_CONFIG_FLAG 32
35 #define SYNC_FRAME 1
36 #define MPEG4_MAX_WIDTH 1920
37 #define MPEG4_MAX_HEIGHT 1080
38 #define H263_MAX_WIDTH 352
39 #define H263_MAX_HEIGHT 288
40 
41 constexpr uint32_t kNumOutputBuffers = 2;
42 
43 struct FrameInfo {
44     int32_t bytesCount;
45     uint32_t flags;
46     int64_t timestamp;
47 };
48 
49 struct tagvideoDecControls;
50 
51 static Mpeg4H263DecoderTestEnvironment *gEnv = nullptr;
52 
53 class Mpeg4H263DecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {
54   public:
Mpeg4H263DecoderTest()55     Mpeg4H263DecoderTest()
56         : mDecHandle(nullptr),
57           mInputBuffer(nullptr),
58           mInitialized(false),
59           mFramesConfigured(false),
60           mNumSamplesOutput(0),
61           mWidth(352),
62           mHeight(288) {
63         memset(mOutputBuffer, 0x0, sizeof(mOutputBuffer));
64     }
65 
~Mpeg4H263DecoderTest()66     ~Mpeg4H263DecoderTest() {
67         if (mEleStream.is_open()) mEleStream.close();
68         if (mDecHandle) {
69             delete mDecHandle;
70             mDecHandle = nullptr;
71         }
72         if (mInputBuffer) {
73             free(mInputBuffer);
74             mInputBuffer = nullptr;
75         }
76         freeOutputBuffer();
77     }
78 
79     status_t initDecoder();
80     void allocOutputBuffer(size_t outputBufferSize);
81     void dumpOutput(ofstream &ostrm);
82     void freeOutputBuffer();
83     void processMpeg4H263Decoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
84                                  ifstream &mEleStream, ofstream &ostrm, MP4DecodingMode inputMode);
85     void deInitDecoder();
86 
87     ifstream mEleStream;
88     tagvideoDecControls *mDecHandle;
89     char *mInputBuffer;
90     uint8_t *mOutputBuffer[kNumOutputBuffers];
91     bool mInitialized;
92     bool mFramesConfigured;
93     uint32_t mNumSamplesOutput;
94     uint32_t mWidth;
95     uint32_t mHeight;
96 };
97 
initDecoder()98 status_t Mpeg4H263DecoderTest::initDecoder() {
99     if (!mDecHandle) {
100         mDecHandle = new tagvideoDecControls;
101     }
102     if (!mDecHandle) {
103         return NO_MEMORY;
104     }
105     memset(mDecHandle, 0, sizeof(tagvideoDecControls));
106 
107     return OK;
108 }
109 
allocOutputBuffer(size_t outputBufferSize)110 void Mpeg4H263DecoderTest::allocOutputBuffer(size_t outputBufferSize) {
111     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
112         if (!mOutputBuffer[i]) {
113             mOutputBuffer[i] = (uint8_t *)malloc(outputBufferSize);
114             ASSERT_NE(mOutputBuffer[i], nullptr) << "Output buffer allocation failed";
115         }
116     }
117 }
118 
dumpOutput(ofstream & ostrm)119 void Mpeg4H263DecoderTest::dumpOutput(ofstream &ostrm) {
120     uint8_t *src = mOutputBuffer[mNumSamplesOutput & 1];
121     size_t vStride = align(mHeight, 16);
122     size_t srcYStride = align(mWidth, 16);
123     size_t srcUVStride = srcYStride / 2;
124     uint8_t *srcStart = src;
125 
126     /* Y buffer */
127     for (size_t i = 0; i < mHeight; ++i) {
128         ostrm.write(reinterpret_cast<char *>(src), mWidth);
129         src += srcYStride;
130     }
131     /* U buffer */
132     src = srcStart + vStride * srcYStride;
133     for (size_t i = 0; i < mHeight / 2; ++i) {
134         ostrm.write(reinterpret_cast<char *>(src), mWidth / 2);
135         src += srcUVStride;
136     }
137     /* V buffer */
138     src = srcStart + vStride * srcYStride * 5 / 4;
139     for (size_t i = 0; i < mHeight / 2; ++i) {
140         ostrm.write(reinterpret_cast<char *>(src), mWidth / 2);
141         src += srcUVStride;
142     }
143 }
144 
freeOutputBuffer()145 void Mpeg4H263DecoderTest::freeOutputBuffer() {
146     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
147         if (mOutputBuffer[i]) {
148             free(mOutputBuffer[i]);
149             mOutputBuffer[i] = nullptr;
150         }
151     }
152 }
153 
processMpeg4H263Decoder(vector<FrameInfo> Info,int32_t offset,int32_t range,ifstream & mEleStream,ofstream & ostrm,MP4DecodingMode inputMode)154 void Mpeg4H263DecoderTest::processMpeg4H263Decoder(vector<FrameInfo> Info, int32_t offset,
155                                                    int32_t range, ifstream &mEleStream,
156                                                    ofstream &ostrm, MP4DecodingMode inputMode) {
157     size_t maxWidth = (inputMode == MPEG4_MODE) ? MPEG4_MAX_WIDTH : H263_MAX_WIDTH;
158     size_t maxHeight = (inputMode == MPEG4_MODE) ? MPEG4_MAX_HEIGHT : H263_MAX_HEIGHT;
159     size_t outputBufferSize = align(maxWidth, 16) * align(maxHeight, 16) * 3 / 2;
160     uint32_t frameIndex = offset;
161     bool status = true;
162     ASSERT_GE(range, 0) << "Invalid range";
163     ASSERT_TRUE(offset >= 0 && offset <= Info.size() - 1) << "Invalid offset";
164     ASSERT_LE(range + offset, Info.size()) << "range+offset can't be greater than the no of frames";
165 
166     while (1) {
167         if (frameIndex == Info.size() || frameIndex == (offset + range)) break;
168 
169         int32_t bytesCount = Info[frameIndex].bytesCount;
170         ASSERT_GT(bytesCount, 0) << "Size for the memory allocation is negative";
171         mInputBuffer = (char *)malloc(bytesCount);
172         ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory to read frame";
173         mEleStream.read(mInputBuffer, bytesCount);
174         ASSERT_EQ(mEleStream.gcount(), bytesCount) << "mEleStream.gcount() != bytesCount";
175         static const uint8_t volInfo[] = {0x00, 0x00, 0x01, 0xB0};
176         bool volHeader = memcmp(mInputBuffer, volInfo, 4) == 0;
177         if (volHeader) {
178             PVCleanUpVideoDecoder(mDecHandle);
179             mInitialized = false;
180         }
181 
182         if (!mInitialized) {
183             uint8_t *volData[1]{};
184             int32_t volSize = 0;
185 
186             uint32_t flags = Info[frameIndex].flags;
187             bool codecConfig = flags == CODEC_CONFIG_FLAG;
188             if (codecConfig || volHeader) {
189                 volData[0] = reinterpret_cast<uint8_t *>(mInputBuffer);
190                 volSize = bytesCount;
191             }
192 
193             status = PVInitVideoDecoder(mDecHandle, volData, &volSize, 1, maxWidth, maxHeight,
194                                         inputMode);
195             ASSERT_TRUE(status) << "PVInitVideoDecoder failed. Unsupported content";
196 
197             mInitialized = true;
198             MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
199             ASSERT_EQ(inputMode, actualMode)
200                     << "Decoded mode not same as actual mode of the decoder";
201 
202             PVSetPostProcType(mDecHandle, 0);
203 
204             int32_t dispWidth, dispHeight;
205             PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
206 
207             int32_t bufWidth, bufHeight;
208             PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
209 
210             ASSERT_LE(dispWidth, bufWidth) << "Display width is greater than buffer width";
211             ASSERT_LE(dispHeight, bufHeight) << "Display height is greater than buffer height";
212 
213             if (dispWidth != mWidth || dispHeight != mHeight) {
214                 mWidth = dispWidth;
215                 mHeight = dispHeight;
216                 freeOutputBuffer();
217                 if (inputMode == H263_MODE) {
218                     PVCleanUpVideoDecoder(mDecHandle);
219 
220                     uint8_t *volData[1]{};
221                     int32_t volSize = 0;
222 
223                     status = PVInitVideoDecoder(mDecHandle, volData, &volSize, 1, maxWidth,
224                                                 maxHeight, H263_MODE);
225                     ASSERT_TRUE(status) << "PVInitVideoDecoder failed for H263";
226                 }
227                 mFramesConfigured = false;
228             }
229 
230             if (codecConfig) {
231                 frameIndex++;
232                 continue;
233             }
234         }
235 
236         uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
237         ASSERT_GE(outputBufferSize, yFrameSize * 3 / 2)
238                 << "Too small output buffer: " << outputBufferSize << " bytes";
239         ASSERT_NO_FATAL_FAILURE(allocOutputBuffer(outputBufferSize));
240 
241         if (!mFramesConfigured) {
242             PVSetReferenceYUV(mDecHandle, mOutputBuffer[1]);
243             mFramesConfigured = true;
244         }
245 
246         // Need to check if header contains new info, e.g., width/height, etc.
247         VopHeaderInfo headerInfo;
248         uint32_t useExtTimestamp = 1;
249         int32_t inputSize = (Info)[frameIndex].bytesCount;
250         uint32_t timestamp = frameIndex;
251 
252         uint8_t *bitstreamTmp = reinterpret_cast<uint8_t *>(mInputBuffer);
253 
254         status = PVDecodeVopHeader(mDecHandle, &bitstreamTmp, &timestamp, &inputSize, &headerInfo,
255                                    &useExtTimestamp, mOutputBuffer[mNumSamplesOutput & 1]);
256         ASSERT_EQ(status, PV_TRUE) << "failed to decode vop header";
257 
258         // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
259         // decoder may detect size change after PVDecodeVopHeader.
260         int32_t dispWidth, dispHeight;
261         PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
262 
263         int32_t bufWidth, bufHeight;
264         PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
265 
266         ASSERT_LE(dispWidth, bufWidth) << "Display width is greater than buffer width";
267         ASSERT_LE(dispHeight, bufHeight) << "Display height is greater than buffer height";
268         if (dispWidth != mWidth || dispHeight != mHeight) {
269             mWidth = dispWidth;
270             mHeight = dispHeight;
271         }
272 
273         status = PVDecodeVopBody(mDecHandle, &inputSize);
274         ASSERT_EQ(status, PV_TRUE) << "failed to decode video frame No = %d" << frameIndex;
275 
276         dumpOutput(ostrm);
277 
278         ++mNumSamplesOutput;
279         ++frameIndex;
280     }
281     freeOutputBuffer();
282 }
283 
deInitDecoder()284 void Mpeg4H263DecoderTest::deInitDecoder() {
285     if (mInitialized) {
286         if (mDecHandle) {
287             PVCleanUpVideoDecoder(mDecHandle);
288             delete mDecHandle;
289             mDecHandle = nullptr;
290         }
291         mInitialized = false;
292     }
293     freeOutputBuffer();
294 }
295 
getInfo(string infoFileName,vector<FrameInfo> & Info)296 void getInfo(string infoFileName, vector<FrameInfo> &Info) {
297     ifstream eleInfo;
298     eleInfo.open(infoFileName);
299     ASSERT_EQ(eleInfo.is_open(), true) << "Failed to open " << infoFileName;
300     int32_t bytesCount = 0;
301     uint32_t flags = 0;
302     uint32_t timestamp = 0;
303     while (1) {
304         if (!(eleInfo >> bytesCount)) {
305             break;
306         }
307         eleInfo >> flags;
308         eleInfo >> timestamp;
309         Info.push_back({bytesCount, flags, timestamp});
310     }
311     if (eleInfo.is_open()) eleInfo.close();
312 }
313 
TEST_P(Mpeg4H263DecoderTest,DecodeTest)314 TEST_P(Mpeg4H263DecoderTest, DecodeTest) {
315     tuple<string /* InputFileName */, string /* InfoFileName */, bool /* mode */> params =
316             GetParam();
317 
318     string inputFileName = gEnv->getRes() + get<0>(params);
319     mEleStream.open(inputFileName, ifstream::binary);
320     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << get<0>(params);
321 
322     string infoFileName = gEnv->getRes() + get<1>(params);
323     vector<FrameInfo> Info;
324     ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
325     ASSERT_NE(Info.empty(), true) << "Invalid Info file";
326 
327     ofstream ostrm;
328     ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
329     ASSERT_EQ(ostrm.is_open(), true) << "Failed to open output stream for " << get<0>(params);
330 
331     status_t err = initDecoder();
332     ASSERT_EQ(err, OK) << "initDecoder: failed to create decoder " << err;
333 
334     bool isMpeg4 = get<2>(params);
335     MP4DecodingMode inputMode = isMpeg4 ? MPEG4_MODE : H263_MODE;
336     ASSERT_NO_FATAL_FAILURE(
337             processMpeg4H263Decoder(Info, 0, Info.size(), mEleStream, ostrm, inputMode));
338     deInitDecoder();
339     ostrm.close();
340     Info.clear();
341 }
342 
TEST_P(Mpeg4H263DecoderTest,FlushTest)343 TEST_P(Mpeg4H263DecoderTest, FlushTest) {
344     tuple<string /* InputFileName */, string /* InfoFileName */, bool /* mode */> params =
345             GetParam();
346 
347     string inputFileName = gEnv->getRes() + get<0>(params);
348     mEleStream.open(inputFileName, ifstream::binary);
349     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << get<0>(params);
350 
351     string infoFileName = gEnv->getRes() + get<1>(params);
352     vector<FrameInfo> Info;
353     ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
354     ASSERT_NE(Info.empty(), true) << "Invalid Info file";
355 
356     ofstream ostrm;
357     ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
358     ASSERT_EQ(ostrm.is_open(), true) << "Failed to open output stream for " << get<0>(params);
359 
360     status_t err = initDecoder();
361     ASSERT_EQ(err, OK) << "initDecoder: failed to create decoder " << err;
362 
363     bool isMpeg4 = get<2>(params);
364     MP4DecodingMode inputMode = isMpeg4 ? MPEG4_MODE : H263_MODE;
365     // Number of frames to be decoded before flush
366     int32_t numFrames = Info.size() / 3;
367     ASSERT_NO_FATAL_FAILURE(
368             processMpeg4H263Decoder(Info, 0, numFrames, mEleStream, ostrm, inputMode));
369 
370     if (mInitialized) {
371         int32_t status = PVResetVideoDecoder(mDecHandle);
372         ASSERT_EQ(status, PV_TRUE);
373     }
374 
375     // Seek to next key frame and start decoding till the end
376     int32_t index = numFrames;
377     bool keyFrame = false;
378     uint32_t flags = 0;
379     while (index < (int32_t)Info.size()) {
380         if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
381         if ((flags & SYNC_FRAME) == SYNC_FRAME) {
382             keyFrame = true;
383             break;
384         }
385         flags = 0;
386         mEleStream.ignore(Info[index].bytesCount);
387         index++;
388     }
389     ALOGV("Index= %d", index);
390     if (keyFrame) {
391         mNumSamplesOutput = 0;
392         ASSERT_NO_FATAL_FAILURE(processMpeg4H263Decoder(Info, index, (int32_t)Info.size() - index,
393                                                         mEleStream, ostrm, inputMode));
394     }
395     deInitDecoder();
396     ostrm.close();
397     Info.clear();
398 }
399 
400 INSTANTIATE_TEST_SUITE_P(
401         Mpeg4H263DecoderTestAll, Mpeg4H263DecoderTest,
402         ::testing::Values(make_tuple("swirl_128x96_h263.h263", "swirl_128x96_h263.info", false),
403                           make_tuple("swirl_176x144_h263.h263", "swirl_176x144_h263.info", false),
404                           make_tuple("swirl_352x288_h263.h263", "swirl_352x288_h263.info", false),
405                           make_tuple("bbb_352x288_h263.h263", "bbb_352x288_h263.info", false),
406                           make_tuple("bbb_352x288_mpeg4.m4v", "bbb_352x288_mpeg4.info", true),
407                           make_tuple("swirl_128x128_mpeg4.m4v", "swirl_128x128_mpeg4.info", true),
408                           make_tuple("swirl_130x132_mpeg4.m4v", "swirl_130x132_mpeg4.info", true),
409                           make_tuple("swirl_132x130_mpeg4.m4v", "swirl_132x130_mpeg4.info", true),
410                           make_tuple("swirl_136x144_mpeg4.m4v", "swirl_136x144_mpeg4.info", true),
411                           make_tuple("swirl_144x136_mpeg4.m4v", "swirl_144x136_mpeg4.info", true)));
412 
main(int argc,char ** argv)413 int main(int argc, char **argv) {
414     gEnv = new Mpeg4H263DecoderTestEnvironment();
415     ::testing::AddGlobalTestEnvironment(gEnv);
416     ::testing::InitGoogleTest(&argc, argv);
417     int status = gEnv->initFromOptions(argc, argv);
418     if (status == 0) {
419         status = RUN_ALL_TESTS();
420         ALOGD("Decoder Test Result = %d\n", status);
421     }
422     return status;
423 }
424