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 package android.mediav2.cts; 18 19 import android.media.MediaCodec; 20 import android.media.MediaCodecInfo; 21 import android.media.MediaCodecList; 22 import android.media.MediaExtractor; 23 import android.media.MediaFormat; 24 import android.media.MediaMuxer; 25 import android.os.Build; 26 import android.util.Log; 27 import android.util.Pair; 28 import android.view.Surface; 29 30 import androidx.test.filters.LargeTest; 31 import androidx.test.platform.app.InstrumentationRegistry; 32 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.junit.runners.Parameterized; 36 37 import java.io.File; 38 import java.io.IOException; 39 import java.nio.ByteBuffer; 40 import java.util.ArrayList; 41 import java.util.Collection; 42 import java.util.List; 43 import java.util.Map; 44 45 import static org.junit.Assert.assertFalse; 46 import static org.junit.Assert.assertTrue; 47 import static org.junit.Assert.fail; 48 49 @RunWith(Parameterized.class) 50 public class CodecEncoderSurfaceTest { 51 private static final String LOG_TAG = CodecEncoderSurfaceTest.class.getSimpleName(); 52 private static final String mInpPrefix = WorkDir.getMediaDirString(); 53 private static final boolean ENABLE_LOGS = false; 54 55 private final String mMime; 56 private final String mTestFile; 57 private final int mBitrate; 58 private final int mFrameRate; 59 private final int mMaxBFrames; 60 61 private MediaExtractor mExtractor; 62 private MediaCodec mEncoder; 63 private CodecAsyncHandler mAsyncHandleEncoder; 64 private MediaCodec mDecoder; 65 private CodecAsyncHandler mAsyncHandleDecoder; 66 private boolean mIsCodecInAsyncMode; 67 private boolean mSignalEOSWithLastFrame; 68 private boolean mSawDecInputEOS; 69 private boolean mSawDecOutputEOS; 70 private boolean mSawEncOutputEOS; 71 private int mDecInputCount; 72 private int mDecOutputCount; 73 private int mEncOutputCount; 74 75 private boolean mSaveToMem; 76 private OutputManager mOutputBuff; 77 78 private Surface mSurface; 79 80 private MediaMuxer mMuxer; 81 private int mTrackID = -1; 82 83 static { 84 android.os.Bundle args = InstrumentationRegistry.getArguments(); 85 CodecTestBase.codecSelKeys = args.getString(CodecTestBase.CODEC_SEL_KEY); 86 if (CodecTestBase.codecSelKeys == null) 87 CodecTestBase.codecSelKeys = CodecTestBase.CODEC_SEL_VALUE; 88 } 89 CodecEncoderSurfaceTest(String mime, String testFile, int bitrate, int frameRate)90 public CodecEncoderSurfaceTest(String mime, String testFile, int bitrate, int frameRate) { 91 mMime = mime; 92 mTestFile = testFile; 93 mBitrate = bitrate; 94 mFrameRate = frameRate; 95 mMaxBFrames = 0; 96 mAsyncHandleDecoder = new CodecAsyncHandler(); 97 mAsyncHandleEncoder = new CodecAsyncHandler(); 98 } 99 100 @Parameterized.Parameters(name = "{index}({0})") input()101 public static Collection<Object[]> input() { 102 ArrayList<String> cddRequiredMimeList = new ArrayList<>(); 103 if (CodecTestBase.isHandheld() || CodecTestBase.isTv() || CodecTestBase.isAutomotive()) { 104 // sec 2.2.2, 2.3.2, 2.5.2 105 cddRequiredMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC); 106 cddRequiredMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP8); 107 } 108 final Object[][] exhaustiveArgsList = new Object[][]{ 109 // Video - CodecMime, test file, bit rate, frame rate 110 {MediaFormat.MIMETYPE_VIDEO_H263, "bbb_176x144_128kbps_15fps_h263.3gp", 128000, 15}, 111 {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4", 64000, 12}, 112 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_cif_768kbps_30fps_avc.mp4", 512000, 30}, 113 {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_cif_768kbps_30fps_avc.mp4", 512000, 30}, 114 {MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_cif_768kbps_30fps_avc.mp4", 512000, 30}, 115 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_cif_768kbps_30fps_avc.mp4", 512000, 30}, 116 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_cif_768kbps_30fps_avc.mp4", 512000, 30}, 117 }; 118 ArrayList<String> mimes = new ArrayList<>(); 119 if (CodecTestBase.codecSelKeys.contains(CodecTestBase.CODEC_SEL_VALUE)) { 120 MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 121 MediaCodecInfo[] codecInfos = codecList.getCodecInfos(); 122 for (MediaCodecInfo codecInfo : codecInfos) { 123 if (!codecInfo.isEncoder()) continue; 124 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue; 125 String[] types = codecInfo.getSupportedTypes(); 126 for (String type : types) { 127 if (!mimes.contains(type) && type.startsWith("video/")) { 128 mimes.add(type); 129 } 130 } 131 } 132 // TODO(b/154423708): add checks for video o/p port and display length >= 2.5" 133 /* sec 5.2: device implementations include an embedded screen display with the diagonal 134 length of at least 2.5inches or include a video output port or declare the support of a 135 camera */ 136 if (CodecTestBase.hasCamera() && !mimes.contains(MediaFormat.MIMETYPE_VIDEO_AVC) && 137 !mimes.contains(MediaFormat.MIMETYPE_VIDEO_VP8)) { 138 fail("device must support at least one of VP8 or AVC video encoders"); 139 } 140 for (String mime : cddRequiredMimeList) { 141 if (!mimes.contains(mime)) { 142 fail("no codec found for mime " + mime + " as required by cdd"); 143 } 144 } 145 } else { 146 for (Map.Entry<String, String> entry : CodecTestBase.codecSelKeyMimeMap.entrySet()) { 147 String key = entry.getKey(); 148 String value = entry.getValue(); 149 if (CodecTestBase.codecSelKeys.contains(key) && !mimes.contains(value)) { 150 mimes.add(value); 151 } 152 } 153 } 154 final List<Object[]> argsList = new ArrayList<>(); 155 for (String mime : mimes) { 156 boolean miss = true; 157 for (Object[] arg : exhaustiveArgsList) { 158 if (mime.equals(arg[0])) { 159 argsList.add(arg); 160 miss = false; 161 } 162 } 163 if (miss) { 164 if (cddRequiredMimeList.contains(mime)) { 165 fail("no test vectors for required mimetype " + mime); 166 } 167 Log.w(LOG_TAG, "no test vectors available for optional mime type " + mime); 168 } 169 } 170 return argsList; 171 } 172 hasSeenError()173 private boolean hasSeenError() { 174 return mAsyncHandleDecoder.hasSeenError() || mAsyncHandleEncoder.hasSeenError(); 175 } 176 setUpSource(String srcFile)177 private MediaFormat setUpSource(String srcFile) throws IOException { 178 mExtractor = new MediaExtractor(); 179 mExtractor.setDataSource(mInpPrefix + srcFile); 180 for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) { 181 MediaFormat format = mExtractor.getTrackFormat(trackID); 182 String mime = format.getString(MediaFormat.KEY_MIME); 183 if (mime.startsWith("video/")) { 184 mExtractor.selectTrack(trackID); 185 // COLOR_FormatYUV420Flexible by default should be supported by all components 186 // This call shouldn't effect configure() call for any codec 187 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 188 MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible); 189 return format; 190 } 191 } 192 mExtractor.release(); 193 fail("No video track found in file: " + srcFile); 194 return null; 195 } 196 resetContext(boolean isAsync, boolean signalEOSWithLastFrame)197 private void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) { 198 mAsyncHandleDecoder.resetContext(); 199 mAsyncHandleEncoder.resetContext(); 200 mIsCodecInAsyncMode = isAsync; 201 mSignalEOSWithLastFrame = signalEOSWithLastFrame; 202 mSawDecInputEOS = false; 203 mSawDecOutputEOS = false; 204 mSawEncOutputEOS = false; 205 mDecInputCount = 0; 206 mDecOutputCount = 0; 207 mEncOutputCount = 0; 208 } 209 configureCodec(MediaFormat decFormat, MediaFormat encFormat, boolean isAsync, boolean signalEOSWithLastFrame)210 private void configureCodec(MediaFormat decFormat, MediaFormat encFormat, boolean isAsync, 211 boolean signalEOSWithLastFrame) { 212 resetContext(isAsync, signalEOSWithLastFrame); 213 mAsyncHandleEncoder.setCallBack(mEncoder, isAsync); 214 mEncoder.configure(encFormat, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null); 215 mSurface = mEncoder.createInputSurface(); 216 assertTrue("Surface is not valid", mSurface.isValid()); 217 mAsyncHandleDecoder.setCallBack(mDecoder, isAsync); 218 mDecoder.configure(decFormat, mSurface, null, 0); 219 if (ENABLE_LOGS) { 220 Log.v(LOG_TAG, "codec configured"); 221 } 222 } 223 enqueueDecoderEOS(int bufferIndex)224 private void enqueueDecoderEOS(int bufferIndex) { 225 if (!mSawDecInputEOS) { 226 mDecoder.queueInputBuffer(bufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 227 mSawDecInputEOS = true; 228 if (ENABLE_LOGS) { 229 Log.v(LOG_TAG, "Queued End of Stream"); 230 } 231 } 232 } 233 enqueueDecoderInput(int bufferIndex)234 private void enqueueDecoderInput(int bufferIndex) { 235 if (mExtractor.getSampleSize() < 0) { 236 enqueueDecoderEOS(bufferIndex); 237 } else { 238 ByteBuffer inputBuffer = mDecoder.getInputBuffer(bufferIndex); 239 mExtractor.readSampleData(inputBuffer, 0); 240 int size = (int) mExtractor.getSampleSize(); 241 long pts = mExtractor.getSampleTime(); 242 int extractorFlags = mExtractor.getSampleFlags(); 243 int codecFlags = 0; 244 if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { 245 codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME; 246 } 247 if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) { 248 codecFlags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME; 249 } 250 if (!mExtractor.advance() && mSignalEOSWithLastFrame) { 251 codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM; 252 mSawDecInputEOS = true; 253 } 254 if (ENABLE_LOGS) { 255 Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts + 256 " flags: " + codecFlags); 257 } 258 mDecoder.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags); 259 if (size > 0 && (codecFlags & (MediaCodec.BUFFER_FLAG_CODEC_CONFIG | 260 MediaCodec.BUFFER_FLAG_PARTIAL_FRAME)) == 0) { 261 mOutputBuff.saveInPTS(pts); 262 mDecInputCount++; 263 } 264 } 265 } 266 dequeueDecoderOutput(int bufferIndex, MediaCodec.BufferInfo info)267 private void dequeueDecoderOutput(int bufferIndex, MediaCodec.BufferInfo info) { 268 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 269 mSawDecOutputEOS = true; 270 } 271 if (ENABLE_LOGS) { 272 Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " + 273 info.size + " timestamp: " + info.presentationTimeUs); 274 } 275 if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 276 mDecOutputCount++; 277 } 278 mDecoder.releaseOutputBuffer(bufferIndex, mSurface != null); 279 } 280 dequeueEncoderOutput(int bufferIndex, MediaCodec.BufferInfo info)281 private void dequeueEncoderOutput(int bufferIndex, MediaCodec.BufferInfo info) { 282 if (ENABLE_LOGS) { 283 Log.v(LOG_TAG, "encoder output: id: " + bufferIndex + " flags: " + info.flags + 284 " size: " + info.size + " timestamp: " + info.presentationTimeUs); 285 } 286 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 287 mSawEncOutputEOS = true; 288 } 289 if (info.size > 0) { 290 ByteBuffer buf = mEncoder.getOutputBuffer(bufferIndex); 291 if (mSaveToMem) { 292 mOutputBuff.saveToMemory(buf, info); 293 } 294 if (mMuxer != null) { 295 if (mTrackID == -1) { 296 mTrackID = mMuxer.addTrack(mEncoder.getOutputFormat()); 297 mMuxer.start(); 298 } 299 mMuxer.writeSampleData(mTrackID, buf, info); 300 } 301 if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 302 mOutputBuff.saveOutPTS(info.presentationTimeUs); 303 mEncOutputCount++; 304 } 305 } 306 mEncoder.releaseOutputBuffer(bufferIndex, false); 307 } 308 tryEncoderOutput(long timeOutUs)309 private void tryEncoderOutput(long timeOutUs) throws InterruptedException { 310 if (mIsCodecInAsyncMode) { 311 if (!hasSeenError() && !mSawEncOutputEOS) { 312 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleEncoder.getOutput(); 313 if (element != null) { 314 dequeueEncoderOutput(element.first, element.second); 315 } 316 } 317 } else { 318 MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo(); 319 if (!mSawEncOutputEOS) { 320 int outputBufferId = mEncoder.dequeueOutputBuffer(outInfo, timeOutUs); 321 if (outputBufferId >= 0) { 322 dequeueEncoderOutput(outputBufferId, outInfo); 323 } 324 } 325 } 326 } 327 waitForAllEncoderOutputs()328 private void waitForAllEncoderOutputs() throws InterruptedException { 329 if (mIsCodecInAsyncMode) { 330 while (!hasSeenError() && !mSawEncOutputEOS) { 331 tryEncoderOutput(CodecTestBase.Q_DEQ_TIMEOUT_US); 332 } 333 } else { 334 while (!mSawEncOutputEOS) { 335 tryEncoderOutput(CodecTestBase.Q_DEQ_TIMEOUT_US); 336 } 337 } 338 } 339 queueEOS()340 private void queueEOS() throws InterruptedException { 341 if (mIsCodecInAsyncMode) { 342 while (!mAsyncHandleDecoder.hasSeenError() && !mSawDecInputEOS) { 343 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork(); 344 if (element != null) { 345 int bufferID = element.first; 346 MediaCodec.BufferInfo info = element.second; 347 if (info != null) { 348 dequeueDecoderOutput(bufferID, info); 349 } else { 350 enqueueDecoderEOS(element.first); 351 } 352 } 353 } 354 } else if (!mSawDecInputEOS) { 355 enqueueDecoderEOS(mDecoder.dequeueInputBuffer(-1)); 356 } 357 if (mIsCodecInAsyncMode) { 358 while (!hasSeenError() && !mSawDecOutputEOS) { 359 Pair<Integer, MediaCodec.BufferInfo> decOp = mAsyncHandleDecoder.getOutput(); 360 if (decOp != null) dequeueDecoderOutput(decOp.first, decOp.second); 361 if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream(); 362 // TODO: remove fixed constant and change it according to encoder latency 363 if (mDecOutputCount - mEncOutputCount > mMaxBFrames) { 364 tryEncoderOutput(-1); 365 } 366 } 367 } else { 368 MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo(); 369 while (!mSawDecOutputEOS) { 370 int outputBufferId = 371 mDecoder.dequeueOutputBuffer(outInfo, CodecTestBase.Q_DEQ_TIMEOUT_US); 372 if (outputBufferId >= 0) { 373 dequeueDecoderOutput(outputBufferId, outInfo); 374 } 375 if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream(); 376 // TODO: remove fixed constant and change it according to encoder latency 377 if (mDecOutputCount - mEncOutputCount > mMaxBFrames) { 378 tryEncoderOutput(-1); 379 } 380 } 381 } 382 } 383 doWork(int frameLimit)384 private void doWork(int frameLimit) throws InterruptedException { 385 int frameCnt = 0; 386 if (mIsCodecInAsyncMode) { 387 // dequeue output after inputEOS is expected to be done in waitForAllOutputs() 388 while (!hasSeenError() && !mSawDecInputEOS && frameCnt < frameLimit) { 389 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork(); 390 if (element != null) { 391 int bufferID = element.first; 392 MediaCodec.BufferInfo info = element.second; 393 if (info != null) { 394 // <id, info> corresponds to output callback. Handle it accordingly 395 dequeueDecoderOutput(bufferID, info); 396 } else { 397 // <id, null> corresponds to input callback. Handle it accordingly 398 enqueueDecoderInput(bufferID); 399 frameCnt++; 400 } 401 } 402 // check decoder EOS 403 if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream(); 404 // encoder output 405 // TODO: remove fixed constant and change it according to encoder latency 406 if (mDecOutputCount - mEncOutputCount > mMaxBFrames) { 407 tryEncoderOutput(-1); 408 } 409 } 410 } else { 411 MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo(); 412 while (!mSawDecInputEOS && frameCnt < frameLimit) { 413 // decoder input 414 int inputBufferId = mDecoder.dequeueInputBuffer(CodecTestBase.Q_DEQ_TIMEOUT_US); 415 if (inputBufferId != -1) { 416 enqueueDecoderInput(inputBufferId); 417 frameCnt++; 418 } 419 // decoder output 420 int outputBufferId = 421 mDecoder.dequeueOutputBuffer(outInfo, CodecTestBase.Q_DEQ_TIMEOUT_US); 422 if (outputBufferId >= 0) { 423 dequeueDecoderOutput(outputBufferId, outInfo); 424 } 425 // check decoder EOS 426 if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream(); 427 // encoder output 428 // TODO: remove fixed constant and change it according to encoder latency 429 if (mDecOutputCount - mEncOutputCount > mMaxBFrames) { 430 tryEncoderOutput(-1); 431 } 432 } 433 } 434 } 435 setUpEncoderFormat(MediaFormat decoderFormat)436 private MediaFormat setUpEncoderFormat(MediaFormat decoderFormat) { 437 MediaFormat encoderFormat = new MediaFormat(); 438 encoderFormat.setString(MediaFormat.KEY_MIME, mMime); 439 encoderFormat.setInteger(MediaFormat.KEY_WIDTH, 440 decoderFormat.getInteger(MediaFormat.KEY_WIDTH)); 441 encoderFormat.setInteger(MediaFormat.KEY_HEIGHT, 442 decoderFormat.getInteger(MediaFormat.KEY_HEIGHT)); 443 encoderFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate); 444 encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, mBitrate); 445 encoderFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f); 446 encoderFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 447 MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); 448 encoderFormat.setInteger(MediaFormat.KEY_MAX_B_FRAMES, mMaxBFrames); 449 return encoderFormat; 450 } 451 452 /** 453 * Tests listed encoder components for sync and async mode in surface mode.The output has to 454 * be consistent (not flaky) in all runs. 455 */ 456 @LargeTest 457 @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS) testSimpleEncodeFromSurface()458 public void testSimpleEncodeFromSurface() throws IOException, InterruptedException { 459 MediaFormat decoderFormat = setUpSource(mTestFile); 460 MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 461 String decoder = codecList.findDecoderForFormat(decoderFormat); 462 if (decoder == null) { 463 mExtractor.release(); 464 fail("no suitable decoder found for format: " + decoderFormat.toString()); 465 } 466 mDecoder = MediaCodec.createByCodecName(decoder); 467 MediaFormat encoderFormat = setUpEncoderFormat(decoderFormat); 468 ArrayList<String> listOfEncoders = CodecTestBase.selectCodecs(mMime, null, null, true); 469 assertFalse("no suitable codecs found for mime: " + mMime, listOfEncoders.isEmpty()); 470 boolean muxOutput = true; 471 for (String encoder : listOfEncoders) { 472 mEncoder = MediaCodec.createByCodecName(encoder); 473 /* TODO(b/149027258) */ 474 mSaveToMem = false; 475 OutputManager ref = new OutputManager(); 476 OutputManager test = new OutputManager(); 477 int loopCounter = 0; 478 boolean[] boolStates = {true, false}; 479 for (boolean isAsync : boolStates) { 480 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 481 mOutputBuff = loopCounter == 0 ? ref : test; 482 mOutputBuff.reset(); 483 if (muxOutput && loopCounter == 0) { 484 String tmpPath; 485 int muxerFormat; 486 if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) || 487 mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) { 488 muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM; 489 tmpPath = File.createTempFile("tmp", ".webm").getAbsolutePath(); 490 } else { 491 muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4; 492 tmpPath = File.createTempFile("tmp", ".mp4").getAbsolutePath(); 493 } 494 mMuxer = new MediaMuxer(tmpPath, muxerFormat); 495 } 496 configureCodec(decoderFormat, encoderFormat, isAsync, false); 497 mEncoder.start(); 498 mDecoder.start(); 499 doWork(Integer.MAX_VALUE); 500 queueEOS(); 501 waitForAllEncoderOutputs(); 502 if (muxOutput) { 503 if (mTrackID != -1) { 504 mMuxer.stop(); 505 mTrackID = -1; 506 } 507 if (mMuxer != null) { 508 mMuxer.release(); 509 mMuxer = null; 510 } 511 } 512 /* TODO(b/147348711) */ 513 if (false) mDecoder.stop(); 514 else mDecoder.reset(); 515 /* TODO(b/147348711) */ 516 if (false) mEncoder.stop(); 517 else mEncoder.reset(); 518 String log = String.format( 519 "format: %s \n codec: %s, file: %s, mode: %s:: ", 520 encoderFormat, encoder, mTestFile, (isAsync ? "async" : "sync")); 521 assertTrue(log + " unexpected error", !hasSeenError()); 522 assertTrue(log + "no input sent", 0 != mDecInputCount); 523 assertTrue(log + "no decoder output received", 0 != mDecOutputCount); 524 assertTrue(log + "no encoder output received", 0 != mEncOutputCount); 525 assertTrue(log + "decoder input count != output count, act/exp: " + 526 mDecOutputCount + 527 " / " + mDecInputCount, mDecInputCount == mDecOutputCount); 528 /* TODO(b/153127506) 529 * Currently disabling all encoder output checks. Added checks only for encoder 530 * timeStamp is in increasing order or not. 531 * Once issue is fixed remove increasing timestamp check and enable encoder checks. 532 */ 533 /*assertTrue(log + "encoder output count != decoder output count, act/exp: " + 534 mEncOutputCount + " / " + mDecOutputCount, 535 mEncOutputCount == mDecOutputCount); 536 if (loopCounter != 0) { 537 assertTrue(log + "encoder output is flaky", ref.equals(test)); 538 } else { 539 assertTrue(log + " input pts list and output pts list are not identical", 540 ref.isOutPtsListIdenticalToInpPtsList((false))); 541 }*/ 542 if (loopCounter != 0) { 543 assertTrue("test output pts is not strictly increasing", 544 test.isPtsStrictlyIncreasing(Long.MIN_VALUE)); 545 } else { 546 assertTrue("ref output pts is not strictly increasing", 547 ref.isPtsStrictlyIncreasing(Long.MIN_VALUE)); 548 } 549 loopCounter++; 550 mSurface.release(); 551 mSurface = null; 552 } 553 mEncoder.release(); 554 } 555 mDecoder.release(); 556 mExtractor.release(); 557 } 558 nativeTestSimpleEncode(String encoder, String decoder, String mime, String testFile, String muxFile, int bitrate, int framerate)559 private native boolean nativeTestSimpleEncode(String encoder, String decoder, String mime, 560 String testFile, String muxFile, int bitrate, int framerate); 561 562 @LargeTest 563 @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS) testSimpleEncodeFromSurfaceNative()564 public void testSimpleEncodeFromSurfaceNative() throws IOException { 565 MediaFormat decoderFormat = setUpSource(mTestFile); 566 MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 567 String decoder = codecList.findDecoderForFormat(decoderFormat); 568 if (decoder == null) { 569 mExtractor.release(); 570 fail("no suitable decoder found for format: " + decoderFormat.toString()); 571 } 572 ArrayList<String> listOfEncoders = CodecTestBase.selectCodecs(mMime, null, null, true); 573 assertFalse("no suitable codecs found for mime: " + mMime, listOfEncoders.isEmpty()); 574 for (String encoder : listOfEncoders) { 575 String tmpPath = null; 576 if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) || 577 mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) { 578 tmpPath = File.createTempFile("tmp", ".webm").getAbsolutePath(); 579 } else { 580 tmpPath = File.createTempFile("tmp", ".mp4").getAbsolutePath(); 581 } 582 assertTrue( 583 nativeTestSimpleEncode(encoder, decoder, mMime, mInpPrefix + mTestFile, tmpPath, 584 mBitrate, mFrameRate)); 585 } 586 } 587 } 588 589