• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 #include <android/native_window_jni.h>
22 #include <jni.h>
23 #include <media/NdkMediaExtractor.h>
24 #include <media/NdkMediaMuxer.h>
25 #include <sys/stat.h>
26 
27 #include "NativeCodecTestBase.h"
28 #include "NativeMediaCommon.h"
29 
30 class CodecEncoderSurfaceTest {
31   private:
32     const char* mMediaType;
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 mMaxBFrames;
51     int mLatency;
52     bool mReviseLatency;
53     int mMuxTrackID;
54 
55     OutputManager* mOutputBuff;
56     OutputManager* mRefBuff;
57     OutputManager* mTestBuff;
58     bool mSaveToMem;
59 
60     std::string mErrorLogs;
61     std::string mTestEnv;
62 
63     bool setUpExtractor(const char* srcFile, int colorFormat);
64     void deleteExtractor();
65     bool configureCodec(bool isAsync, bool signalEOSWithLastFrame, bool usePersistentSurface);
66     void resetContext(bool isAsync, bool signalEOSWithLastFrame);
67     bool enqueueDecoderInput(size_t bufferIndex);
68     bool dequeueDecoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo);
69     bool dequeueEncoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* info);
70     bool tryEncoderOutput(long timeOutUs);
71     bool waitForAllEncoderOutputs();
72     bool queueEOS();
73     bool enqueueDecoderEOS(size_t bufferIndex);
74     bool doWork(int frameLimit);
hasSeenError()75     bool hasSeenError() { return mAsyncHandleDecoder.getError() || mAsyncHandleEncoder.getError(); }
76 
77   public:
getErrorMsg()78     std::string getErrorMsg() {
79         return mTestEnv +
80                 "###################       Error Details         #####################\n" +
81                 mErrorLogs;
82     }
83     CodecEncoderSurfaceTest(const char* mediaType, const char* cfgParams, const char* separator);
84     ~CodecEncoderSurfaceTest();
85 
86     bool testSimpleEncode(const char* encoder, const char* decoder, const char* srcPath,
87                           const char* muxOutPath, int colorFormat, bool usePersistentSurface);
88 };
89 
CodecEncoderSurfaceTest(const char * mediaType,const char * cfgParams,const char * separator)90 CodecEncoderSurfaceTest::CodecEncoderSurfaceTest(const char* mediaType, const char* cfgParams,
91                                                  const char* separator)
92     : mMediaType{mediaType} {
93     mWindow = nullptr;
94     mExtractor = nullptr;
95     mDecFormat = nullptr;
96     mEncFormat = deSerializeMediaFormat(cfgParams, separator);
97     mMuxer = nullptr;
98     mDecoder = nullptr;
99     mEncoder = nullptr;
100     resetContext(false, false);
101     mMaxBFrames = 0;
102     if (mEncFormat != nullptr) {
103         AMediaFormat_getInt32(mEncFormat, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES, &mMaxBFrames);
104     }
105     mLatency = mMaxBFrames;
106     mReviseLatency = false;
107     mMuxTrackID = -1;
108     mRefBuff = new OutputManager();
109     mTestBuff = new OutputManager(mRefBuff->getSharedErrorLogs());
110 }
111 
~CodecEncoderSurfaceTest()112 CodecEncoderSurfaceTest::~CodecEncoderSurfaceTest() {
113     deleteExtractor();
114     if (mWindow) {
115         ANativeWindow_release(mWindow);
116         mWindow = nullptr;
117     }
118     if (mEncFormat) {
119         AMediaFormat_delete(mEncFormat);
120         mEncFormat = nullptr;
121     }
122     if (mMuxer) {
123         AMediaMuxer_delete(mMuxer);
124         mMuxer = nullptr;
125     }
126     if (mDecoder) {
127         AMediaCodec_delete(mDecoder);
128         mDecoder = nullptr;
129     }
130     if (mEncoder) {
131         AMediaCodec_delete(mEncoder);
132         mEncoder = nullptr;
133     }
134     delete mRefBuff;
135     delete mTestBuff;
136 }
137 
setUpExtractor(const char * srcFile,int colorFormat)138 bool CodecEncoderSurfaceTest::setUpExtractor(const char* srcFile, int colorFormat) {
139     FILE* fp = fopen(srcFile, "rbe");
140     struct stat buf {};
141     if (fp && !fstat(fileno(fp), &buf)) {
142         deleteExtractor();
143         mExtractor = AMediaExtractor_new();
144         media_status_t res =
145                 AMediaExtractor_setDataSourceFd(mExtractor, fileno(fp), 0, buf.st_size);
146         if (res != AMEDIA_OK) {
147             deleteExtractor();
148         } else {
149             for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(mExtractor);
150                  trackID++) {
151                 AMediaFormat* currFormat = AMediaExtractor_getTrackFormat(mExtractor, trackID);
152                 const char* mediaType = nullptr;
153                 AMediaFormat_getString(currFormat, AMEDIAFORMAT_KEY_MIME, &mediaType);
154                 if (mediaType && strncmp(mediaType, "video/", strlen("video/")) == 0) {
155                     AMediaExtractor_selectTrack(mExtractor, trackID);
156                     AMediaFormat_setInt32(currFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, colorFormat);
157                     mDecFormat = currFormat;
158                     break;
159                 }
160                 AMediaFormat_delete(currFormat);
161             }
162         }
163     }
164     if (fp) fclose(fp);
165     return mDecFormat != nullptr;
166 }
167 
deleteExtractor()168 void CodecEncoderSurfaceTest::deleteExtractor() {
169     if (mExtractor) {
170         AMediaExtractor_delete(mExtractor);
171         mExtractor = nullptr;
172     }
173     if (mDecFormat) {
174         AMediaFormat_delete(mDecFormat);
175         mDecFormat = nullptr;
176     }
177 }
178 
configureCodec(bool isAsync,bool signalEOSWithLastFrame,bool usePersistentSurface)179 bool CodecEncoderSurfaceTest::configureCodec(bool isAsync, bool signalEOSWithLastFrame,
180                                              bool usePersistentSurface) {
181     RETURN_IF_NULL(mEncFormat,
182                    std::string{"encountered error during deserialization of media format"})
183     resetContext(isAsync, signalEOSWithLastFrame);
184     mTestEnv = "###################      Test Environment       #####################\n";
185     {
186         char* name = nullptr;
187         media_status_t val = AMediaCodec_getName(mEncoder, &name);
188         if (AMEDIA_OK != val) {
189             mErrorLogs = StringFormat("%s with error %d \n", "AMediaCodec_getName failed", val);
190             return false;
191         }
192         if (!name) {
193             mErrorLogs = std::string{"AMediaCodec_getName returned null"};
194             return false;
195         }
196         mTestEnv.append(StringFormat("Component name %s \n", name));
197         AMediaCodec_releaseName(mEncoder, name);
198     }
199     {
200         char* name = nullptr;
201         media_status_t val = AMediaCodec_getName(mDecoder, &name);
202         if (AMEDIA_OK != val) {
203             mErrorLogs = StringFormat("%s with error %d \n", "AMediaCodec_getName failed", val);
204             return false;
205         }
206         if (!name) {
207             mErrorLogs = std::string{"AMediaCodec_getName returned null"};
208             return false;
209         }
210         mTestEnv.append(StringFormat("Decoder Component name %s \n", name));
211         AMediaCodec_releaseName(mDecoder, name);
212     }
213     mTestEnv += StringFormat("Format under test :- %s \n", AMediaFormat_toString(mEncFormat));
214     mTestEnv += StringFormat("Format of Decoder input :- %s \n", AMediaFormat_toString(mDecFormat));
215     mTestEnv += StringFormat("Encoder and Decoder are operating in :- %s mode \n",
216                              (isAsync ? "asynchronous" : "synchronous"));
217     mTestEnv += StringFormat("Components received input eos :- %s \n",
218                              (signalEOSWithLastFrame ? "with full buffer" : "with empty buffer"));
219     RETURN_IF_FAIL(mAsyncHandleEncoder.setCallBack(mEncoder, isAsync),
220                    "AMediaCodec_setAsyncNotifyCallback failed")
221     RETURN_IF_FAIL(AMediaCodec_configure(mEncoder, mEncFormat, nullptr, nullptr,
222                                          AMEDIACODEC_CONFIGURE_FLAG_ENCODE),
223                    "AMediaCodec_configure failed")
224     AMediaFormat* inpFormat = AMediaCodec_getInputFormat(mEncoder);
225     mReviseLatency = AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_LATENCY, &mLatency);
226     AMediaFormat_delete(inpFormat);
227 
228     if (usePersistentSurface) {
229         RETURN_IF_FAIL(AMediaCodec_createPersistentInputSurface(&mWindow),
230                        "AMediaCodec_createPersistentInputSurface failed")
231         RETURN_IF_FAIL(AMediaCodec_setInputSurface(mEncoder,
232                                                    reinterpret_cast<ANativeWindow*>(mWindow)),
233                        "AMediaCodec_setInputSurface failed")
234     } else {
235         RETURN_IF_FAIL(AMediaCodec_createInputSurface(mEncoder, &mWindow),
236                        "AMediaCodec_createInputSurface failed")
237     }
238     RETURN_IF_FAIL(mAsyncHandleDecoder.setCallBack(mDecoder, isAsync),
239                    "AMediaCodec_setAsyncNotifyCallback failed")
240     RETURN_IF_FAIL(AMediaCodec_configure(mDecoder, mDecFormat, mWindow, nullptr, 0),
241                    "AMediaCodec_configure failed")
242     return !hasSeenError();
243 }
244 
resetContext(bool isAsync,bool signalEOSWithLastFrame)245 void CodecEncoderSurfaceTest::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
246     mAsyncHandleDecoder.resetContext();
247     mAsyncHandleEncoder.resetContext();
248     mIsCodecInAsyncMode = isAsync;
249     mSawDecInputEOS = false;
250     mSawDecOutputEOS = false;
251     mSawEncOutputEOS = false;
252     mSignalEOSWithLastFrame = signalEOSWithLastFrame;
253     mDecInputCount = 0;
254     mDecOutputCount = 0;
255     mEncOutputCount = 0;
256 }
257 
enqueueDecoderEOS(size_t bufferIndex)258 bool CodecEncoderSurfaceTest::enqueueDecoderEOS(size_t bufferIndex) {
259     if (!hasSeenError() && !mSawDecInputEOS) {
260         RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, 0, 0,
261                                                     AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM),
262                        "Queued Decoder End of Stream Failed")
263         mSawDecInputEOS = true;
264         ALOGV("Queued Decoder End of Stream");
265     }
266     return !hasSeenError();
267 }
268 
enqueueDecoderInput(size_t bufferIndex)269 bool CodecEncoderSurfaceTest::enqueueDecoderInput(size_t bufferIndex) {
270     if (AMediaExtractor_getSampleSize(mExtractor) < 0) {
271         return enqueueDecoderEOS(bufferIndex);
272     } else {
273         uint32_t flags = 0;
274         size_t bufSize = 0;
275         uint8_t* buf = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufSize);
276         RETURN_IF_NULL(buf, std::string{"AMediaCodec_getInputBuffer failed"})
277         ssize_t size = AMediaExtractor_getSampleSize(mExtractor);
278         int64_t pts = AMediaExtractor_getSampleTime(mExtractor);
279         RETURN_IF_TRUE(size > bufSize,
280                        StringFormat("extractor sample size exceeds codec input buffer size %zu %zu",
281                                     size, bufSize))
282         RETURN_IF_TRUE(size != AMediaExtractor_readSampleData(mExtractor, buf, bufSize),
283                        std::string{"AMediaExtractor_readSampleData failed"})
284         if (!AMediaExtractor_advance(mExtractor) && mSignalEOSWithLastFrame) {
285             flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
286             mSawDecInputEOS = true;
287         }
288         RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, size, pts, flags),
289                        "AMediaCodec_queueInputBuffer failed")
290         ALOGV("input: id: %zu  size: %zu  pts: %" PRId64 "  flags: %d", bufferIndex, size, pts,
291               flags);
292         if (size > 0) {
293             mOutputBuff->saveInPTS(pts);
294             mDecInputCount++;
295         }
296     }
297     return !hasSeenError();
298 }
299 
dequeueDecoderOutput(size_t bufferIndex,AMediaCodecBufferInfo * bufferInfo)300 bool CodecEncoderSurfaceTest::dequeueDecoderOutput(size_t bufferIndex,
301                                                    AMediaCodecBufferInfo* bufferInfo) {
302     if ((bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
303         mSawDecOutputEOS = true;
304     }
305     if (bufferInfo->size > 0 && (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
306         mDecOutputCount++;
307     }
308     ALOGV("output: id: %zu  size: %d  pts: %" PRId64 "  flags: %d", bufferIndex, bufferInfo->size,
309           bufferInfo->presentationTimeUs, bufferInfo->flags);
310     RETURN_IF_FAIL(AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, mWindow != nullptr),
311                    "AMediaCodec_releaseOutputBuffer failed")
312     return !hasSeenError();
313 }
314 
dequeueEncoderOutput(size_t bufferIndex,AMediaCodecBufferInfo * info)315 bool CodecEncoderSurfaceTest::dequeueEncoderOutput(size_t bufferIndex,
316                                                    AMediaCodecBufferInfo* info) {
317     if ((info->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
318         mSawEncOutputEOS = true;
319     }
320     if (info->size > 0) {
321         size_t buffSize;
322         uint8_t* buf = AMediaCodec_getOutputBuffer(mEncoder, bufferIndex, &buffSize);
323         if (mSaveToMem) {
324             mOutputBuff->saveToMemory(buf, info);
325         }
326         if (mMuxer != nullptr) {
327             if (mMuxTrackID == -1) {
328                 mMuxTrackID = AMediaMuxer_addTrack(mMuxer, AMediaCodec_getOutputFormat(mEncoder));
329                 RETURN_IF_FAIL(AMediaMuxer_start(mMuxer), "AMediaMuxer_start failed")
330             }
331             RETURN_IF_FAIL(AMediaMuxer_writeSampleData(mMuxer, mMuxTrackID, buf, info),
332                            "AMediaMuxer_writeSampleData failed")
333         }
334         if ((info->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
335             mOutputBuff->saveOutPTS(info->presentationTimeUs);
336             mEncOutputCount++;
337         }
338     }
339     ALOGV("output: id: %zu  size: %d  pts: %" PRId64 "  flags: %d", bufferIndex, info->size,
340           info->presentationTimeUs, info->flags);
341     RETURN_IF_FAIL(AMediaCodec_releaseOutputBuffer(mEncoder, bufferIndex, false),
342                    "AMediaCodec_releaseOutputBuffer failed")
343     return !hasSeenError();
344 }
345 
tryEncoderOutput(long timeOutUs)346 bool CodecEncoderSurfaceTest::tryEncoderOutput(long timeOutUs) {
347     if (mIsCodecInAsyncMode) {
348         if (!hasSeenError() && !mSawEncOutputEOS) {
349             int retry = 0;
350             while (mReviseLatency) {
351                 if (mAsyncHandleEncoder.hasOutputFormatChanged()) {
352                     int actualLatency;
353                     mReviseLatency = false;
354                     if (AMediaFormat_getInt32(mAsyncHandleEncoder.getOutputFormat(),
355                                               AMEDIAFORMAT_KEY_LATENCY, &actualLatency)) {
356                         if (mLatency < actualLatency) {
357                             mLatency = actualLatency;
358                             return !hasSeenError();
359                         }
360                     }
361                 } else {
362                     if (retry > kRetryLimit) return false;
363                     usleep(kQDeQTimeOutUs);
364                     retry++;
365                 }
366             }
367             callbackObject element = mAsyncHandleEncoder.getOutput();
368             if (element.bufferIndex >= 0) {
369                 if (!dequeueEncoderOutput(element.bufferIndex, &element.bufferInfo)) return false;
370             }
371         }
372     } else {
373         AMediaCodecBufferInfo outInfo;
374         if (!mSawEncOutputEOS) {
375             int bufferID = AMediaCodec_dequeueOutputBuffer(mEncoder, &outInfo, timeOutUs);
376             if (bufferID >= 0) {
377                 if (!dequeueEncoderOutput(bufferID, &outInfo)) return false;
378             } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
379                 AMediaFormat* outFormat = AMediaCodec_getOutputFormat(mEncoder);
380                 AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_LATENCY, &mLatency);
381                 AMediaFormat_delete(outFormat);
382             } else if (bufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
383             } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
384             } else {
385                 mErrorLogs.append(
386                         StringFormat("unexpected return value from *_dequeueOutputBuffer: %d",
387                                      bufferID));
388                 return false;
389             }
390         }
391     }
392     return !hasSeenError();
393 }
394 
waitForAllEncoderOutputs()395 bool CodecEncoderSurfaceTest::waitForAllEncoderOutputs() {
396     if (mIsCodecInAsyncMode) {
397         while (!hasSeenError() && !mSawEncOutputEOS) {
398             if (!tryEncoderOutput(kQDeQTimeOutUs)) return false;
399         }
400     } else {
401         while (!mSawEncOutputEOS) {
402             if (!tryEncoderOutput(kQDeQTimeOutUs)) return false;
403         }
404     }
405     return !hasSeenError();
406 }
407 
queueEOS()408 bool CodecEncoderSurfaceTest::queueEOS() {
409     if (mIsCodecInAsyncMode) {
410         while (!hasSeenError() && !mSawDecInputEOS) {
411             callbackObject element = mAsyncHandleDecoder.getWork();
412             if (element.bufferIndex >= 0) {
413                 if (element.isInput) {
414                     if (!enqueueDecoderEOS(element.bufferIndex)) return false;
415                 } else {
416                     if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) {
417                         return false;
418                     }
419                 }
420             }
421         }
422     } else {
423         AMediaCodecBufferInfo outInfo;
424         while (!mSawDecInputEOS) {
425             ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
426             if (oBufferID >= 0) {
427                 if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
428             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
429             } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
430             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
431             } else {
432                 mErrorLogs.append(
433                         StringFormat("unexpected return value from *_dequeueOutputBuffer: %d",
434                                      oBufferID));
435                 return false;
436             }
437             ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mDecoder, kQDeQTimeOutUs);
438             if (iBufferId >= 0) {
439                 if (!enqueueDecoderEOS(iBufferId)) return false;
440             } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
441             } else {
442                 mErrorLogs.append(
443                         StringFormat("unexpected return value from *_dequeueInputBuffer: %zd",
444                                      iBufferId));
445                 return false;
446             }
447         }
448     }
449 
450     if (mIsCodecInAsyncMode) {
451         // output processing after queuing EOS is done in waitForAllOutputs()
452         while (!hasSeenError() && !mSawDecOutputEOS) {
453             callbackObject element = mAsyncHandleDecoder.getOutput();
454             if (element.bufferIndex >= 0) {
455                 if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) return false;
456             }
457             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
458             if (mDecOutputCount - mEncOutputCount > mLatency) {
459                 if (!tryEncoderOutput(-1)) return false;
460             }
461         }
462     } else {
463         AMediaCodecBufferInfo outInfo;
464         // output processing after queuing EOS is done in waitForAllOutputs()
465         while (!mSawDecOutputEOS) {
466             if (!mSawDecOutputEOS) {
467                 ssize_t oBufferID =
468                         AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
469                 if (oBufferID >= 0) {
470                     if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
471                 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
472                 } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
473                 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
474                 } else {
475                     mErrorLogs.append(
476                             StringFormat("unexpected return value from *_dequeueOutputBuffer: %d",
477                                          oBufferID));
478                     return false;
479                 }
480             }
481             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
482             if (mDecOutputCount - mEncOutputCount > mLatency) {
483                 if (!tryEncoderOutput(-1)) return false;
484             }
485         }
486     }
487     return !hasSeenError();
488 }
489 
doWork(int frameLimit)490 bool CodecEncoderSurfaceTest::doWork(int frameLimit) {
491     int frameCnt = 0;
492     if (mIsCodecInAsyncMode) {
493         // output processing after queuing EOS is done in waitForAllOutputs()
494         while (!hasSeenError() && !mSawDecInputEOS && frameCnt < frameLimit) {
495             callbackObject element = mAsyncHandleDecoder.getWork();
496             if (element.bufferIndex >= 0) {
497                 if (element.isInput) {
498                     if (!enqueueDecoderInput(element.bufferIndex)) return false;
499                     frameCnt++;
500                 } else {
501                     if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) {
502                         return false;
503                     }
504                 }
505             }
506             // check decoder EOS
507             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
508             // encoder output
509             if (mDecOutputCount - mEncOutputCount > mLatency) {
510                 if (!tryEncoderOutput(-1)) return false;
511             }
512         }
513     } else {
514         AMediaCodecBufferInfo outInfo;
515         // output processing after queuing EOS is done in waitForAllOutputs()
516         while (!mSawDecInputEOS && frameCnt < frameLimit) {
517             ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
518             if (oBufferID >= 0) {
519                 if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
520             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
521             } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
522             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
523             } else {
524                 mErrorLogs.append(
525                         StringFormat("unexpected return value from *_dequeueOutputBuffer: %zd",
526                                      oBufferID));
527                 return false;
528             }
529             ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mDecoder, kQDeQTimeOutUs);
530             if (iBufferId >= 0) {
531                 if (!enqueueDecoderInput(iBufferId)) return false;
532                 frameCnt++;
533             } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
534             } else {
535                 mErrorLogs.append(
536                         StringFormat("unexpected return value from *_dequeueInputBuffer: %zd",
537                                      iBufferId));
538                 return false;
539             }
540             if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
541             if (mDecOutputCount - mEncOutputCount > mLatency) {
542                 if (!tryEncoderOutput(-1)) return false;
543             }
544         }
545     }
546     return !hasSeenError();
547 }
548 
testSimpleEncode(const char * encoder,const char * decoder,const char * srcPath,const char * muxOutPath,int colorFormat,bool usePersistentSurface)549 bool CodecEncoderSurfaceTest::testSimpleEncode(const char* encoder, const char* decoder,
550                                                const char* srcPath, const char* muxOutPath,
551                                                int colorFormat, bool usePersistentSurface) {
552     RETURN_IF_FALSE(setUpExtractor(srcPath, colorFormat), std::string{"setUpExtractor failed"})
553     bool muxOutput = muxOutPath != nullptr;
554 
555     /* TODO(b/149027258) */
556     if (true) mSaveToMem = false;
557     else mSaveToMem = true;
558     auto ref = mRefBuff;
559     auto test = mTestBuff;
560     int loopCounter = 0;
561     const bool boolStates[]{true, false};
562     for (bool isAsync : boolStates) {
563         AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
564         mOutputBuff = loopCounter == 0 ? ref : test;
565         mOutputBuff->reset();
566 
567         /* TODO(b/147348711) */
568         /* Instead of create and delete codec at every iteration, we would like to create
569          * once and use it for all iterations and delete before exiting */
570         mEncoder = AMediaCodec_createCodecByName(encoder);
571         mDecoder = AMediaCodec_createCodecByName(decoder);
572         RETURN_IF_NULL(mDecoder, StringFormat("unable to create media codec by name %s", decoder))
573         RETURN_IF_NULL(mEncoder, StringFormat("unable to create media codec by name %s", encoder))
574         FILE* ofp = nullptr;
575         if (muxOutput && loopCounter == 0) {
576             int muxerFormat = 0;
577             if (!strcmp(mMediaType, AMEDIA_MIMETYPE_VIDEO_VP8) ||
578                 !strcmp(mMediaType, AMEDIA_MIMETYPE_VIDEO_VP9)) {
579                 muxerFormat = OUTPUT_FORMAT_WEBM;
580             } else {
581                 muxerFormat = OUTPUT_FORMAT_MPEG_4;
582             }
583             ofp = fopen(muxOutPath, "wbe+");
584             if (ofp) {
585                 mMuxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)muxerFormat);
586             }
587         }
588         if (!configureCodec(isAsync, false, usePersistentSurface)) return false;
589         RETURN_IF_FAIL(AMediaCodec_start(mEncoder), "Encoder AMediaCodec_start failed")
590         RETURN_IF_FAIL(AMediaCodec_start(mDecoder), "Decoder AMediaCodec_start failed")
591         if (!doWork(INT32_MAX)) return false;
592         if (!queueEOS()) return false;
593         if (!waitForAllEncoderOutputs()) return false;
594         if (muxOutput) {
595             if (mMuxer != nullptr) {
596                 RETURN_IF_FAIL(AMediaMuxer_stop(mMuxer), "AMediaMuxer_stop failed")
597                 mMuxTrackID = -1;
598                 RETURN_IF_FAIL(AMediaMuxer_delete(mMuxer), "AMediaMuxer_delete failed")
599                 mMuxer = nullptr;
600             }
601             if (ofp) fclose(ofp);
602         }
603         RETURN_IF_FAIL(AMediaCodec_stop(mDecoder), "AMediaCodec_stop failed for Decoder")
604         RETURN_IF_FAIL(AMediaCodec_stop(mEncoder), "AMediaCodec_stop failed for Encoder")
605         RETURN_IF_TRUE(mAsyncHandleDecoder.getError(),
606                        std::string{"Decoder has encountered error in async mode. \n"}.append(
607                                mAsyncHandleDecoder.getErrorMsg()))
608         RETURN_IF_TRUE(mAsyncHandleEncoder.getError(),
609                        std::string{"Encoder has encountered error in async mode. \n"}.append(
610                                mAsyncHandleEncoder.getErrorMsg()))
611         RETURN_IF_TRUE((0 == mDecInputCount), std::string{"Decoder has not received any input \n"})
612         RETURN_IF_TRUE((0 == mDecOutputCount), std::string{"Decoder has not sent any output \n"})
613         RETURN_IF_TRUE((0 == mEncOutputCount), std::string{"Encoder has not sent any output \n"})
614         RETURN_IF_TRUE((mDecInputCount != mDecOutputCount),
615                        StringFormat("Decoder output count is not equal to decoder input count\n "
616                                     "Input count : %s, Output count : %s\n",
617                                     mDecInputCount, mDecOutputCount))
618         /* TODO(b/153127506)
619          *  Currently disabling all encoder output checks. Added checks only for encoder timeStamp
620          *  is in increasing order or not.
621          *  Once issue is fixed remove increasing timestamp check and enable encoder checks.
622          */
623         /*RETURN_IF_TRUE((mEncOutputCount != mDecOutputCount),
624                        StringFormat("Encoder output count is not equal to decoder input count\n "
625                                     "Input count : %s, Output count : %s\n",
626                                     mDecInputCount, mEncOutputCount))
627         RETURN_IF_TRUE((loopCounter != 0 && !ref->equals(test)),
628                        std::string{"Encoder output is not consistent across runs \n"}.append(
629                                test->getErrorMsg()))
630         RETURN_IF_TRUE((loopCounter == 0 &&
631                         !mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0)),
632                        std::string{"Input pts list and Output pts list are not identical \n"}
633                                .append(ref->getErrorMsg()))*/
634         loopCounter++;
635         ANativeWindow_release(mWindow);
636         mWindow = nullptr;
637         RETURN_IF_FAIL(AMediaCodec_delete(mEncoder), "AMediaCodec_delete failed for encoder")
638         mEncoder = nullptr;
639         RETURN_IF_FAIL(AMediaCodec_delete(mDecoder), "AMediaCodec_delete failed for decoder")
640         mDecoder = nullptr;
641     }
642     return true;
643 }
644 
nativeTestSimpleEncode(JNIEnv * env,jobject,jstring jEncoder,jstring jDecoder,jstring jMediaType,jstring jtestFile,jstring jmuxFile,jint jColorFormat,jboolean jUsePersistentSurface,jstring jCfgParams,jstring jSeparator,jobject jRetMsg)645 static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jDecoder,
646                                        jstring jMediaType, jstring jtestFile, jstring jmuxFile,
647                                        jint jColorFormat, jboolean jUsePersistentSurface,
648                                        jstring jCfgParams, jstring jSeparator, jobject jRetMsg) {
649     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
650     const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
651     const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
652     const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
653     const char* cMuxFile = jmuxFile ? env->GetStringUTFChars(jmuxFile, nullptr) : nullptr;
654     const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
655     const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
656     auto codecEncoderSurfaceTest = new CodecEncoderSurfaceTest(cMediaType, cCfgParams, cSeparator);
657     bool isPass = codecEncoderSurfaceTest->testSimpleEncode(cEncoder, cDecoder, cTestFile, cMuxFile,
658                                                             jColorFormat, jUsePersistentSurface);
659     std::string msg = isPass ? std::string{} : codecEncoderSurfaceTest->getErrorMsg();
660     delete codecEncoderSurfaceTest;
661     jclass clazz = env->GetObjectClass(jRetMsg);
662     jmethodID mId =
663             env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
664     env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
665     env->ReleaseStringUTFChars(jEncoder, cEncoder);
666     env->ReleaseStringUTFChars(jDecoder, cDecoder);
667     env->ReleaseStringUTFChars(jMediaType, cMediaType);
668     env->ReleaseStringUTFChars(jtestFile, cTestFile);
669     if (cMuxFile) env->ReleaseStringUTFChars(jmuxFile, cMuxFile);
670     env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
671     env->ReleaseStringUTFChars(jSeparator, cSeparator);
672 
673     return isPass;
674 }
675 
registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv * env)676 int registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv* env) {
677     const JNINativeMethod methodTable[] = {
678             {"nativeTestSimpleEncode",
679              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;"
680              "Ljava/lang/String;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/StringBuilder;)Z",
681              (void*)nativeTestSimpleEncode},
682     };
683     jclass c = env->FindClass("android/mediav2/cts/CodecEncoderSurfaceTest");
684     return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
685 }
686 
JNI_OnLoad(JavaVM * vm,void *)687 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
688     JNIEnv* env;
689     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
690     if (registerAndroidMediaV2CtsEncoderSurfaceTest(env) != JNI_OK) return JNI_ERR;
691     return JNI_VERSION_1_6;
692 }
693