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 "NativeCodecEncoderTest"
19 #include <log/log.h>
20
21 #include <jni.h>
22 #include <sys/stat.h>
23
24 #include "NativeCodecTestBase.h"
25 #include "NativeMediaCommon.h"
26
27 class CodecEncoderTest final : CodecTestBase {
28 private:
29 uint8_t* mInputData;
30 size_t mInputLength;
31 int mNumBytesSubmitted;
32 int64_t mInputOffsetPts;
33 std::vector<AMediaFormat*> mFormats;
34 int mNumSyncFramesReceived;
35 std::vector<int> mSyncFramesPos;
36
37 int32_t* mBitRates;
38 int mLen0;
39 int32_t* mEncParamList1;
40 int mLen1;
41 int32_t* mEncParamList2;
42 int mLen2;
43
44 int mWidth, mHeight;
45 int mChannels;
46 int mSampleRate;
47 int mColorFormat;
48 int mMaxBFrames;
49 int mDefFrameRate;
50 const int kInpFrmWidth = 352;
51 const int kInpFrmHeight = 288;
52
53 void convertyuv420ptoyuv420sp();
54 void setUpSource(const char* srcPath);
55 void deleteSource();
56 void setUpParams(int limit);
57 void deleteParams();
58 bool flushCodec() override;
59 void resetContext(bool isAsync, bool signalEOSWithLastFrame) override;
60 bool enqueueInput(size_t bufferIndex) override;
61 bool dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo) override;
62 void initFormat(AMediaFormat* format);
63 bool encodeToMemory(const char* file, const char* encoder, int frameLimit, AMediaFormat* format,
64 OutputManager* ref);
65 void fillByteBuffer(uint8_t* inputBuffer);
66 void forceSyncFrame(AMediaFormat* format);
67 void updateBitrate(AMediaFormat* format, int bitrate);
68
69 public:
70 CodecEncoderTest(const char* mime, int32_t* list0, int len0, int32_t* list1, int len1,
71 int32_t* list2, int len2, int colorFormat);
72 ~CodecEncoderTest();
73
74 bool testSimpleEncode(const char* encoder, const char* srcPath);
75 bool testFlush(const char* encoder, const char* srcPath);
76 bool testReconfigure(const char* encoder, const char* srcPath);
77 bool testSetForceSyncFrame(const char* encoder, const char* srcPath);
78 bool testAdaptiveBitRate(const char* encoder, const char* srcPath);
79 bool testOnlyEos(const char* encoder);
80 };
81
CodecEncoderTest(const char * mime,int32_t * list0,int len0,int32_t * list1,int len1,int32_t * list2,int len2,int colorFormat)82 CodecEncoderTest::CodecEncoderTest(const char* mime, int32_t* list0, int len0, int32_t* list1,
83 int len1, int32_t* list2, int len2, int colorFormat)
84 : CodecTestBase(mime),
85 mBitRates{list0},
86 mLen0{len0},
87 mEncParamList1{list1},
88 mLen1{len1},
89 mEncParamList2{list2},
90 mLen2{len2},
91 mColorFormat{colorFormat} {
92 mDefFrameRate = 30;
93 if (!strcmp(mime, AMEDIA_MIMETYPE_VIDEO_H263)) mDefFrameRate = 12;
94 else if (!strcmp(mime, AMEDIA_MIMETYPE_VIDEO_MPEG4)) mDefFrameRate = 12;
95 mMaxBFrames = 0;
96 mInputData = nullptr;
97 mInputLength = 0;
98 mNumBytesSubmitted = 0;
99 mInputOffsetPts = 0;
100 }
101
~CodecEncoderTest()102 CodecEncoderTest::~CodecEncoderTest() {
103 deleteSource();
104 deleteParams();
105 }
106
convertyuv420ptoyuv420sp()107 void CodecEncoderTest::convertyuv420ptoyuv420sp() {
108 int ySize = kInpFrmWidth * kInpFrmHeight;
109 int uSize = kInpFrmWidth * kInpFrmHeight / 4;
110 int frameSize = ySize + uSize * 2;
111 int totalFrames = mInputLength / frameSize;
112 uint8_t* u = new uint8_t[uSize];
113 uint8_t* v = new uint8_t[uSize];
114 uint8_t* frameBase = mInputData;
115 for (int i = 0; i < totalFrames; i++) {
116 uint8_t* uvBase = frameBase + ySize;
117 memcpy(u, uvBase, uSize);
118 memcpy(v, uvBase + uSize, uSize);
119 for (int j = 0, idx = 0; j < uSize; j++, idx += 2) {
120 uvBase[idx] = u[j];
121 uvBase[idx + 1] = v[j];
122 }
123 frameBase += frameSize;
124 }
125 delete[] u;
126 delete[] v;
127 }
128
setUpSource(const char * srcPath)129 void CodecEncoderTest::setUpSource(const char* srcPath) {
130 FILE* fp = fopen(srcPath, "rbe");
131 struct stat buf {};
132 if (fp && !fstat(fileno(fp), &buf)) {
133 deleteSource();
134 mInputLength = buf.st_size;
135 mInputData = new uint8_t[mInputLength];
136 fread(mInputData, sizeof(uint8_t), mInputLength, fp);
137 if (mColorFormat == COLOR_FormatYUV420SemiPlanar) {
138 convertyuv420ptoyuv420sp();
139 }
140 } else {
141 ALOGE("unable to open input file %s", srcPath);
142 }
143 if (fp) fclose(fp);
144 }
145
deleteSource()146 void CodecEncoderTest::deleteSource() {
147 if (mInputData) {
148 delete[] mInputData;
149 mInputData = nullptr;
150 }
151 mInputLength = 0;
152 }
153
setUpParams(int limit)154 void CodecEncoderTest::setUpParams(int limit) {
155 int count = 0;
156 for (int k = 0; k < mLen0; k++) {
157 int bitrate = mBitRates[k];
158 if (mIsAudio) {
159 for (int j = 0; j < mLen1; j++) {
160 int rate = mEncParamList1[j];
161 for (int i = 0; i < mLen2; i++) {
162 int channels = mEncParamList2[i];
163 AMediaFormat* format = AMediaFormat_new();
164 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mMime);
165 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
166 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, rate);
167 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channels);
168 mFormats.push_back(format);
169 count++;
170 if (count >= limit) break;
171 }
172 }
173 } else {
174 for (int j = 0; j < mLen1; j++) {
175 int width = mEncParamList1[j];
176 int height = mEncParamList2[j];
177 AMediaFormat* format = AMediaFormat_new();
178 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mMime);
179 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
180 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, width);
181 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height);
182 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, mDefFrameRate);
183 AMediaFormat_setInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES,
184 mMaxBFrames);
185 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1.0F);
186 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, mColorFormat);
187 mFormats.push_back(format);
188 count++;
189 if (count >= limit) break;
190 }
191 }
192 }
193 }
194
deleteParams()195 void CodecEncoderTest::deleteParams() {
196 for (auto format : mFormats) AMediaFormat_delete(format);
197 mFormats.clear();
198 }
199
resetContext(bool isAsync,bool signalEOSWithLastFrame)200 void CodecEncoderTest::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
201 CodecTestBase::resetContext(isAsync, signalEOSWithLastFrame);
202 mNumBytesSubmitted = 0;
203 mInputOffsetPts = 0;
204 mNumSyncFramesReceived = 0;
205 mSyncFramesPos.clear();
206 }
207
flushCodec()208 bool CodecEncoderTest::flushCodec() {
209 bool isOk = CodecTestBase::flushCodec();
210 if (mIsAudio) {
211 mInputOffsetPts = (mNumBytesSubmitted + 1024) * 1000000L / (2 * mChannels * mSampleRate);
212 } else {
213 mInputOffsetPts = (mInputCount + 5) * 1000000L / mDefFrameRate;
214 }
215 mPrevOutputPts = mInputOffsetPts - 1;
216 mNumBytesSubmitted = 0;
217 mNumSyncFramesReceived = 0;
218 mSyncFramesPos.clear();
219 return isOk;
220 }
221
fillByteBuffer(uint8_t * inputBuffer)222 void CodecEncoderTest::fillByteBuffer(uint8_t* inputBuffer) {
223 int width, height, tileWidth, tileHeight;
224 int offset = 0, frmOffset = mNumBytesSubmitted;
225 int numOfPlanes;
226 if (mColorFormat == COLOR_FormatYUV420SemiPlanar) {
227 numOfPlanes = 2;
228 } else {
229 numOfPlanes = 3;
230 }
231 for (int plane = 0; plane < numOfPlanes; plane++) {
232 if (plane == 0) {
233 width = mWidth;
234 height = mHeight;
235 tileWidth = kInpFrmWidth;
236 tileHeight = kInpFrmHeight;
237 } else {
238 if (mColorFormat == COLOR_FormatYUV420SemiPlanar) {
239 width = mWidth;
240 tileWidth = kInpFrmWidth;
241 } else {
242 width = mWidth / 2;
243 tileWidth = kInpFrmWidth / 2;
244 }
245 height = mHeight / 2;
246 tileHeight = kInpFrmHeight / 2;
247 }
248 for (int k = 0; k < height; k += tileHeight) {
249 int rowsToCopy = std::min(height - k, tileHeight);
250 for (int j = 0; j < rowsToCopy; j++) {
251 for (int i = 0; i < width; i += tileWidth) {
252 int colsToCopy = std::min(width - i, tileWidth);
253 memcpy(inputBuffer + (offset + (k + j) * width + i),
254 mInputData + (frmOffset + j * tileWidth), colsToCopy);
255 }
256 }
257 }
258 offset += width * height;
259 frmOffset += tileWidth * tileHeight;
260 }
261 }
262
enqueueInput(size_t bufferIndex)263 bool CodecEncoderTest::enqueueInput(size_t bufferIndex) {
264 if (mNumBytesSubmitted >= mInputLength) {
265 return enqueueEOS(bufferIndex);
266 } else {
267 int size = 0;
268 int flags = 0;
269 int64_t pts = mInputOffsetPts;
270 size_t buffSize;
271 uint8_t* inputBuffer = AMediaCodec_getInputBuffer(mCodec, bufferIndex, &buffSize);
272 if (mIsAudio) {
273 pts += mNumBytesSubmitted * 1000000L / (2 * mChannels * mSampleRate);
274 size = std::min(buffSize, mInputLength - mNumBytesSubmitted);
275 memcpy(inputBuffer, mInputData + mNumBytesSubmitted, size);
276 if (mNumBytesSubmitted + size >= mInputLength && mSignalEOSWithLastFrame) {
277 flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
278 mSawInputEOS = true;
279 }
280 mNumBytesSubmitted += size;
281 } else {
282 pts += mInputCount * 1000000L / mDefFrameRate;
283 size = mWidth * mHeight * 3 / 2;
284 int frmSize = kInpFrmWidth * kInpFrmHeight * 3 / 2;
285 if (mNumBytesSubmitted + frmSize > mInputLength) {
286 ALOGE("received partial frame to encode");
287 return false;
288 } else if (size > buffSize) {
289 ALOGE("frame size exceeds buffer capacity of input buffer %d %zu", size, buffSize);
290 return false;
291 } else {
292 if (mWidth == kInpFrmWidth && mHeight == kInpFrmHeight) {
293 memcpy(inputBuffer, mInputData + mNumBytesSubmitted, size);
294 } else {
295 fillByteBuffer(inputBuffer);
296 }
297 }
298 if (mNumBytesSubmitted + frmSize >= mInputLength && mSignalEOSWithLastFrame) {
299 flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
300 mSawInputEOS = true;
301 }
302 mNumBytesSubmitted += frmSize;
303 }
304 CHECK_STATUS(AMediaCodec_queueInputBuffer(mCodec, bufferIndex, 0, size, pts, flags),
305 "AMediaCodec_queueInputBuffer failed");
306 ALOGV("input: id: %zu size: %d pts: %d flags: %d", bufferIndex, size, (int)pts, flags);
307 mOutputBuff->saveInPTS(pts);
308 mInputCount++;
309 }
310 return !hasSeenError();
311 }
312
dequeueOutput(size_t bufferIndex,AMediaCodecBufferInfo * info)313 bool CodecEncoderTest::dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* info) {
314 if ((info->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
315 mSawOutputEOS = true;
316 }
317 if (info->size > 0) {
318 if (mSaveToMem) {
319 size_t buffSize;
320 uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, bufferIndex, &buffSize);
321 mOutputBuff->saveToMemory(buf, info);
322 }
323 if ((info->flags & TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME) != 0) {
324 mNumSyncFramesReceived += 1;
325 mSyncFramesPos.push_back(mOutputCount);
326 }
327 if ((info->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
328 mOutputBuff->saveOutPTS(info->presentationTimeUs);
329 mOutputCount++;
330 }
331 }
332 ALOGV("output: id: %zu size: %d pts: %d flags: %d", bufferIndex, info->size,
333 (int)info->presentationTimeUs, info->flags);
334 CHECK_STATUS(AMediaCodec_releaseOutputBuffer(mCodec, bufferIndex, false),
335 "AMediaCodec_releaseOutputBuffer failed");
336 return !hasSeenError();
337 }
338
initFormat(AMediaFormat * format)339 void CodecEncoderTest::initFormat(AMediaFormat* format) {
340 if (mIsAudio) {
341 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate);
342 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mChannels);
343 } else {
344 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth);
345 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight);
346 }
347 }
348
encodeToMemory(const char * file,const char * encoder,int32_t frameLimit,AMediaFormat * format,OutputManager * ref)349 bool CodecEncoderTest::encodeToMemory(const char* file, const char* encoder, int32_t frameLimit,
350 AMediaFormat* format, OutputManager* ref) {
351 /* TODO(b/149027258) */
352 if (true) mSaveToMem = false;
353 else mSaveToMem = true;
354 mOutputBuff = ref;
355 mCodec = AMediaCodec_createCodecByName(encoder);
356 if (!mCodec) {
357 ALOGE("unable to create codec %s", encoder);
358 return false;
359 }
360 setUpSource(file);
361 if (!mInputData) return false;
362 if (!configureCodec(format, false, true, true)) return false;
363 initFormat(format);
364 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
365 if (!doWork(frameLimit)) return false;
366 if (!queueEOS()) return false;
367 if (!waitForAllOutputs()) return false;
368 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
369 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
370 mCodec = nullptr;
371 mSaveToMem = false;
372 return !hasSeenError();
373 }
374
forceSyncFrame(AMediaFormat * format)375 void CodecEncoderTest::forceSyncFrame(AMediaFormat* format) {
376 AMediaFormat_setInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
377 ALOGV("requesting key frame");
378 AMediaCodec_setParameters(mCodec, format);
379 }
380
updateBitrate(AMediaFormat * format,int bitrate)381 void CodecEncoderTest::updateBitrate(AMediaFormat* format, int bitrate) {
382 AMediaFormat_setInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE, bitrate);
383 ALOGV("requesting bitrate to be changed to %d", bitrate);
384 AMediaCodec_setParameters(mCodec, format);
385 }
386
testSimpleEncode(const char * encoder,const char * srcPath)387 bool CodecEncoderTest::testSimpleEncode(const char* encoder, const char* srcPath) {
388 bool isPass = true;
389 setUpSource(srcPath);
390 if (!mInputData) return false;
391 setUpParams(INT32_MAX);
392 /* TODO(b/149027258) */
393 if (true) mSaveToMem = false;
394 else mSaveToMem = true;
395 auto ref = &mRefBuff;
396 auto test = &mTestBuff;
397 const bool boolStates[]{true, false};
398 for (int i = 0; i < mFormats.size() && isPass; i++) {
399 AMediaFormat* format = mFormats[i];
400 initFormat(format);
401 int loopCounter = 0;
402 for (auto eosType : boolStates) {
403 if (!isPass) break;
404 for (auto isAsync : boolStates) {
405 if (!isPass) break;
406 char log[1000];
407 snprintf(log, sizeof(log),
408 "format: %s \n codec: %s, file: %s, mode: %s, eos type: %s:: ",
409 AMediaFormat_toString(format), encoder, srcPath,
410 (isAsync ? "async" : "sync"),
411 (eosType ? "eos with last frame" : "eos separate"));
412 mOutputBuff = loopCounter == 0 ? ref : test;
413 mOutputBuff->reset();
414 /* TODO(b/147348711) */
415 /* Instead of create and delete codec at every iteration, we would like to create
416 * once and use it for all iterations and delete before exiting */
417 mCodec = AMediaCodec_createCodecByName(encoder);
418 if (!mCodec) {
419 ALOGE("%s unable to create media codec by name %s", log, encoder);
420 isPass = false;
421 continue;
422 }
423 char* name = nullptr;
424 if (AMEDIA_OK == AMediaCodec_getName(mCodec, &name)) {
425 if (!name || strcmp(name, encoder) != 0) {
426 ALOGE("%s error codec-name act/got: %s/%s", log, name, encoder);
427 if (name) AMediaCodec_releaseName(mCodec, name);
428 return false;
429 }
430 } else {
431 ALOGE("AMediaCodec_getName failed unexpectedly");
432 return false;
433 }
434 if (name) AMediaCodec_releaseName(mCodec, name);
435 if (!configureCodec(format, isAsync, eosType, true)) return false;
436 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
437 if (!doWork(INT32_MAX)) return false;
438 if (!queueEOS()) return false;
439 if (!waitForAllOutputs()) return false;
440 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
441 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
442 mCodec = nullptr;
443 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
444 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
445 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
446 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log,
447 "input cnt != output cnt", isPass);
448 CHECK_ERR((loopCounter != 0 && !ref->equals(test)), log, "output is flaky", isPass);
449 CHECK_ERR((loopCounter == 0 && mIsAudio &&
450 !ref->isPtsStrictlyIncreasing(mPrevOutputPts)),
451 log, "pts is not strictly increasing", isPass);
452 CHECK_ERR((loopCounter == 0 && !mIsAudio &&
453 !ref->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
454 log, "input pts list and output pts list are not identical", isPass);
455 loopCounter++;
456 }
457 }
458 }
459 return isPass;
460 }
461
testFlush(const char * encoder,const char * srcPath)462 bool CodecEncoderTest::testFlush(const char* encoder, const char* srcPath) {
463 bool isPass = true;
464 setUpSource(srcPath);
465 if (!mInputData) return false;
466 setUpParams(1);
467 mOutputBuff = &mTestBuff;
468 AMediaFormat* format = mFormats[0];
469 initFormat(format);
470 const bool boolStates[]{true, false};
471 for (auto isAsync : boolStates) {
472 if (!isPass) break;
473 char log[1000];
474 snprintf(log, sizeof(log),
475 "format: %s \n codec: %s, file: %s, mode: %s:: ", AMediaFormat_toString(format),
476 encoder, srcPath, (isAsync ? "async" : "sync"));
477 /* TODO(b/147348711) */
478 /* Instead of create and delete codec at every iteration, we would like to create
479 * once and use it for all iterations and delete before exiting */
480 mCodec = AMediaCodec_createCodecByName(encoder);
481 if (!mCodec) {
482 ALOGE("unable to create media codec by name %s", encoder);
483 isPass = false;
484 continue;
485 }
486 if (!configureCodec(format, isAsync, true, true)) return false;
487 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
488
489 /* test flush in running state before queuing input */
490 if (!flushCodec()) return false;
491 mOutputBuff->reset();
492 if (mIsCodecInAsyncMode) {
493 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
494 }
495 if (!doWork(23)) return false;
496 CHECK_ERR((!mOutputBuff->isPtsStrictlyIncreasing(mPrevOutputPts)), log,
497 "pts is not strictly increasing", isPass);
498 if (!isPass) continue;
499
500 /* test flush in running state */
501 if (!flushCodec()) return false;
502 mOutputBuff->reset();
503 if (mIsCodecInAsyncMode) {
504 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
505 }
506 if (!doWork(INT32_MAX)) return false;
507 if (!queueEOS()) return false;
508 if (!waitForAllOutputs()) return false;
509 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
510 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
511 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
512 CHECK_ERR((mIsAudio && !mOutputBuff->isPtsStrictlyIncreasing(mPrevOutputPts)), log,
513 "pts is not strictly increasing", isPass);
514 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
515 isPass);
516 CHECK_ERR((!mIsAudio && !mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
517 log, "input pts list and output pts list are not identical", isPass);
518 if (!isPass) continue;
519
520 /* test flush in eos state */
521 if (!flushCodec()) return false;
522 mOutputBuff->reset();
523 if (mIsCodecInAsyncMode) {
524 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
525 }
526 if (!doWork(INT32_MAX)) return false;
527 if (!queueEOS()) return false;
528 if (!waitForAllOutputs()) return false;
529 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
530 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
531 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
532 CHECK_ERR((mIsAudio && !mOutputBuff->isPtsStrictlyIncreasing(mPrevOutputPts)), log,
533 "pts is not strictly increasing", isPass);
534 CHECK_ERR(!mIsAudio && (mInputCount != mOutputCount), log, "input cnt != output cnt",
535 isPass);
536 CHECK_ERR(!mIsAudio && (!mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
537 log, "input pts list and output pts list are not identical", isPass);
538 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
539 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
540 mCodec = nullptr;
541 }
542 return isPass;
543 }
544
testReconfigure(const char * encoder,const char * srcPath)545 bool CodecEncoderTest::testReconfigure(const char* encoder, const char* srcPath) {
546 bool isPass = true;
547 setUpSource(srcPath);
548 if (!mInputData) return false;
549 setUpParams(2);
550 auto configRef = &mReconfBuff;
551 if (mFormats.size() > 1) {
552 auto format = mFormats[1];
553 if (!encodeToMemory(srcPath, encoder, INT32_MAX, format, configRef)) {
554 ALOGE("encodeToMemory failed for file: %s codec: %s \n format: %s", srcPath, encoder,
555 AMediaFormat_toString(format));
556 return false;
557 }
558 CHECK_ERR(mIsAudio && (!configRef->isPtsStrictlyIncreasing(mPrevOutputPts)), "",
559 "pts is not strictly increasing", isPass);
560 CHECK_ERR(!mIsAudio && (!configRef->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
561 "", "input pts list and output pts list are not identical", isPass);
562 if (!isPass) return false;
563 }
564 auto format = mFormats[0];
565 auto ref = &mRefBuff;
566 if (!encodeToMemory(srcPath, encoder, INT32_MAX, format, ref)) {
567 ALOGE("encodeToMemory failed for file: %s codec: %s \n format: %s", srcPath, encoder,
568 AMediaFormat_toString(format));
569 return false;
570 }
571 CHECK_ERR(mIsAudio && (!ref->isPtsStrictlyIncreasing(mPrevOutputPts)), "",
572 "pts is not strictly increasing", isPass);
573 CHECK_ERR(!mIsAudio && (!ref->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)), "",
574 "input pts list and output pts list are not identical", isPass);
575 if (!isPass) return false;
576
577 auto test = &mTestBuff;
578 mOutputBuff = test;
579 const bool boolStates[]{true, false};
580 for (auto isAsync : boolStates) {
581 if (!isPass) break;
582 char log[1000];
583 snprintf(log, sizeof(log),
584 "format: %s \n codec: %s, file: %s, mode: %s:: ", AMediaFormat_toString(format),
585 encoder, srcPath, (isAsync ? "async" : "sync"));
586 /* TODO(b/147348711) */
587 /* Instead of create and delete codec at every iteration, we would like to create
588 * once and use it for all iterations and delete before exiting */
589 mCodec = AMediaCodec_createCodecByName(encoder);
590 if (!mCodec) {
591 ALOGE("%s unable to create media codec by name %s", log, encoder);
592 isPass = false;
593 continue;
594 }
595 if (!configureCodec(format, isAsync, true, true)) return false;
596 /* test reconfigure in init state */
597 if (!reConfigureCodec(format, !isAsync, false, true)) return false;
598 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
599
600 /* test reconfigure in running state before queuing input */
601 if (!reConfigureCodec(format, !isAsync, false, true)) return false;
602 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
603 if (!doWork(23)) return false;
604
605 /* test reconfigure codec in running state */
606 if (!reConfigureCodec(format, isAsync, true, true)) return false;
607 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
608
609 /* TODO(b/149027258) */
610 if (true) mSaveToMem = false;
611 else mSaveToMem = true;
612 test->reset();
613 if (!doWork(INT32_MAX)) return false;
614 if (!queueEOS()) return false;
615 if (!waitForAllOutputs()) return false;
616 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
617 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
618 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
619 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
620 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
621 isPass);
622 CHECK_ERR((!ref->equals(test)), log, "output is flaky", isPass);
623 if (!isPass) continue;
624
625 /* test reconfigure codec at eos state */
626 if (!reConfigureCodec(format, !isAsync, false, true)) return false;
627 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
628 test->reset();
629 if (!doWork(INT32_MAX)) return false;
630 if (!queueEOS()) return false;
631 if (!waitForAllOutputs()) return false;
632 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
633 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
634 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
635 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
636 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
637 isPass);
638 CHECK_ERR((!ref->equals(test)), log, "output is flaky", isPass);
639
640 /* test reconfigure codec for new format */
641 if (mFormats.size() > 1) {
642 if (!reConfigureCodec(mFormats[1], isAsync, false, true)) return false;
643 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
644 test->reset();
645 if (!doWork(INT32_MAX)) return false;
646 if (!queueEOS()) return false;
647 if (!waitForAllOutputs()) return false;
648 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
649 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
650 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
651 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
652 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
653 isPass);
654 CHECK_ERR((!configRef->equals(test)), log, "output is flaky", isPass);
655 }
656 mSaveToMem = false;
657 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
658 mCodec = nullptr;
659 }
660 return isPass;
661 }
662
testOnlyEos(const char * encoder)663 bool CodecEncoderTest::testOnlyEos(const char* encoder) {
664 bool isPass = true;
665 setUpParams(1);
666 /* TODO(b/149027258) */
667 if (true) mSaveToMem = false;
668 else mSaveToMem = true;
669 auto ref = &mRefBuff;
670 auto test = &mTestBuff;
671 const bool boolStates[]{true, false};
672 AMediaFormat* format = mFormats[0];
673 int loopCounter = 0;
674 for (int k = 0; (k < (sizeof(boolStates) / sizeof(boolStates[0]))) && isPass; k++) {
675 bool isAsync = boolStates[k];
676 char log[1000];
677 snprintf(log, sizeof(log),
678 "format: %s \n codec: %s, mode: %s:: ", AMediaFormat_toString(format), encoder,
679 (isAsync ? "async" : "sync"));
680 mOutputBuff = loopCounter == 0 ? ref : test;
681 mOutputBuff->reset();
682 /* TODO(b/147348711) */
683 /* Instead of create and delete codec at every iteration, we would like to create
684 * once and use it for all iterations and delete before exiting */
685 mCodec = AMediaCodec_createCodecByName(encoder);
686 if (!mCodec) {
687 ALOGE("unable to create media codec by name %s", encoder);
688 isPass = false;
689 continue;
690 }
691 if (!configureCodec(format, isAsync, false, true)) return false;
692 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
693 if (!queueEOS()) return false;
694 if (!waitForAllOutputs()) return false;
695 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
696 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
697 mCodec = nullptr;
698 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
699 CHECK_ERR(loopCounter != 0 && (!ref->equals(test)), log, "output is flaky", isPass);
700 CHECK_ERR(loopCounter == 0 && mIsAudio && (!ref->isPtsStrictlyIncreasing(mPrevOutputPts)),
701 log, "pts is not strictly increasing", isPass);
702 CHECK_ERR(loopCounter == 0 && !mIsAudio &&
703 (!ref->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
704 log, "input pts list and output pts list are not identical", isPass);
705 loopCounter++;
706 }
707 return isPass;
708 }
709
testSetForceSyncFrame(const char * encoder,const char * srcPath)710 bool CodecEncoderTest::testSetForceSyncFrame(const char* encoder, const char* srcPath) {
711 bool isPass = true;
712 setUpSource(srcPath);
713 if (!mInputData) return false;
714 setUpParams(1);
715 AMediaFormat* format = mFormats[0];
716 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 500.f);
717 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth);
718 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight);
719 // Maximum allowed key frame interval variation from the target value.
720 int kMaxKeyFrameIntervalVariation = 3;
721 int kKeyFrameInterval = 2; // force key frame every 2 seconds.
722 int kKeyFramePos = mDefFrameRate * kKeyFrameInterval;
723 int kNumKeyFrameRequests = 7;
724 AMediaFormat* params = AMediaFormat_new();
725 mFormats.push_back(params);
726 mOutputBuff = &mTestBuff;
727 const bool boolStates[]{true, false};
728 for (auto isAsync : boolStates) {
729 if (!isPass) break;
730 char log[1000];
731 snprintf(log, sizeof(log),
732 "format: %s \n codec: %s, file: %s, mode: %s:: ", AMediaFormat_toString(format),
733 encoder, srcPath, (isAsync ? "async" : "sync"));
734 mOutputBuff->reset();
735 /* TODO(b/147348711) */
736 /* Instead of create and delete codec at every iteration, we would like to create
737 * once and use it for all iterations and delete before exiting */
738 mCodec = AMediaCodec_createCodecByName(encoder);
739 if (!mCodec) {
740 ALOGE("%s unable to create media codec by name %s", log, encoder);
741 isPass = false;
742 continue;
743 }
744 if (!configureCodec(format, isAsync, false, true)) return false;
745 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
746 for (int i = 0; i < kNumKeyFrameRequests; i++) {
747 if (!doWork(kKeyFramePos)) return false;
748 assert(!mSawInputEOS);
749 forceSyncFrame(params);
750 mNumBytesSubmitted = 0;
751 }
752 if (!queueEOS()) return false;
753 if (!waitForAllOutputs()) return false;
754 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
755 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
756 mCodec = nullptr;
757 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
758 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
759 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
760 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
761 isPass);
762 CHECK_ERR((!mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)), log,
763 "input pts list and output pts list are not identical", isPass);
764 CHECK_ERR((mNumSyncFramesReceived < kNumKeyFrameRequests), log,
765 "Num Sync Frames Received != Num Key Frame Requested", isPass);
766 ALOGD("mNumSyncFramesReceived %d", mNumSyncFramesReceived);
767 for (int i = 0, expPos = 0, index = 0; i < kNumKeyFrameRequests; i++) {
768 int j = index;
769 for (; j < mSyncFramesPos.size(); j++) {
770 // Check key frame intervals:
771 // key frame position should not be greater than target value + 3
772 // key frame position should not be less than target value - 3
773 if (abs(expPos - mSyncFramesPos.at(j)) <= kMaxKeyFrameIntervalVariation) {
774 index = j;
775 break;
776 }
777 }
778 if (j == mSyncFramesPos.size()) {
779 ALOGW("requested key frame at frame index %d none found near by", expPos);
780 }
781 expPos += kKeyFramePos;
782 }
783 }
784 return isPass;
785 }
786
testAdaptiveBitRate(const char * encoder,const char * srcPath)787 bool CodecEncoderTest::testAdaptiveBitRate(const char* encoder, const char* srcPath) {
788 bool isPass = true;
789 setUpSource(srcPath);
790 if (!mInputData) return false;
791 setUpParams(1);
792 AMediaFormat* format = mFormats[0];
793 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth);
794 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight);
795 int kAdaptiveBitrateInterval = 3; // change bitrate every 3 seconds.
796 int kAdaptiveBitrateDurationFrame = mDefFrameRate * kAdaptiveBitrateInterval;
797 int kBitrateChangeRequests = 7;
798 AMediaFormat* params = AMediaFormat_new();
799 mFormats.push_back(params);
800 // Setting in CBR Mode
801 AMediaFormat_setInt32(format, TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE, kBitrateModeConstant);
802 mOutputBuff = &mTestBuff;
803 mSaveToMem = true;
804 const bool boolStates[]{true, false};
805 for (auto isAsync : boolStates) {
806 if (!isPass) break;
807 char log[1000];
808 snprintf(log, sizeof(log),
809 "format: %s \n codec: %s, file: %s, mode: %s:: ", AMediaFormat_toString(format),
810 encoder, srcPath, (isAsync ? "async" : "sync"));
811 mOutputBuff->reset();
812 /* TODO(b/147348711) */
813 /* Instead of create and delete codec at every iteration, we would like to create
814 * once and use it for all iterations and delete before exiting */
815 mCodec = AMediaCodec_createCodecByName(encoder);
816 if (!mCodec) {
817 ALOGE("%s unable to create media codec by name %s", log, encoder);
818 isPass = false;
819 continue;
820 }
821 if (!configureCodec(format, isAsync, false, true)) return false;
822 CHECK_STATUS(AMediaCodec_start(mCodec), "AMediaCodec_start failed");
823 int expOutSize = 0;
824 int bitrate;
825 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate);
826 for (int i = 0; i < kBitrateChangeRequests; i++) {
827 if (!doWork(kAdaptiveBitrateDurationFrame)) return false;
828 assert(!mSawInputEOS);
829 expOutSize += kAdaptiveBitrateInterval * bitrate;
830 if ((i & 1) == 1) bitrate *= 2;
831 else bitrate /= 2;
832 updateBitrate(params, bitrate);
833 mNumBytesSubmitted = 0;
834 }
835 if (!queueEOS()) return false;
836 if (!waitForAllOutputs()) return false;
837 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
838 CHECK_STATUS(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed");
839 mCodec = nullptr;
840 CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
841 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
842 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
843 CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
844 isPass);
845 CHECK_ERR((!mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)), log,
846 "input pts list and output pts list are not identical", isPass);
847 /* TODO: validate output br with sliding window constraints Sec 5.2 cdd */
848 int outSize = mOutputBuff->getOutStreamSize() * 8;
849 float brDev = abs(expOutSize - outSize) * 100.0f / expOutSize;
850 ALOGD("%s relative bitrate error is %f %%", log, brDev);
851 if (brDev > 50) {
852 ALOGE("%s relative bitrate error is is too large %f %%", log, brDev);
853 return false;
854 }
855 }
856 return isPass;
857 }
858
nativeTestSimpleEncode(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMime,jintArray jList0,jintArray jList1,jintArray jList2,jint colorFormat)859 static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
860 jstring jMime, jintArray jList0, jintArray jList1,
861 jintArray jList2, jint colorFormat) {
862 const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
863 const char* cmime = env->GetStringUTFChars(jMime, nullptr);
864 const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
865 jsize cLen0 = env->GetArrayLength(jList0);
866 jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
867 jsize cLen1 = env->GetArrayLength(jList1);
868 jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
869 jsize cLen2 = env->GetArrayLength(jList2);
870 jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
871 auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
872 (int)colorFormat);
873 bool isPass = codecEncoderTest->testSimpleEncode(cEncoder, csrcPath);
874 delete codecEncoderTest;
875 env->ReleaseIntArrayElements(jList0, cList0, 0);
876 env->ReleaseIntArrayElements(jList1, cList1, 0);
877 env->ReleaseIntArrayElements(jList2, cList2, 0);
878 env->ReleaseStringUTFChars(jEncoder, cEncoder);
879 env->ReleaseStringUTFChars(jMime, cmime);
880 env->ReleaseStringUTFChars(jsrcPath, csrcPath);
881 return static_cast<jboolean>(isPass);
882 }
883
nativeTestFlush(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMime,jintArray jList0,jintArray jList1,jintArray jList2,jint colorFormat)884 static jboolean nativeTestFlush(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
885 jstring jMime, jintArray jList0, jintArray jList1, jintArray jList2,
886 jint colorFormat) {
887 const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
888 const char* cmime = env->GetStringUTFChars(jMime, nullptr);
889 const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
890 jsize cLen0 = env->GetArrayLength(jList0);
891 jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
892 jsize cLen1 = env->GetArrayLength(jList1);
893 jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
894 jsize cLen2 = env->GetArrayLength(jList2);
895 jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
896 auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
897 (int)colorFormat);
898 bool isPass = codecEncoderTest->testFlush(cEncoder, csrcPath);
899 delete codecEncoderTest;
900 env->ReleaseIntArrayElements(jList0, cList0, 0);
901 env->ReleaseIntArrayElements(jList1, cList1, 0);
902 env->ReleaseIntArrayElements(jList2, cList2, 0);
903 env->ReleaseStringUTFChars(jEncoder, cEncoder);
904 env->ReleaseStringUTFChars(jMime, cmime);
905 env->ReleaseStringUTFChars(jsrcPath, csrcPath);
906 return static_cast<jboolean>(isPass);
907 }
908
nativeTestReconfigure(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMime,jintArray jList0,jintArray jList1,jintArray jList2,jint colorFormat)909 static jboolean nativeTestReconfigure(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
910 jstring jMime, jintArray jList0, jintArray jList1,
911 jintArray jList2, jint colorFormat) {
912 bool isPass;
913 const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
914 const char* cmime = env->GetStringUTFChars(jMime, nullptr);
915 const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
916 jsize cLen0 = env->GetArrayLength(jList0);
917 jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
918 jsize cLen1 = env->GetArrayLength(jList1);
919 jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
920 jsize cLen2 = env->GetArrayLength(jList2);
921 jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
922 auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
923 (int)colorFormat);
924 isPass = codecEncoderTest->testReconfigure(cEncoder, csrcPath);
925 delete codecEncoderTest;
926 env->ReleaseIntArrayElements(jList0, cList0, 0);
927 env->ReleaseIntArrayElements(jList1, cList1, 0);
928 env->ReleaseIntArrayElements(jList2, cList2, 0);
929 env->ReleaseStringUTFChars(jEncoder, cEncoder);
930 env->ReleaseStringUTFChars(jMime, cmime);
931 env->ReleaseStringUTFChars(jsrcPath, csrcPath);
932 return static_cast<jboolean>(isPass);
933 }
934
nativeTestSetForceSyncFrame(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMime,jintArray jList0,jintArray jList1,jintArray jList2,jint colorFormat)935 static jboolean nativeTestSetForceSyncFrame(JNIEnv* env, jobject, jstring jEncoder,
936 jstring jsrcPath, jstring jMime, jintArray jList0,
937 jintArray jList1, jintArray jList2, jint colorFormat) {
938 const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
939 const char* cmime = env->GetStringUTFChars(jMime, nullptr);
940 const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
941 jsize cLen0 = env->GetArrayLength(jList0);
942 jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
943 jsize cLen1 = env->GetArrayLength(jList1);
944 jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
945 jsize cLen2 = env->GetArrayLength(jList2);
946 jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
947 auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
948 (int)colorFormat);
949 bool isPass = codecEncoderTest->testSetForceSyncFrame(cEncoder, csrcPath);
950 delete codecEncoderTest;
951 env->ReleaseIntArrayElements(jList0, cList0, 0);
952 env->ReleaseIntArrayElements(jList1, cList1, 0);
953 env->ReleaseIntArrayElements(jList2, cList2, 0);
954 env->ReleaseStringUTFChars(jEncoder, cEncoder);
955 env->ReleaseStringUTFChars(jMime, cmime);
956 env->ReleaseStringUTFChars(jsrcPath, csrcPath);
957 return static_cast<jboolean>(isPass);
958 }
959
nativeTestAdaptiveBitRate(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMime,jintArray jList0,jintArray jList1,jintArray jList2,jint colorFormat)960 static jboolean nativeTestAdaptiveBitRate(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
961 jstring jMime, jintArray jList0, jintArray jList1,
962 jintArray jList2, jint colorFormat) {
963 const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
964 const char* cmime = env->GetStringUTFChars(jMime, nullptr);
965 const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
966 jsize cLen0 = env->GetArrayLength(jList0);
967 jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
968 jsize cLen1 = env->GetArrayLength(jList1);
969 jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
970 jsize cLen2 = env->GetArrayLength(jList2);
971 jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
972 auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
973 (int)colorFormat);
974 bool isPass = codecEncoderTest->testAdaptiveBitRate(cEncoder, csrcPath);
975 delete codecEncoderTest;
976 env->ReleaseIntArrayElements(jList0, cList0, 0);
977 env->ReleaseIntArrayElements(jList1, cList1, 0);
978 env->ReleaseIntArrayElements(jList2, cList2, 0);
979 env->ReleaseStringUTFChars(jEncoder, cEncoder);
980 env->ReleaseStringUTFChars(jMime, cmime);
981 env->ReleaseStringUTFChars(jsrcPath, csrcPath);
982 return static_cast<jboolean>(isPass);
983 }
984
nativeTestOnlyEos(JNIEnv * env,jobject,jstring jEncoder,jstring jMime,jintArray jList0,jintArray jList1,jintArray jList2,jint colorFormat)985 static jboolean nativeTestOnlyEos(JNIEnv* env, jobject, jstring jEncoder, jstring jMime,
986 jintArray jList0, jintArray jList1, jintArray jList2,
987 jint colorFormat) {
988 const char* cmime = env->GetStringUTFChars(jMime, nullptr);
989 const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
990 jsize cLen0 = env->GetArrayLength(jList0);
991 jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
992 jsize cLen1 = env->GetArrayLength(jList1);
993 jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
994 jsize cLen2 = env->GetArrayLength(jList2);
995 jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
996 auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
997 (int)colorFormat);
998 bool isPass = codecEncoderTest->testOnlyEos(cEncoder);
999 delete codecEncoderTest;
1000 env->ReleaseIntArrayElements(jList0, cList0, 0);
1001 env->ReleaseIntArrayElements(jList1, cList1, 0);
1002 env->ReleaseIntArrayElements(jList2, cList2, 0);
1003 env->ReleaseStringUTFChars(jEncoder, cEncoder);
1004 env->ReleaseStringUTFChars(jMime, cmime);
1005 return static_cast<jboolean>(isPass);
1006 }
1007
registerAndroidMediaV2CtsEncoderTest(JNIEnv * env)1008 int registerAndroidMediaV2CtsEncoderTest(JNIEnv* env) {
1009 const JNINativeMethod methodTable[] = {
1010 {"nativeTestSimpleEncode",
1011 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[II)Z",
1012 (void*)nativeTestSimpleEncode},
1013 {"nativeTestFlush", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[II)Z",
1014 (void*)nativeTestFlush},
1015 {"nativeTestReconfigure",
1016 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[II)Z",
1017 (void*)nativeTestReconfigure},
1018 {"nativeTestSetForceSyncFrame",
1019 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[II)Z",
1020 (void*)nativeTestSetForceSyncFrame},
1021 {"nativeTestAdaptiveBitRate",
1022 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[II)Z",
1023 (void*)nativeTestAdaptiveBitRate},
1024 {"nativeTestOnlyEos", "(Ljava/lang/String;Ljava/lang/String;[I[I[II)Z",
1025 (void*)nativeTestOnlyEos},
1026 };
1027 jclass c = env->FindClass("android/mediav2/cts/CodecEncoderTest");
1028 return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
1029 }
1030
1031 extern int registerAndroidMediaV2CtsCodecUnitTest(JNIEnv* env);
1032 extern int registerAndroidMediaV2CtsDecoderTest(JNIEnv* env);
1033 extern int registerAndroidMediaV2CtsDecoderSurfaceTest(JNIEnv* env);
1034 extern int registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv* env);
1035
JNI_OnLoad(JavaVM * vm,void *)1036 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
1037 JNIEnv* env;
1038 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
1039 if (registerAndroidMediaV2CtsCodecUnitTest(env) != JNI_OK) return JNI_ERR;
1040 if (registerAndroidMediaV2CtsEncoderTest(env) != JNI_OK) return JNI_ERR;
1041 if (registerAndroidMediaV2CtsDecoderTest(env) != JNI_OK) return JNI_ERR;
1042 if (registerAndroidMediaV2CtsDecoderSurfaceTest(env) != JNI_OK) return JNI_ERR;
1043 if (registerAndroidMediaV2CtsEncoderSurfaceTest(env) != JNI_OK) return JNI_ERR;
1044 return JNI_VERSION_1_6;
1045 }
1046