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