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 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 102 CodecEncoderTest::~CodecEncoderTest() { 103 deleteSource(); 104 deleteParams(); 105 } 106 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 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 146 void CodecEncoderTest::deleteSource() { 147 if (mInputData) { 148 delete[] mInputData; 149 mInputData = nullptr; 150 } 151 mInputLength = 0; 152 } 153 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 200 void CodecEncoderTest::deleteParams() { 201 for (auto format : mFormats) AMediaFormat_delete(format); 202 mFormats.clear(); 203 } 204 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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