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