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