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, ×tamp, &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("qtype0_mpeg4.m4v", "qtype0_mpeg4.info", true),
408 make_tuple("qtype1_mpeg4.m4v", "qtype1_mpeg4.info", true),
409 make_tuple("qtype1_qmatrix_mpeg4.m4v", "qtype1_qmatrix_mpeg4.info", true),
410 make_tuple("swirl_128x128_mpeg4.m4v", "swirl_128x128_mpeg4.info", true),
411 make_tuple("swirl_130x132_mpeg4.m4v", "swirl_130x132_mpeg4.info", true),
412 make_tuple("swirl_132x130_mpeg4.m4v", "swirl_132x130_mpeg4.info", true),
413 make_tuple("swirl_136x144_mpeg4.m4v", "swirl_136x144_mpeg4.info", true),
414 make_tuple("swirl_144x136_mpeg4.m4v", "swirl_144x136_mpeg4.info", true)));
415
main(int argc,char ** argv)416 int main(int argc, char **argv) {
417 gEnv = new Mpeg4H263DecoderTestEnvironment();
418 ::testing::AddGlobalTestEnvironment(gEnv);
419 ::testing::InitGoogleTest(&argc, argv);
420 int status = gEnv->initFromOptions(argc, argv);
421 if (status == 0) {
422 status = RUN_ALL_TESTS();
423 ALOGD("Decoder Test Result = %d\n", status);
424 }
425 return status;
426 }
427