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