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