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 "NativeCodecEncoderSurfaceTest"
19 #include <log/log.h>
20 #include <android/native_window_jni.h>
21 #include <NdkMediaExtractor.h>
22 #include <NdkMediaMuxer.h>
23 #include <jni.h>
24 #include <sys/stat.h>
25 
26 #include "NativeCodecTestBase.h"
27 #include "NativeMediaCommon.h"
28 
29 class CodecEncoderSurfaceTest {
30   private:
31     const long kQDeQTimeOutUs = 5000;
32     const char* mMime;
33     ANativeWindow* mWindow;
34     AMediaExtractor* mExtractor;
35     AMediaFormat* mDecFormat;
36     AMediaFormat* mEncFormat;
37     AMediaMuxer* mMuxer;
38     AMediaCodec* mDecoder;
39     AMediaCodec* mEncoder;
40     CodecAsyncHandler mAsyncHandleDecoder;
41     CodecAsyncHandler mAsyncHandleEncoder;
42     bool mIsCodecInAsyncMode;
43     bool mSawDecInputEOS;
44     bool mSawDecOutputEOS;
45     bool mSawEncOutputEOS;
46     bool mSignalEOSWithLastFrame;
47     int mDecInputCount;
48     int mDecOutputCount;
49     int mEncOutputCount;
50     int mEncBitrate;
51     int mEncFramerate;
52     int mMaxBFrames;
53     int mMuxTrackID;
54 
55     OutputManager* mOutputBuff;
56     OutputManager mRefBuff;
57     OutputManager mTestBuff;
58     bool mSaveToMem;
59 
60     bool setUpExtractor(const char* srcPath);
61     void deleteExtractor();
62     bool configureCodec(bool isAsync, bool signalEOSWithLastFrame);
63     void resetContext(bool isAsync, bool signalEOSWithLastFrame);
64     void setUpEncoderFormat();
65     bool enqueueDecoderInput(size_t bufferIndex);
66     bool dequeueDecoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo);
67     bool dequeueEncoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* info);
68     bool tryEncoderOutput(long timeOutUs);
69     bool waitForAllEncoderOutputs();
70     bool queueEOS();
71     bool enqueueDecoderEOS(size_t bufferIndex);
72     bool doWork(int frameLimit);
hasSeenError()73     bool hasSeenError() { return mAsyncHandleDecoder.getError() || mAsyncHandleEncoder.getError(); }
74 
75   public:
76     CodecEncoderSurfaceTest(const char* mime, int bitrate, int framerate);
77     ~CodecEncoderSurfaceTest();
78 
79     bool testSimpleEncode(const char* encoder, const char* decoder, const char* srcPath,
80                           const char* muxOutPath);
81 };
82 
CodecEncoderSurfaceTest(const char * mime,int bitrate,int framerate)83 CodecEncoderSurfaceTest::CodecEncoderSurfaceTest(const char* mime, int bitrate, int framerate)
84     : mMime{mime}, mEncBitrate{bitrate}, mEncFramerate{framerate} {
85     mWindow = nullptr;
86     mExtractor = nullptr;
87     mDecFormat = nullptr;
88     mEncFormat = nullptr;
89     mMuxer = nullptr;
90     mDecoder = nullptr;
91     mEncoder = nullptr;
92     resetContext(false, false);
93     mMaxBFrames = 0;
94     mMuxTrackID = -1;
95 }
96 
~CodecEncoderSurfaceTest()97 CodecEncoderSurfaceTest::~CodecEncoderSurfaceTest() {
98     deleteExtractor();
99     if (mWindow) {
100         ANativeWindow_release(mWindow);
101         mWindow = nullptr;
102     }
103     if (mEncFormat) {
104         AMediaFormat_delete(mEncFormat);
105         mEncFormat = nullptr;
106     }
107     if (mMuxer) {
108         AMediaMuxer_delete(mMuxer);
109         mMuxer = nullptr;
110     }
111     if (mDecoder) {
112         AMediaCodec_delete(mDecoder);
113         mDecoder = nullptr;
114     }
115     if (mEncoder) {
116         AMediaCodec_delete(mEncoder);
117         mEncoder = nullptr;
118     }
119 }
120 
setUpExtractor(const char * srcFile)121 bool CodecEncoderSurfaceTest::setUpExtractor(const char* srcFile) {
122     FILE* fp = fopen(srcFile, "rbe");
123     struct stat buf {};
124     if (fp && !fstat(fileno(fp), &buf)) {
125         deleteExtractor();
126         mExtractor = AMediaExtractor_new();
127         media_status_t res =
128                 AMediaExtractor_setDataSourceFd(mExtractor, fileno(fp), 0, buf.st_size);
129         if (res != AMEDIA_OK) {
130             deleteExtractor();
131         } else {
132             for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(mExtractor);
133                  trackID++) {
134                 AMediaFormat* currFormat = AMediaExtractor_getTrackFormat(mExtractor, trackID);
135                 const char* mime = nullptr;
136                 AMediaFormat_getString(currFormat, AMEDIAFORMAT_KEY_MIME, &mime);
137                 if (mime && strncmp(mime, "video/", strlen("video/")) == 0) {
138                     AMediaExtractor_selectTrack(mExtractor, trackID);
139                     AMediaFormat_setInt32(currFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT,
140                                           COLOR_FormatYUV420Flexible);
141                     mDecFormat = currFormat;
142                     break;
143                 }
144                 AMediaFormat_delete(currFormat);
145             }
146         }
147     }
148     if (fp) fclose(fp);
149     return mDecFormat != nullptr;
150 }
151 
deleteExtractor()152 void CodecEncoderSurfaceTest::deleteExtractor() {
153     if (mExtractor) {
154         AMediaExtractor_delete(mExtractor);
155         mExtractor = nullptr;
156     }
157     if (mDecFormat) {
158         AMediaFormat_delete(mDecFormat);
159         mDecFormat = nullptr;
160     }
161 }
162 
configureCodec(bool isAsync,bool signalEOSWithLastFrame)163 bool CodecEncoderSurfaceTest::configureCodec(bool isAsync, bool signalEOSWithLastFrame) {
164     resetContext(isAsync, signalEOSWithLastFrame);
165     CHECK_STATUS(mAsyncHandleEncoder.setCallBack(mEncoder, isAsync),
166                  "AMediaCodec_setAsyncNotifyCallback failed");
167     CHECK_STATUS(AMediaCodec_configure(mEncoder, mEncFormat, nullptr, nullptr,
168                                        AMEDIACODEC_CONFIGURE_FLAG_ENCODE),
169                  "AMediaCodec_configure failed");
170     CHECK_STATUS(AMediaCodec_createInputSurface(mEncoder, &mWindow),
171                  "AMediaCodec_createInputSurface failed");
172     CHECK_STATUS(mAsyncHandleDecoder.setCallBack(mDecoder, isAsync),
173                  "AMediaCodec_setAsyncNotifyCallback failed");
174     CHECK_STATUS(AMediaCodec_configure(mDecoder, mDecFormat, mWindow, nullptr, 0),
175                  "AMediaCodec_configure failed");
176     return !hasSeenError();
177 }
178 
resetContext(bool isAsync,bool signalEOSWithLastFrame)179 void CodecEncoderSurfaceTest::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
180     mAsyncHandleDecoder.resetContext();
181     mAsyncHandleEncoder.resetContext();
182     mIsCodecInAsyncMode = isAsync;
183     mSawDecInputEOS = false;
184     mSawDecOutputEOS = false;
185     mSawEncOutputEOS = false;
186     mSignalEOSWithLastFrame = signalEOSWithLastFrame;
187     mDecInputCount = 0;
188     mDecOutputCount = 0;
189     mEncOutputCount = 0;
190 }
191 
setUpEncoderFormat()192 void CodecEncoderSurfaceTest::setUpEncoderFormat() {
193     if (mEncFormat) AMediaFormat_delete(mEncFormat);
194     mEncFormat = AMediaFormat_new();
195     int width, height;
196     AMediaFormat_getInt32(mDecFormat, AMEDIAFORMAT_KEY_WIDTH, &width);
197     AMediaFormat_getInt32(mDecFormat, AMEDIAFORMAT_KEY_HEIGHT, &height);
198     AMediaFormat_setString(mEncFormat, AMEDIAFORMAT_KEY_MIME, mMime);
199     AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_WIDTH, width);
200     AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_HEIGHT, height);
201     AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_BIT_RATE, mEncBitrate);
202     AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_FRAME_RATE, mEncFramerate);
203     AMediaFormat_setInt32(mEncFormat, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES, mMaxBFrames);
204     AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatSurface);
205     AMediaFormat_setFloat(mEncFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1.0F);
206 }
207 
enqueueDecoderEOS(size_t bufferIndex)208 bool CodecEncoderSurfaceTest::enqueueDecoderEOS(size_t bufferIndex) {
209     if (!hasSeenError() && !mSawDecInputEOS) {
210         CHECK_STATUS(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, 0, 0,
211                                                   AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM),
212                      "Queued Decoder End of Stream Failed");
213         mSawDecInputEOS = true;
214         ALOGV("Queued Decoder End of Stream");
215     }
216     return !hasSeenError();
217 }
218 
enqueueDecoderInput(size_t bufferIndex)219 bool CodecEncoderSurfaceTest::enqueueDecoderInput(size_t bufferIndex) {
220     if (AMediaExtractor_getSampleSize(mExtractor) < 0) {
221         return enqueueDecoderEOS(bufferIndex);
222     } else {
223         uint32_t flags = 0;
224         size_t bufSize = 0;
225         uint8_t* buf = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufSize);
226         if (buf == nullptr) {
227             ALOGE("AMediaCodec_getInputBuffer failed");
228             return false;
229         }
230         ssize_t size = AMediaExtractor_getSampleSize(mExtractor);
231         int64_t pts = AMediaExtractor_getSampleTime(mExtractor);
232         if (size > bufSize) {
233             ALOGE("extractor sample size exceeds codec input buffer size %zu %zu", size, bufSize);
234             return false;
235         }
236         if (size != AMediaExtractor_readSampleData(mExtractor, buf, bufSize)) {
237             ALOGE("AMediaExtractor_readSampleData failed");
238             return false;
239         }
240         if (!AMediaExtractor_advance(mExtractor) && mSignalEOSWithLastFrame) {
241             flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
242             mSawDecInputEOS = true;
243         }
244         CHECK_STATUS(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, size, pts, flags),
245                      "AMediaCodec_queueInputBuffer failed");
246         ALOGV("input: id: %zu  size: %zu  pts: %d  flags: %d", bufferIndex, size, (int)pts, flags);
247         if (size > 0) {
248             mOutputBuff->saveInPTS(pts);
249             mDecInputCount++;
250         }
251     }
252     return !hasSeenError();
253 }
254 
dequeueDecoderOutput(size_t bufferIndex,AMediaCodecBufferInfo * bufferInfo)255 bool CodecEncoderSurfaceTest::dequeueDecoderOutput(size_t bufferIndex,
256                                                    AMediaCodecBufferInfo* bufferInfo) {
257     if ((bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
258         mSawDecOutputEOS = true;
259     }
260     if (bufferInfo->size > 0 && (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
261         mDecOutputCount++;
262     }
263     ALOGV("output: id: %zu  size: %d  pts: %d  flags: %d", bufferIndex, bufferInfo->size,
264           (int)bufferInfo->presentationTimeUs, bufferInfo->flags);
265     CHECK_STATUS(AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, mWindow != nullptr),
266                  "AMediaCodec_releaseOutputBuffer failed");
267     return !hasSeenError();
268 }
269 
dequeueEncoderOutput(size_t bufferIndex,AMediaCodecBufferInfo * info)270 bool CodecEncoderSurfaceTest::dequeueEncoderOutput(size_t bufferIndex,
271                                                    AMediaCodecBufferInfo* info) {
272     if ((info->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
273         mSawEncOutputEOS = true;
274     }
275     if (info->size > 0) {
276         size_t buffSize;
277         uint8_t* buf = AMediaCodec_getOutputBuffer(mEncoder, bufferIndex, &buffSize);
278         if (mSaveToMem) {
279             mOutputBuff->saveToMemory(buf, info);
280         }
281         if (mMuxer != nullptr) {
282             if (mMuxTrackID == -1) {
283                 mMuxTrackID = AMediaMuxer_addTrack(mMuxer, AMediaCodec_getOutputFormat(mEncoder));
284                 CHECK_STATUS(AMediaMuxer_start(mMuxer), "AMediaMuxer_start failed");
285             }
286             CHECK_STATUS(AMediaMuxer_writeSampleData(mMuxer, mMuxTrackID, buf, info),
287                          "AMediaMuxer_writeSampleData failed");
288         }
289         if ((info->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
290             mOutputBuff->saveOutPTS(info->presentationTimeUs);
291             mEncOutputCount++;
292         }
293     }
294     ALOGV("output: id: %zu  size: %d  pts: %d  flags: %d", bufferIndex, info->size,
295           (int)info->presentationTimeUs, info->flags);
296     CHECK_STATUS(AMediaCodec_releaseOutputBuffer(mEncoder, bufferIndex, false),
297                  "AMediaCodec_releaseOutputBuffer failed");
298     return !hasSeenError();
299 }
300 
tryEncoderOutput(long timeOutUs)301 bool CodecEncoderSurfaceTest::tryEncoderOutput(long timeOutUs) {
302     if (mIsCodecInAsyncMode) {
303         if (!hasSeenError() && !mSawEncOutputEOS) {
304             callbackObject element = mAsyncHandleEncoder.getOutput();
305             if (element.bufferIndex >= 0) {
306                 if (!dequeueEncoderOutput(element.bufferIndex, &element.bufferInfo)) return false;
307             }
308         }
309     } else {
310         AMediaCodecBufferInfo outInfo;
311         if (!mSawEncOutputEOS) {
312             int bufferID = AMediaCodec_dequeueOutputBuffer(mEncoder, &outInfo, timeOutUs);
313             if (bufferID >= 0) {
314                 if (!dequeueEncoderOutput(bufferID, &outInfo)) return false;
315             } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
316             } else if (bufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
317             } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
318             } else {
319                 ALOGE("unexpected return value from *_dequeueOutputBuffer: %d", (int)bufferID);
320                 return false;
321             }
322         }
323     }
324     return !hasSeenError();
325 }
326 
waitForAllEncoderOutputs()327 bool CodecEncoderSurfaceTest::waitForAllEncoderOutputs() {
328     if (mIsCodecInAsyncMode) {
329         while (!hasSeenError() && !mSawEncOutputEOS) {
330             if (!tryEncoderOutput(kQDeQTimeOutUs)) return false;
331         }
332     } else {
333         while (!mSawEncOutputEOS) {
334             if (!tryEncoderOutput(kQDeQTimeOutUs)) return false;
335         }
336     }
337     return !hasSeenError();
338 }
339 
queueEOS()340 bool CodecEncoderSurfaceTest::queueEOS() {
341     if (mIsCodecInAsyncMode) {
342         if (!hasSeenError() && !mSawDecInputEOS) {
343             callbackObject element = mAsyncHandleDecoder.getInput();
344             if (element.bufferIndex >= 0) {
345                 if (!enqueueDecoderEOS(element.bufferIndex)) return false;
346             }
347         }
348     } else {
349         if (!mSawDecInputEOS) {
350             int bufferIndex = AMediaCodec_dequeueInputBuffer(mDecoder, -1);
351             if (bufferIndex >= 0) {
352                 if (!enqueueDecoderEOS(bufferIndex)) return false;
353             } else {
354                 ALOGE("unexpected return value from *_dequeueInputBufferBuffer: %d",
355                       (int)bufferIndex);
356                 return false;
357             }
358         }
359     }
360 
361     if (mIsCodecInAsyncMode) {
362         // output processing after queuing EOS is done in waitForAllOutputs()
363         while (!hasSeenError() && !mSawDecOutputEOS) {
364             callbackObject element = mAsyncHandleDecoder.getOutput();
365             if (element.bufferIndex >= 0) {
366                 if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) return false;
367             }
368             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
369             if (mDecOutputCount - mEncOutputCount > mMaxBFrames) {
370                 if (!tryEncoderOutput(-1)) return false;
371             }
372         }
373     } else {
374         AMediaCodecBufferInfo outInfo;
375         // output processing after queuing EOS is done in waitForAllOutputs()
376         while (!mSawDecOutputEOS) {
377             if (!mSawDecOutputEOS) {
378                 ssize_t oBufferID =
379                         AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
380                 if (oBufferID >= 0) {
381                     if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
382                 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
383                 } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
384                 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
385                 } else {
386                     ALOGE("unexpected return value from *_dequeueOutputBuffer: %d", (int)oBufferID);
387                     return false;
388                 }
389             }
390             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
391             if (mDecOutputCount - mEncOutputCount > mMaxBFrames) {
392                 if (!tryEncoderOutput(-1)) return false;
393             }
394         }
395     }
396     return !hasSeenError();
397 }
398 
doWork(int frameLimit)399 bool CodecEncoderSurfaceTest::doWork(int frameLimit) {
400     int frameCnt = 0;
401     if (mIsCodecInAsyncMode) {
402         // output processing after queuing EOS is done in waitForAllOutputs()
403         while (!hasSeenError() && !mSawDecInputEOS && frameCnt < frameLimit) {
404             callbackObject element = mAsyncHandleDecoder.getWork();
405             if (element.bufferIndex >= 0) {
406                 if (element.isInput) {
407                     if (!enqueueDecoderInput(element.bufferIndex)) return false;
408                     frameCnt++;
409                 } else {
410                     if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) {
411                         return false;
412                     }
413                 }
414             }
415             // check decoder EOS
416             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
417             // encoder output
418             // TODO: remove fixed constant and change it according to encoder latency
419             if (mDecOutputCount - mEncOutputCount > mMaxBFrames) {
420                 if (!tryEncoderOutput(-1)) return false;
421             }
422         }
423     } else {
424         AMediaCodecBufferInfo outInfo;
425         // output processing after queuing EOS is done in waitForAllOutputs()
426         while (!mSawDecInputEOS && frameCnt < frameLimit) {
427             ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
428             if (oBufferID >= 0) {
429                 if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
430             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
431             } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
432             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
433             } else {
434                 ALOGE("unexpected return value from *_dequeueOutputBuffer: %d", (int)oBufferID);
435                 return false;
436             }
437             ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mDecoder, kQDeQTimeOutUs);
438             if (iBufferId >= 0) {
439                 if (!enqueueDecoderInput(iBufferId)) return false;
440                 frameCnt++;
441             } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
442             } else {
443                 ALOGE("unexpected return value from *_dequeueInputBuffer: %d", (int)iBufferId);
444                 return false;
445             }
446             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
447             // TODO: remove fixed constant and change it according to encoder latency
448             if (mDecOutputCount - mEncOutputCount > mMaxBFrames) {
449                 if (!tryEncoderOutput(-1)) return false;
450             }
451         }
452     }
453     return !hasSeenError();
454 }
455 
testSimpleEncode(const char * encoder,const char * decoder,const char * srcPath,const char * muxOutPath)456 bool CodecEncoderSurfaceTest::testSimpleEncode(const char* encoder, const char* decoder,
457                                                const char* srcPath, const char* muxOutPath) {
458     bool isPass = true;
459     if (!setUpExtractor(srcPath)) {
460         ALOGE("setUpExtractor failed");
461         return false;
462     }
463     setUpEncoderFormat();
464     bool muxOutput = true;
465 
466     /* TODO(b/149027258) */
467     if (true) mSaveToMem = false;
468     else mSaveToMem = true;
469     auto ref = &mRefBuff;
470     auto test = &mTestBuff;
471     int loopCounter = 0;
472     const bool boolStates[]{true, false};
473     for (bool isAsync : boolStates) {
474         if (!isPass) break;
475         AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
476         mOutputBuff = loopCounter == 0 ? ref : test;
477         mOutputBuff->reset();
478 
479         /* TODO(b/147348711) */
480         /* Instead of create and delete codec at every iteration, we would like to create
481          * once and use it for all iterations and delete before exiting */
482         mEncoder = AMediaCodec_createCodecByName(encoder);
483         mDecoder = AMediaCodec_createCodecByName(decoder);
484         if (!mDecoder || !mEncoder) {
485             ALOGE("unable to create media codec by name %s or %s", encoder, decoder);
486             isPass = false;
487             continue;
488         }
489 
490         FILE* ofp = nullptr;
491         if (muxOutput && loopCounter == 0) {
492             int muxerFormat = 0;
493             if (!strcmp(mMime, AMEDIA_MIMETYPE_VIDEO_VP8) ||
494                 !strcmp(mMime, AMEDIA_MIMETYPE_VIDEO_VP9)) {
495                 muxerFormat = OUTPUT_FORMAT_WEBM;
496             } else {
497                 muxerFormat = OUTPUT_FORMAT_MPEG_4;
498             }
499             ofp = fopen(muxOutPath, "wbe+");
500             if (ofp) {
501                 mMuxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)muxerFormat);
502             }
503         }
504         if (!configureCodec(mIsCodecInAsyncMode, mSignalEOSWithLastFrame)) return false;
505         CHECK_STATUS(AMediaCodec_start(mEncoder), "AMediaCodec_start failed");
506         CHECK_STATUS(AMediaCodec_start(mDecoder), "AMediaCodec_start failed");
507         if (!doWork(INT32_MAX)) return false;
508         if (!queueEOS()) return false;
509         if (!waitForAllEncoderOutputs()) return false;
510         if (muxOutput) {
511             if (mMuxer != nullptr) {
512                 CHECK_STATUS(AMediaMuxer_stop(mMuxer), "AMediaMuxer_stop failed");
513                 mMuxTrackID = -1;
514                 CHECK_STATUS(AMediaMuxer_delete(mMuxer), "AMediaMuxer_delete failed");
515                 mMuxer = nullptr;
516             }
517             if (ofp) fclose(ofp);
518         }
519         CHECK_STATUS(AMediaCodec_stop(mDecoder), "AMediaCodec_stop failed");
520         CHECK_STATUS(AMediaCodec_stop(mEncoder), "AMediaCodec_stop failed");
521         char log[1000];
522         snprintf(log, sizeof(log), "format: %s \n codec: %s, file: %s, mode: %s:: ",
523                  AMediaFormat_toString(mEncFormat), encoder, srcPath, (isAsync ? "async" : "sync"));
524         CHECK_ERR((hasSeenError()), log, "has seen error", isPass);
525         CHECK_ERR((0 == mDecInputCount), log, "no input sent", isPass);
526         CHECK_ERR((0 == mDecOutputCount), log, "no decoder output received", isPass);
527         CHECK_ERR((0 == mEncOutputCount), log, "no encoder output received", isPass);
528         CHECK_ERR((mDecInputCount != mDecOutputCount), log, "decoder input count != output count",
529                   isPass);
530         /* TODO(b/153127506)
531          *  Currently disabling all encoder output checks. Added checks only for encoder timeStamp
532          *  is in increasing order or not.
533          *  Once issue is fixed remove increasing timestamp check and enable encoder checks.
534          */
535         /*CHECK_ERR((mEncOutputCount != mDecOutputCount), log,
536                   "encoder output count != decoder output count", isPass);
537         CHECK_ERR((loopCounter != 0 && !ref->equals(test)), log, "output is flaky", isPass);
538         CHECK_ERR((loopCounter == 0 && !ref->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
539                   log, "input pts list and output pts list are not identical", isPass);*/
540         CHECK_ERR(loopCounter == 0 && (!ref->isPtsStrictlyIncreasing(INT32_MIN)), log,
541                   "Ref pts is not strictly increasing", isPass);
542         CHECK_ERR(loopCounter != 0 && (!test->isPtsStrictlyIncreasing(INT32_MIN)), log,
543                   "Test pts is not strictly increasing", isPass);
544 
545         loopCounter++;
546         ANativeWindow_release(mWindow);
547         mWindow = nullptr;
548         CHECK_STATUS(AMediaCodec_delete(mEncoder), "AMediaCodec_delete failed");
549         mEncoder = nullptr;
550         CHECK_STATUS(AMediaCodec_delete(mDecoder), "AMediaCodec_delete failed");
551         mDecoder = nullptr;
552     }
553     return isPass;
554 }
555 
nativeTestSimpleEncode(JNIEnv * env,jobject,jstring jEncoder,jstring jDecoder,jstring jMime,jstring jtestFile,jstring jmuxFile,jint jBitrate,jint jFramerate)556 static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jDecoder,
557                                        jstring jMime, jstring jtestFile, jstring jmuxFile,
558                                        jint jBitrate, jint jFramerate) {
559     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
560     const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
561     const char* cMime = env->GetStringUTFChars(jMime, nullptr);
562     const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
563     const char* cMuxFile = env->GetStringUTFChars(jmuxFile, nullptr);
564     auto codecEncoderSurfaceTest =
565             new CodecEncoderSurfaceTest(cMime, (int)jBitrate, (int)jFramerate);
566     bool isPass =
567             codecEncoderSurfaceTest->testSimpleEncode(cEncoder, cDecoder, cTestFile, cMuxFile);
568     delete codecEncoderSurfaceTest;
569     env->ReleaseStringUTFChars(jEncoder, cEncoder);
570     env->ReleaseStringUTFChars(jDecoder, cDecoder);
571     env->ReleaseStringUTFChars(jMime, cMime);
572     env->ReleaseStringUTFChars(jtestFile, cTestFile);
573     env->ReleaseStringUTFChars(jmuxFile, cMuxFile);
574     return static_cast<jboolean>(isPass);
575 }
576 
registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv * env)577 int registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv* env) {
578     const JNINativeMethod methodTable[] = {
579             {"nativeTestSimpleEncode",
580              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
581              "String;II)Z",
582              (void*)nativeTestSimpleEncode},
583     };
584     jclass c = env->FindClass("android/mediav2/cts/CodecEncoderSurfaceTest");
585     return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
586 }
587