1 /* 2 * Copyright (C) 2019 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 static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible; 20 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar; 21 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar; 22 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar; 23 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_ALL; 24 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_OPTIONAL; 25 26 import static org.junit.Assert.assertEquals; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assert.fail; 29 30 import android.media.AudioFormat; 31 import android.media.MediaCodec; 32 import android.media.MediaCodecInfo; 33 import android.media.MediaExtractor; 34 import android.media.MediaFormat; 35 import android.mediav2.common.cts.CodecDecoderBlockModelTestBase; 36 import android.mediav2.common.cts.CodecDecoderTestBase; 37 import android.mediav2.common.cts.OutputManager; 38 import android.util.Log; 39 import android.view.Surface; 40 41 import androidx.test.filters.LargeTest; 42 import androidx.test.filters.SmallTest; 43 44 import com.android.compatibility.common.util.ApiTest; 45 import com.android.compatibility.common.util.CddTest; 46 import com.android.compatibility.common.util.Preconditions; 47 48 import org.junit.Assume; 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.junit.runners.Parameterized; 53 54 import java.io.File; 55 import java.io.FileInputStream; 56 import java.io.IOException; 57 import java.nio.ByteBuffer; 58 import java.nio.ByteOrder; 59 import java.nio.channels.FileChannel; 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.Collection; 63 import java.util.List; 64 import java.util.stream.IntStream; 65 66 /** 67 * Test mediacodec api, decoders and their interactions in byte buffer mode 68 * <p> 69 * The test decodes a compressed frame and stores the result in ByteBuffer. This allows 70 * validating the decoded output. Hence wherever possible we check if the decoded output is 71 * compliant. 72 * <ul> 73 * <li>For Avc, Hevc, Vpx and Av1, the test expects the decoded output to be identical to 74 * reference decoded output. The reference decoded output is represented by its CRC32 75 * checksum and is sent to the test as a parameter along with the test clip.</li> 76 * <li>For others codecs (mpeg2, mpeg4, h263, ...) the decoded output is checked for 77 * consistency (doesn't change across runs). No crc32 verification is done because idct for 78 * these standards are non-normative.</li> 79 * <li>For lossless audio media types, the test verifies if the rms error between input and 80 * output is 0.</li> 81 * <li>For lossy audio media types, the test verifies if the rms error is within 5% of 82 * reference rms error. The reference value is computed using reference decoder and is sent 83 * to the test as a parameter along with the test clip.</li> 84 * <li>For all video components, the test expects the output timestamp list to be identical to 85 * input timestamp list.</li> 86 * <li>For all audio components, the test expects the output timestamps to be strictly 87 * increasing.</li> 88 * <li>The test also verifies if the component reports a format change if the test clip does 89 * not use the default format.</li> 90 * </ul> 91 * <p> 92 * The test runs mediacodec in synchronous and asynchronous mode. 93 */ 94 @RunWith(Parameterized.class) 95 public class CodecDecoderTest extends CodecDecoderTestBase { 96 private static final String LOG_TAG = CodecDecoderTest.class.getSimpleName(); 97 private static final float RMS_ERROR_TOLERANCE = 1.05f; // 5% 98 private static final String MEDIA_DIR = WorkDir.getMediaDirString(); 99 100 private final String mRefFile; 101 private final String mReconfigFile; 102 private final float mRmsError; 103 private final long mRefCRC; 104 private final SupportClass mSupportRequirements; 105 106 static { 107 System.loadLibrary("ctsmediav2codecdec_jni"); 108 } 109 CodecDecoderTest(String decoder, String mediaType, String testFile, String refFile, String reconfigFile, float rmsError, long refCRC, SupportClass supportRequirements, String allTestParams)110 public CodecDecoderTest(String decoder, String mediaType, String testFile, String refFile, 111 String reconfigFile, float rmsError, long refCRC, SupportClass supportRequirements, 112 String allTestParams) { 113 super(decoder, mediaType, MEDIA_DIR + testFile, allTestParams); 114 mRefFile = MEDIA_DIR + refFile; 115 mReconfigFile = MEDIA_DIR + reconfigFile; 116 mRmsError = rmsError; 117 mRefCRC = refCRC; 118 mSupportRequirements = supportRequirements; 119 } 120 readAudioReferenceFile(String file)121 static ByteBuffer readAudioReferenceFile(String file) throws IOException { 122 Preconditions.assertTestFileExists(file); 123 File refFile = new File(file); 124 ByteBuffer refBuffer; 125 try (FileInputStream refStream = new FileInputStream(refFile)) { 126 FileChannel fileChannel = refStream.getChannel(); 127 int length = (int) refFile.length(); 128 refBuffer = ByteBuffer.allocate(length); 129 refBuffer.order(ByteOrder.LITTLE_ENDIAN); 130 fileChannel.read(refBuffer); 131 } 132 return refBuffer; 133 } 134 createSubFrames(ByteBuffer buffer, int sfCount)135 private ArrayList<MediaCodec.BufferInfo> createSubFrames(ByteBuffer buffer, int sfCount) { 136 int size = (int) mExtractor.getSampleSize(); 137 if (size < 0) return null; 138 mExtractor.readSampleData(buffer, 0); 139 long pts = mExtractor.getSampleTime(); 140 int flags = mExtractor.getSampleFlags(); 141 if (size < sfCount) sfCount = size; 142 ArrayList<MediaCodec.BufferInfo> list = new ArrayList<>(); 143 int offset = 0; 144 for (int i = 0; i < sfCount; i++) { 145 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 146 info.offset = offset; 147 info.presentationTimeUs = pts; 148 info.flags = 0; 149 if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { 150 info.flags |= MediaCodec.BUFFER_FLAG_KEY_FRAME; 151 } 152 if ((flags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) { 153 info.flags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME; 154 } 155 if (i != sfCount - 1) { 156 info.size = size / sfCount; 157 info.flags |= MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME; 158 } else { 159 info.size = size - offset; 160 } 161 list.add(info); 162 offset += info.size; 163 } 164 return list; 165 } 166 167 @Parameterized.Parameters(name = "{index}_{0}_{1}") input()168 public static Collection<Object[]> input() { 169 final boolean isEncoder = false; 170 final boolean needAudio = true; 171 final boolean needVideo = true; 172 // mediaType, testClip, referenceClip, reconfigureTestClip, refRmsError, refCRC32, 173 // SupportClass 174 final List<Object[]> exhaustiveArgsList = new ArrayList<>(Arrays.asList(new Object[][]{ 175 {MediaFormat.MIMETYPE_AUDIO_MPEG, "bbb_1ch_8kHz_lame_cbr.mp3", 176 "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_44kHz_lame_vbr.mp3", 91.026749f, -1L, 177 CODEC_ALL}, 178 {MediaFormat.MIMETYPE_AUDIO_MPEG, "bbb_2ch_44kHz_lame_cbr.mp3", 179 "bbb_2ch_44kHz_s16le.raw", "bbb_1ch_16kHz_lame_vbr.mp3", 103.603081f, -1L, 180 CODEC_ALL}, 181 {MediaFormat.MIMETYPE_AUDIO_AMR_WB, "bbb_1ch_16kHz_16kbps_amrwb.3gp", 182 "bbb_1ch_16kHz_s16le.raw", "bbb_1ch_16kHz_23kbps_amrwb.3gp", 2393.5979f, 183 -1L, CODEC_ALL}, 184 {MediaFormat.MIMETYPE_AUDIO_AMR_NB, "bbb_1ch_8kHz_10kbps_amrnb.3gp", 185 "bbb_1ch_8kHz_s16le.raw", "bbb_1ch_8kHz_8kbps_amrnb.3gp", -1.0f, -1L, 186 CODEC_ALL}, 187 {MediaFormat.MIMETYPE_AUDIO_FLAC, "bbb_1ch_16kHz_flac.mka", 188 "bbb_1ch_16kHz_s16le.raw", "bbb_2ch_44kHz_flac.mka", 0.0f, -1L, CODEC_ALL}, 189 {MediaFormat.MIMETYPE_AUDIO_FLAC, "bbb_2ch_44kHz_flac.mka", 190 "bbb_2ch_44kHz_s16le.raw", "bbb_1ch_16kHz_flac.mka", 0.0f, -1L, CODEC_ALL}, 191 {MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_1ch_16kHz.wav", "bbb_1ch_16kHz_s16le.raw", 192 "bbb_2ch_44kHz.wav", 0.0f, -1L, CODEC_ALL}, 193 {MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_2ch_44kHz.wav", "bbb_2ch_44kHz_s16le.raw", 194 "bbb_1ch_16kHz.wav", 0.0f, -1L, CODEC_ALL}, 195 {MediaFormat.MIMETYPE_AUDIO_G711_ALAW, "bbb_1ch_8kHz_alaw.wav", 196 "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_8kHz_alaw.wav", 23.087402f, -1L, 197 CODEC_ALL}, 198 {MediaFormat.MIMETYPE_AUDIO_G711_MLAW, "bbb_1ch_8kHz_mulaw.wav", 199 "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_8kHz_mulaw.wav", 24.413954f, -1L, 200 CODEC_ALL}, 201 {MediaFormat.MIMETYPE_AUDIO_MSGSM, "bbb_1ch_8kHz_gsm.wav", 202 "bbb_1ch_8kHz_s16le.raw", "bbb_1ch_8kHz_gsm.wav", 946.026978f, -1L, 203 CODEC_ALL}, 204 {MediaFormat.MIMETYPE_AUDIO_VORBIS, "bbb_1ch_16kHz_vorbis.mka", 205 "bbb_1ch_8kHz_s16le.raw", "bbb_2ch_44kHz_vorbis.mka", -1.0f, -1L, 206 CODEC_ALL}, 207 {MediaFormat.MIMETYPE_AUDIO_OPUS, "bbb_2ch_48kHz_opus.mka", 208 "bbb_2ch_48kHz_s16le.raw", "bbb_1ch_48kHz_opus.mka", -1.0f, -1L, CODEC_ALL}, 209 {MediaFormat.MIMETYPE_AUDIO_AAC, "bbb_1ch_16kHz_aac.mp4", 210 "bbb_1ch_16kHz_s16le.raw", "bbb_2ch_44kHz_aac.mp4", -1.0f, -1L, CODEC_ALL}, 211 {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_340x280_768kbps_30fps_mpeg2.mp4", null, 212 "bbb_520x390_1mbps_30fps_mpeg2.mp4", -1.0f, -1L, CODEC_ALL}, 213 {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_340x280_768kbps_30fps_avc.mp4", null, 214 "bbb_520x390_1mbps_30fps_avc.mp4", -1.0f, 1746312400L, CODEC_ALL}, 215 {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_520x390_1mbps_30fps_hevc.mp4", null, 216 "bbb_340x280_768kbps_30fps_hevc.mp4", -1.0f, 3061322606L, CODEC_ALL}, 217 {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4", 218 null, "bbb_176x144_192kbps_15fps_mpeg4.mp4", -1.0f, -1L, CODEC_ALL}, 219 {MediaFormat.MIMETYPE_VIDEO_H263, "bbb_176x144_128kbps_15fps_h263.3gp", 220 null, "bbb_176x144_192kbps_10fps_h263.3gp", -1.0f, -1L, CODEC_ALL}, 221 {MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_340x280_768kbps_30fps_vp8.webm", null, 222 "bbb_520x390_1mbps_30fps_vp8.webm", -1.0f, 2030620796L, CODEC_ALL}, 223 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_340x280_768kbps_30fps_vp9.webm", null, 224 "bbb_520x390_1mbps_30fps_vp9.webm", -1.0f, 4122701060L, CODEC_ALL}, 225 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_340x280_768kbps_30fps_av1.mp4", null, 226 "bbb_520x390_1mbps_30fps_av1.mp4", -1.0f, 400672933L, CODEC_ALL}, 227 })); 228 // P010 support was added in Android T, hence limit the following tests to Android T and 229 // above 230 if (IS_AT_LEAST_T) { 231 exhaustiveArgsList.addAll(Arrays.asList(new Object[][]{ 232 {MediaFormat.MIMETYPE_VIDEO_AVC, "cosmat_340x280_24fps_crf22_avc_10bit.mkv", 233 null, "cosmat_520x390_24fps_crf22_avc_10bit.mkv", -1.0f, 1462636611L, 234 CODEC_OPTIONAL}, 235 {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_340x280_24fps_crf22_hevc_10bit.mkv", 236 null, "cosmat_520x390_24fps_crf22_hevc_10bit.mkv", -1.0f, 2611796790L, 237 CODEC_OPTIONAL}, 238 {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_340x280_24fps_crf22_vp9_10bit.mkv", 239 null, "cosmat_520x390_24fps_crf22_vp9_10bit.mkv", -1.0f, 2419292938L, 240 CODEC_OPTIONAL}, 241 {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_340x280_24fps_512kbps_av1_10bit.mkv", 242 null, "cosmat_520x390_24fps_768kbps_av1_10bit.mkv", -1.0f, 1021109556L, 243 CODEC_ALL}, 244 {MediaFormat.MIMETYPE_VIDEO_AVC, "cosmat_340x280_24fps_crf22_avc_10bit.mkv", 245 null, "bbb_520x390_1mbps_30fps_avc.mp4", -1.0f, 1462636611L, 246 CODEC_OPTIONAL}, 247 {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_340x280_24fps_crf22_hevc_10bit.mkv", 248 null, "bbb_520x390_1mbps_30fps_hevc.mp4", -1.0f, 2611796790L, 249 CODEC_OPTIONAL}, 250 {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_340x280_24fps_crf22_vp9_10bit.mkv", 251 null, "bbb_520x390_1mbps_30fps_vp9.webm", -1.0f, 2419292938L, 252 CODEC_OPTIONAL}, 253 {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_340x280_24fps_512kbps_av1_10bit.mkv", 254 null, "bbb_520x390_1mbps_30fps_av1.mp4", -1.0f, 1021109556L, 255 CODEC_ALL}, 256 {MediaFormat.MIMETYPE_VIDEO_AVC, "cosmat_520x390_24fps_crf22_avc_10bit.mkv", 257 null, "bbb_340x280_768kbps_30fps_avc.mp4", -1.0f, 2245243696L, 258 CODEC_OPTIONAL}, 259 {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_520x390_24fps_crf22_hevc_10bit.mkv" 260 , null, "bbb_340x280_768kbps_30fps_hevc.mp4", -1.0f, 2486118612L, 261 CODEC_OPTIONAL}, 262 {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_520x390_24fps_crf22_vp9_10bit.mkv", 263 null, "bbb_340x280_768kbps_30fps_vp9.webm", -1.0f, 3677982654L, 264 CODEC_OPTIONAL}, 265 {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_520x390_24fps_768kbps_av1_10bit.mkv", 266 null, "bbb_340x280_768kbps_30fps_av1.mp4", -1.0f, 1139081423L, 267 CODEC_ALL}, 268 })); 269 } 270 return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, true); 271 } 272 verify(OutputManager outBuff, String refFile, float rmsError, int audioFormat, long refCRC, String msg)273 static void verify(OutputManager outBuff, String refFile, float rmsError, int audioFormat, 274 long refCRC, String msg) throws IOException { 275 if (rmsError >= 0) { 276 int bytesPerSample = AudioFormat.getBytesPerSample(audioFormat); 277 ByteBuffer bb = readAudioReferenceFile(refFile); 278 bb.position(0); 279 int bufferSize = bb.limit(); 280 assertEquals("error, reference audio buffer contains partial samples\n" + msg, 0, 281 bufferSize % bytesPerSample); 282 Object refObject = null; 283 int refObjectLen = bufferSize / bytesPerSample; 284 switch (audioFormat) { 285 case AudioFormat.ENCODING_PCM_8BIT: 286 refObject = new byte[refObjectLen]; 287 bb.get((byte[]) refObject); 288 break; 289 case AudioFormat.ENCODING_PCM_16BIT: 290 refObject = new short[refObjectLen]; 291 bb.asShortBuffer().get((short[]) refObject); 292 break; 293 case AudioFormat.ENCODING_PCM_24BIT_PACKED: 294 refObject = new int[refObjectLen]; 295 int[] refArray = (int[]) refObject; 296 for (int i = 0, j = 0; i < bufferSize; i += 3, j++) { 297 int byte1 = (bb.get() & 0xff); 298 int byte2 = (bb.get() & 0xff); 299 int byte3 = (bb.get() & 0xff); 300 refArray[j] = byte1 | (byte2 << 8) | (byte3 << 16); 301 } 302 break; 303 case AudioFormat.ENCODING_PCM_32BIT: 304 refObject = new int[refObjectLen]; 305 bb.asIntBuffer().get((int[]) refObject); 306 break; 307 case AudioFormat.ENCODING_PCM_FLOAT: 308 refObject = new float[refObjectLen]; 309 bb.asFloatBuffer().get((float[]) refObject); 310 break; 311 default: 312 fail("unrecognized audio encoding type :- " + audioFormat + "\n" + msg); 313 } 314 float currError = outBuff.getRmsError(refObject, audioFormat); 315 float errMargin = rmsError * RMS_ERROR_TOLERANCE; 316 assertTrue(String.format("%s rms error too high ref/exp/got %f/%f/%f \n", refFile, 317 rmsError, errMargin, currError) + msg, currError <= errMargin); 318 } else if (refCRC >= 0) { 319 assertEquals("checksum mismatch \n" + msg, refCRC, outBuff.getCheckSumImage()); 320 } 321 } 322 doOutputFormatChecks(MediaFormat defaultFormat, MediaFormat configuredFormat)323 void doOutputFormatChecks(MediaFormat defaultFormat, MediaFormat configuredFormat) { 324 String msg = String.format("Input test file format is not same as default format of" 325 + " component, but test did not receive INFO_OUTPUT_FORMAT_CHANGED signal" 326 + ".\nInput file format is :- %s \nDefault format is :- %s \n", 327 configuredFormat, defaultFormat); 328 assertTrue(msg + mTestConfig + mTestEnv, 329 mIsCodecInAsyncMode ? mAsyncHandle.hasOutputFormatChanged() : 330 mSignalledOutFormatChanged); 331 MediaFormat outputFormat = 332 mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat() : mOutFormat; 333 msg = String.format("Configured input format and received output format are " 334 + "not similar. \nConfigured Input format is :- %s \nReceived Output " 335 + "format is :- %s \n", configuredFormat, outputFormat); 336 assertTrue(msg + mTestConfig + mTestEnv, isFormatSimilar(configuredFormat, outputFormat)); 337 } 338 339 @Before setUp()340 public void setUp() throws IOException { 341 MediaFormat format = setUpSource(mTestFile); 342 mExtractor.release(); 343 ArrayList<MediaFormat> formatList = new ArrayList<>(); 344 formatList.add(format); 345 checkFormatSupport(mCodecName, mMediaType, false, formatList, null, mSupportRequirements); 346 } 347 nativeTestSimpleDecode(String decoder, Surface surface, String mediaType, String testFile, String refFile, int colorFormat, float rmsError, long checksum, StringBuilder retMsg)348 private native boolean nativeTestSimpleDecode(String decoder, Surface surface, String mediaType, 349 String testFile, String refFile, int colorFormat, float rmsError, long checksum, 350 StringBuilder retMsg); 351 352 /** 353 * Verifies if the component under test can decode the test file correctly. The decoding 354 * happens in synchronous, asynchronous mode, eos flag signalled with last compressed frame and 355 * eos flag signalled separately after sending all compressed frames. It expects consistent 356 * output in all these runs. That is, the ByteBuffer info and output timestamp list has to be 357 * same in all the runs. Further for audio, the output timestamp has to be strictly 358 * increasing, for lossless audio codec the rms error has to be 0 and for lossy audio codecs, 359 * the rms error has to be with in tolerance limit. For video the output timestamp list has 360 * to be same as input timestamp list (no frame drops) and for completely normative codecs, 361 * the output checksum has to be identical to reference checksum. For non-normative codecs, 362 * the output has to be consistent. The test also verifies if the component / framework 363 * behavior is consistent between SDK and NDK. The test also verifies if the 364 * component / framework behavior is consistent between block model mode and normal mode. 365 */ 366 @CddTest(requirements = {"2.2.2", "2.3.2", "2.5.2", "5.1.2"}) 367 @ApiTest(apis = {"android.media.MediaCodecInfo.CodecCapabilities#COLOR_FormatYUV420Flexible", 368 "android.media.MediaCodecInfo.CodecCapabilities#COLOR_FormatYUVP010", 369 "android.media.AudioFormat#ENCODING_PCM_16BIT", 370 "android.media.MediaCodec#CONFIGURE_FLAG_USE_BLOCK_MODEL"}) 371 @LargeTest 372 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testSimpleDecode()373 public void testSimpleDecode() throws IOException, InterruptedException { 374 MediaFormat format = setUpSource(mTestFile); 375 boolean[] boolStates = {true, false}; 376 mSaveToMem = true; 377 OutputManager ref = new OutputManager(); 378 OutputManager test = new OutputManager(ref.getSharedErrorLogs()); 379 { 380 mCodec = MediaCodec.createByCodecName(mCodecName); 381 assertEquals("codec name act/got: " + mCodec.getName() + '/' + mCodecName, 382 mCodecName, mCodec.getName()); 383 assertTrue("error! codec canonical name is null or empty", 384 mCodec.getCanonicalName() != null && !mCodec.getCanonicalName().isEmpty()); 385 validateMetrics(mCodecName); 386 int loopCounter = 0; 387 for (boolean eosType : boolStates) { 388 for (boolean isAsync : boolStates) { 389 boolean validateFormat = true; 390 mOutputBuff = loopCounter == 0 ? ref : test; 391 mOutputBuff.reset(); 392 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 393 configureCodec(format, isAsync, eosType, false); 394 MediaFormat defFormat = mCodec.getOutputFormat(); 395 if (isFormatSimilar(format, defFormat)) { 396 if (ENABLE_LOGS) { 397 Log.d("Input format is same as default for format for %s", mCodecName); 398 } 399 validateFormat = false; 400 } 401 mCodec.start(); 402 doWork(Integer.MAX_VALUE); 403 queueEOS(); 404 waitForAllOutputs(); 405 validateMetrics(mCodecName, format); 406 endCodecSession(mCodec); 407 if (loopCounter != 0 && !ref.equals(test)) { 408 fail("Decoder output is not consistent across runs \n" + mTestConfig 409 + mTestEnv + test.getErrMsg()); 410 } 411 if (validateFormat) { 412 doOutputFormatChecks(defFormat, format); 413 } 414 loopCounter++; 415 } 416 } 417 mCodec.release(); 418 mExtractor.release(); 419 // The following part of the test was added after Android U and is not guaranteed 420 // to work on versions before that, hence limit it to Android V and above. 421 if (IS_AT_LEAST_V && mSaveToMem && mIsAudio) { 422 test.reset(); 423 CodecDecoderBlockModelTestBase cdbmtb = new CodecDecoderBlockModelTestBase( 424 mCodecName, mMediaType, null, mAllTestParams); 425 cdbmtb.decodeToMemory(mTestFile, mCodecName, test, 0, 426 MediaExtractor.SEEK_TO_CLOSEST_SYNC, Integer.MAX_VALUE, true, false); 427 if (!ref.equals(test)) { 428 fail("Output in block model mode is not same as output in normal mode. \n" 429 + mTestConfig + mTestEnv + test.getErrMsg()); 430 } 431 } 432 int colorFormat = mIsAudio ? 0 : format.getInteger(MediaFormat.KEY_COLOR_FORMAT); 433 boolean isPass = nativeTestSimpleDecode(mCodecName, null, mMediaType, mTestFile, 434 mRefFile, colorFormat, mRmsError, ref.getCheckSumBuffer(), mTestConfig); 435 assertTrue(mTestConfig.toString(), isPass); 436 if (mSaveToMem) { 437 int audioEncoding = mIsAudio ? format.getInteger(MediaFormat.KEY_PCM_ENCODING, 438 AudioFormat.ENCODING_PCM_16BIT) : AudioFormat.ENCODING_INVALID; 439 Assume.assumeFalse("skip checksum due to tone mapping", mSkipChecksumVerification); 440 verify(mOutputBuff, mRefFile, mRmsError, audioEncoding, mRefCRC, 441 mTestConfig.toString() + mTestEnv.toString()); 442 } 443 } 444 } 445 446 /** 447 * Verifies component and framework behaviour to flush API when the codec is operating in 448 * byte buffer mode. 449 * <p> 450 * While the component is decoding the test clip, mediacodec flush() is called. The flush API 451 * is called at various points :- 452 * <ul> 453 * <li>In running state but before queueing any input (might have to resubmit csd as they 454 * may not have been processed).</li> 455 * <li>In running state, after queueing 1 frame.</li> 456 * <li>In running state, after queueing n frames.</li> 457 * <li>In eos state.</li> 458 * </ul> 459 * <p> 460 * In all situations (pre-flush or post-flush), the test expects the output timestamps to be 461 * strictly increasing. The flush call makes the output received non-deterministic even for a 462 * given input. Hence, besides timestamp checks, no additional validation is done for outputs 463 * received before flush. Post flush, the decode begins from a sync frame. So the test 464 * expects consistent output and this needs to be identical to the reference. 465 * <p> 466 * The test runs mediacodec in synchronous and asynchronous mode. 467 */ 468 @ApiTest(apis = {"android.media.MediaCodec#flush"}) 469 @LargeTest 470 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testFlush()471 public void testFlush() throws IOException, InterruptedException { 472 MediaFormat format = setUpSource(mTestFile); 473 mExtractor.release(); 474 mCsdBuffers.clear(); 475 for (int i = 0; ; i++) { 476 String csdKey = "csd-" + i; 477 if (format.containsKey(csdKey)) { 478 mCsdBuffers.add(format.getByteBuffer(csdKey)); 479 } else break; 480 } 481 final long pts = 500000; 482 final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC; 483 boolean[] boolStates = {true, false}; 484 { 485 decodeToMemory(mTestFile, mCodecName, pts, mode, Integer.MAX_VALUE); 486 OutputManager ref = mOutputBuff; 487 OutputManager test = new OutputManager(ref.getSharedErrorLogs()); 488 mOutputBuff = test; 489 setUpSource(mTestFile); 490 mCodec = MediaCodec.createByCodecName(mCodecName); 491 for (boolean isAsync : boolStates) { 492 if (isAsync) continue; // TODO(b/147576107) 493 mExtractor.seekTo(0, mode); 494 configureCodec(format, isAsync, true, false); 495 MediaFormat defFormat = mCodec.getOutputFormat(); 496 boolean validateFormat = true; 497 if (isFormatSimilar(format, defFormat)) { 498 if (ENABLE_LOGS) { 499 Log.d("Input format is same as default for format for %s", mCodecName); 500 } 501 validateFormat = false; 502 } 503 mCodec.start(); 504 505 /* test flush in running state before queuing input */ 506 flushCodec(); 507 if (mIsCodecInAsyncMode) mCodec.start(); 508 queueCodecConfig(); /* flushed codec too soon after start, resubmit csd */ 509 510 doWork(1); 511 flushCodec(); 512 if (mIsCodecInAsyncMode) mCodec.start(); 513 queueCodecConfig(); /* flushed codec too soon after start, resubmit csd */ 514 515 mExtractor.seekTo(0, mode); 516 test.reset(); 517 doWork(23); 518 if (!test.isPtsStrictlyIncreasing(mPrevOutputPts)) { 519 fail("Output timestamps are not strictly increasing \n" + mTestConfig + mTestEnv 520 + test.getErrMsg()); 521 } 522 523 boolean checkMetrics = (mOutputCount != 0); 524 525 /* test flush in running state */ 526 flushCodec(); 527 if (checkMetrics) validateMetrics(mCodecName, format); 528 if (mIsCodecInAsyncMode) mCodec.start(); 529 mSaveToMem = true; 530 test.reset(); 531 mExtractor.seekTo(pts, mode); 532 doWork(Integer.MAX_VALUE); 533 queueEOS(); 534 waitForAllOutputs(); 535 if (isMediaTypeOutputUnAffectedBySeek(mMediaType) && (!ref.equals(test))) { 536 fail("Decoder output is not consistent across runs \n" + mTestConfig + mTestEnv 537 + test.getErrMsg()); 538 } 539 540 /* test flush in eos state */ 541 flushCodec(); 542 if (mIsCodecInAsyncMode) mCodec.start(); 543 test.reset(); 544 mExtractor.seekTo(pts, mode); 545 doWork(Integer.MAX_VALUE); 546 queueEOS(); 547 waitForAllOutputs(); 548 endCodecSession(mCodec); 549 if (isMediaTypeOutputUnAffectedBySeek(mMediaType) && (!ref.equals(test))) { 550 fail("Decoder output is not consistent across runs \n" + mTestConfig + mTestEnv 551 + test.getErrMsg()); 552 } 553 if (validateFormat) { 554 doOutputFormatChecks(defFormat, format); 555 } 556 mSaveToMem = false; 557 } 558 mCodec.release(); 559 mExtractor.release(); 560 } 561 } 562 nativeTestFlush(String decoder, Surface surface, String mediaType, String testFile, int colorFormat, StringBuilder retMsg)563 private native boolean nativeTestFlush(String decoder, Surface surface, String mediaType, 564 String testFile, int colorFormat, StringBuilder retMsg); 565 566 /** 567 * Test is similar to {@link #testFlush()} but uses ndk api 568 */ 569 @ApiTest(apis = {"android.media.MediaCodec#flush"}) 570 @LargeTest 571 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testFlushNative()572 public void testFlushNative() throws IOException { 573 int colorFormat = 0; 574 if (mIsVideo) { 575 MediaFormat format = setUpSource(mTestFile); 576 mExtractor.release(); 577 colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT); 578 } 579 boolean isPass = nativeTestFlush(mCodecName, null, mMediaType, mTestFile, 580 colorFormat, mTestConfig); 581 assertTrue(mTestConfig.toString(), isPass); 582 } 583 584 /** 585 * Verifies component and framework behaviour for resolution change in bytebuffer mode. The 586 * resolution change is not seamless (AdaptivePlayback) but done via reconfigure. 587 * <p> 588 * The reconfiguring of media codec component happens at various points :- 589 * <ul> 590 * <li>After initial configuration (stopped state).</li> 591 * <li>In running state, before queueing any input.</li> 592 * <li>In running state, after queuing n frames.</li> 593 * <li>In eos state.</li> 594 * </ul> 595 * In eos state, 596 * <ul> 597 * <li>reconfigure with same clip.</li> 598 * <li>reconfigure with different clip (different resolution).</li> 599 * </ul> 600 * <p> 601 * In all situations (pre-reconfigure or post-reconfigure), the test expects the output 602 * timestamps to be strictly increasing. The reconfigure call makes the output received 603 * non-deterministic even for a given input. Hence, besides timestamp checks, no additional 604 * validation is done for outputs received before reconfigure. Post reconfigure, the decode 605 * begins from a sync frame. So the test expects consistent output and this needs to be 606 * identical to the reference. 607 * <p> 608 * The test runs mediacodec in synchronous and asynchronous mode. 609 * <p> 610 * During reconfiguration, the mode of operation is toggled. That is, if first configure 611 * operates the codec in sync mode, then next configure operates the codec in async mode and 612 * so on. 613 */ 614 @ApiTest(apis = "android.media.MediaCodec#configure") 615 @LargeTest 616 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testReconfigure()617 public void testReconfigure() throws IOException, InterruptedException { 618 Assume.assumeTrue("Test needs Android 11", IS_AT_LEAST_R); 619 620 MediaFormat format = setUpSource(mTestFile); 621 mExtractor.release(); 622 MediaFormat newFormat = setUpSource(mReconfigFile); 623 mExtractor.release(); 624 ArrayList<MediaFormat> formatList = new ArrayList<>(); 625 formatList.add(newFormat); 626 checkFormatSupport(mCodecName, mMediaType, false, formatList, null, mSupportRequirements); 627 final long startTs = 0; 628 final long seekTs = 500000; 629 final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC; 630 boolean[] boolStates = {true, false}; 631 { 632 decodeToMemory(mTestFile, mCodecName, startTs, mode, Integer.MAX_VALUE); 633 OutputManager ref = mOutputBuff; 634 decodeToMemory(mReconfigFile, mCodecName, seekTs, mode, Integer.MAX_VALUE); 635 OutputManager configRef = mOutputBuff; 636 OutputManager test = new OutputManager(ref.getSharedErrorLogs()); 637 OutputManager configTest = new OutputManager(configRef.getSharedErrorLogs()); 638 mCodec = MediaCodec.createByCodecName(mCodecName); 639 for (boolean isAsync : boolStates) { 640 mOutputBuff = test; 641 setUpSource(mTestFile); 642 mExtractor.seekTo(startTs, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 643 configureCodec(format, isAsync, true, false); 644 MediaFormat defFormat = mCodec.getOutputFormat(); 645 boolean validateFormat = true; 646 if (isFormatSimilar(format, defFormat)) { 647 if (ENABLE_LOGS) { 648 Log.d("Input format is same as default for format for %s", mCodecName); 649 } 650 validateFormat = false; 651 } 652 653 /* test reconfigure in stopped state */ 654 reConfigureCodec(format, !isAsync, false, false); 655 mCodec.start(); 656 657 /* test reconfigure in running state before queuing input */ 658 reConfigureCodec(format, !isAsync, false, false); 659 mCodec.start(); 660 doWork(23); 661 662 if (mOutputCount != 0) { 663 if (validateFormat) { 664 doOutputFormatChecks(defFormat, format); 665 } 666 validateMetrics(mCodecName, format); 667 } 668 669 /* test reconfigure codec in running state */ 670 reConfigureCodec(format, isAsync, true, false); 671 mCodec.start(); 672 mSaveToMem = true; 673 test.reset(); 674 mExtractor.seekTo(startTs, mode); 675 doWork(Integer.MAX_VALUE); 676 queueEOS(); 677 waitForAllOutputs(); 678 endCodecSession(mCodec); 679 if (!ref.equals(test)) { 680 fail("Decoder output is not consistent across runs \n" + mTestConfig + mTestEnv 681 + test.getErrMsg()); 682 } 683 if (validateFormat) { 684 doOutputFormatChecks(defFormat, format); 685 } 686 687 /* test reconfigure codec at eos state */ 688 reConfigureCodec(format, !isAsync, false, false); 689 mCodec.start(); 690 test.reset(); 691 mExtractor.seekTo(startTs, mode); 692 doWork(Integer.MAX_VALUE); 693 queueEOS(); 694 waitForAllOutputs(); 695 endCodecSession(mCodec); 696 if (!ref.equals(test)) { 697 fail("Decoder output is not consistent across runs \n" + mTestConfig + mTestEnv 698 + test.getErrMsg()); 699 } 700 if (validateFormat) { 701 doOutputFormatChecks(defFormat, format); 702 } 703 mExtractor.release(); 704 705 /* test reconfigure codec for new file */ 706 mOutputBuff = configTest; 707 setUpSource(mReconfigFile); 708 reConfigureCodec(newFormat, isAsync, false, false); 709 if (isFormatSimilar(newFormat, defFormat)) { 710 if (ENABLE_LOGS) { 711 Log.d("Input format is same as default for format for %s", mCodecName); 712 } 713 validateFormat = false; 714 } 715 mCodec.start(); 716 configTest.reset(); 717 mExtractor.seekTo(seekTs, mode); 718 doWork(Integer.MAX_VALUE); 719 queueEOS(); 720 waitForAllOutputs(); 721 validateMetrics(mCodecName, newFormat); 722 endCodecSession(mCodec); 723 if (!configRef.equals(configTest)) { 724 fail("Decoder output is not consistent across runs \n" + mTestConfig + mTestEnv 725 + configTest.getErrMsg()); 726 } 727 if (validateFormat) { 728 doOutputFormatChecks(defFormat, newFormat); 729 } 730 mSaveToMem = false; 731 mExtractor.release(); 732 } 733 mCodec.release(); 734 } 735 } 736 737 /** 738 * Test decoder for EOS only input. As BUFFER_FLAG_END_OF_STREAM is queued with an input buffer 739 * of size 0, during dequeue the test expects to receive BUFFER_FLAG_END_OF_STREAM with an 740 * output buffer of size 0. No input is given, so no output shall be received. 741 */ 742 @ApiTest(apis = "android.media.MediaCodec#BUFFER_FLAG_END_OF_STREAM") 743 @SmallTest 744 @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS) testOnlyEos()745 public void testOnlyEos() throws IOException, InterruptedException { 746 MediaFormat format = setUpSource(mTestFile); 747 boolean[] boolStates = {true, false}; 748 OutputManager ref = new OutputManager(); 749 OutputManager test = new OutputManager(ref.getSharedErrorLogs()); 750 mSaveToMem = true; 751 { 752 mCodec = MediaCodec.createByCodecName(mCodecName); 753 int loopCounter = 0; 754 for (boolean isAsync : boolStates) { 755 configureCodec(format, isAsync, false, false); 756 mOutputBuff = loopCounter == 0 ? ref : test; 757 mOutputBuff.reset(); 758 mCodec.start(); 759 queueEOS(); 760 waitForAllOutputs(); 761 endCodecSession(mCodec); 762 if (loopCounter != 0 && !ref.equals(test)) { 763 fail("Decoder output is not consistent across runs \n" + mTestConfig + mTestEnv 764 + test.getErrMsg()); 765 } 766 loopCounter++; 767 } 768 mCodec.release(); 769 } 770 mExtractor.release(); 771 } 772 nativeTestOnlyEos(String decoder, String mediaType, String testFile, int colorFormat, StringBuilder retMsg)773 private native boolean nativeTestOnlyEos(String decoder, String mediaType, String testFile, 774 int colorFormat, StringBuilder retMsg); 775 776 /** 777 * Test is similar to {@link #testOnlyEos()} but uses ndk api 778 */ 779 @ApiTest(apis = "android.media.MediaCodec#BUFFER_FLAG_END_OF_STREAM") 780 @SmallTest 781 @Test testOnlyEosNative()782 public void testOnlyEosNative() throws IOException { 783 int colorFormat = 0; 784 if (mIsVideo) { 785 MediaFormat format = setUpSource(mTestFile); 786 mExtractor.release(); 787 colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT); 788 } 789 boolean isPass = nativeTestOnlyEos(mCodecName, mMediaType, mTestFile, colorFormat, 790 mTestConfig); 791 assertTrue(mTestConfig.toString(), isPass); 792 } 793 794 /** 795 * CSD buffers can be queued at configuration or can be queued separately as the first buffer(s) 796 * sent to the codec. This test ensures that both mechanisms function and that they are 797 * semantically the same. 798 */ 799 @ApiTest(apis = "android.media.MediaCodec#BUFFER_FLAG_CODEC_CONFIG") 800 @LargeTest 801 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testSimpleDecodeQueueCSD()802 public void testSimpleDecodeQueueCSD() throws IOException, InterruptedException { 803 MediaFormat format = setUpSource(mTestFile); 804 if (!hasCSD(format)) { 805 mExtractor.release(); 806 return; 807 } 808 ArrayList<MediaFormat> formats = new ArrayList<>(); 809 formats.add(format); 810 formats.add(new MediaFormat(format)); 811 for (int i = 0; ; i++) { 812 String csdKey = "csd-" + i; 813 if (format.containsKey(csdKey)) { 814 mCsdBuffers.add(format.getByteBuffer(csdKey).duplicate()); 815 format.removeKey(csdKey); 816 } else break; 817 } 818 boolean[] boolStates = {true, false}; 819 mSaveToMem = true; 820 OutputManager ref = new OutputManager(); 821 OutputManager test = new OutputManager(ref.getSharedErrorLogs()); 822 { 823 mCodec = MediaCodec.createByCodecName(mCodecName); 824 int loopCounter = 0; 825 for (int i = 0; i < formats.size(); i++) { 826 MediaFormat fmt = formats.get(i); 827 for (boolean eosMode : boolStates) { 828 for (boolean isAsync : boolStates) { 829 boolean validateFormat = true; 830 mOutputBuff = loopCounter == 0 ? ref : test; 831 mOutputBuff.reset(); 832 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 833 configureCodec(fmt, isAsync, eosMode, false); 834 MediaFormat defFormat = mCodec.getOutputFormat(); 835 if (isFormatSimilar(defFormat, format)) { 836 if (ENABLE_LOGS) { 837 Log.d("Input format is same as default for format for %s", 838 mCodecName); 839 } 840 validateFormat = false; 841 } 842 mCodec.start(); 843 if (i == 0) queueCodecConfig(); 844 doWork(Integer.MAX_VALUE); 845 queueEOS(); 846 waitForAllOutputs(); 847 validateMetrics(mCodecName); 848 endCodecSession(mCodec); 849 if (loopCounter != 0 && !ref.equals(test)) { 850 fail("Decoder output is not consistent across runs \n" + mTestConfig 851 + mTestEnv + test.getErrMsg()); 852 } 853 if (validateFormat) { 854 doOutputFormatChecks(defFormat, format); 855 } 856 loopCounter++; 857 } 858 } 859 } 860 mCodec.release(); 861 } 862 mExtractor.release(); 863 } 864 nativeTestSimpleDecodeQueueCSD(String decoder, String mediaType, String testFile, int colorFormat, StringBuilder retMsg)865 private native boolean nativeTestSimpleDecodeQueueCSD(String decoder, String mediaType, 866 String testFile, int colorFormat, StringBuilder retMsg); 867 868 /** 869 * Test is similar to {@link #testSimpleDecodeQueueCSD()} but uses ndk api 870 */ 871 @ApiTest(apis = "android.media.MediaCodec#BUFFER_FLAG_CODEC_CONFIG") 872 @LargeTest 873 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testSimpleDecodeQueueCSDNative()874 public void testSimpleDecodeQueueCSDNative() throws IOException { 875 MediaFormat format = setUpSource(mTestFile); 876 if (!hasCSD(format)) { 877 mExtractor.release(); 878 return; 879 } 880 mExtractor.release(); 881 int colorFormat = mIsAudio ? 0 : format.getInteger(MediaFormat.KEY_COLOR_FORMAT); 882 boolean isPass = nativeTestSimpleDecodeQueueCSD(mCodecName, mMediaType, mTestFile, 883 colorFormat, mTestConfig); 884 assertTrue(mTestConfig.toString(), isPass); 885 } 886 887 /** 888 * Test decoder for partial frame inputs. The test expects decoder to give same output for a 889 * regular sequence and when any frames of that sequence are delivered in parts using the 890 * PARTIAL_FRAME flag. 891 */ 892 @ApiTest(apis = {"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_PartialFrame", 893 "android.media.MediaCodec#BUFFER_FLAG_PARTIAL_FRAME"}) 894 @LargeTest 895 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testDecodePartialFrame()896 public void testDecodePartialFrame() throws IOException, InterruptedException { 897 Assume.assumeTrue("codec: " + mCodecName + " does not advertise FEATURE_PartialFrame", 898 isFeatureSupported(mCodecName, mMediaType, 899 MediaCodecInfo.CodecCapabilities.FEATURE_PartialFrame)); 900 MediaFormat format = setUpSource(mTestFile); 901 boolean[] boolStates = {true, false}; 902 int frameLimit = 10; 903 ByteBuffer buffer = ByteBuffer.allocate(4 * 1024 * 1024); 904 { 905 decodeToMemory(mTestFile, mCodecName, 0, MediaExtractor.SEEK_TO_CLOSEST_SYNC, 906 frameLimit); 907 mCodec = MediaCodec.createByCodecName(mCodecName); 908 OutputManager ref = mOutputBuff; 909 mSaveToMem = true; 910 OutputManager test = new OutputManager(ref.getSharedErrorLogs()); 911 mOutputBuff = test; 912 for (boolean isAsync : boolStates) { 913 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 914 test.reset(); 915 configureCodec(format, isAsync, true, false); 916 mCodec.start(); 917 doWork(frameLimit - 1); 918 ArrayList<MediaCodec.BufferInfo> list = createSubFrames(buffer, 4); 919 assertTrue("no sub frames in list received for " + mTestFile, 920 list != null && list.size() > 0); 921 doWork(buffer, list); 922 queueEOS(); 923 waitForAllOutputs(); 924 endCodecSession(mCodec); 925 if (!ref.equals(test)) { 926 fail("Decoder output of a compressed stream segmented at frame/access unit " 927 + "boundaries is different from a compressed stream segmented at " 928 + "arbitrary byte boundary \n" 929 + mTestConfig + mTestEnv + test.getErrMsg()); 930 } 931 } 932 mCodec.release(); 933 } 934 mExtractor.release(); 935 } 936 937 /** 938 * Test if decoder outputs 8-bit data for 8-bit as well as 10-bit content by default. The 939 * test removes the key "KEY_COLOR_FORMAT" from the input format to the decoder and verifies if 940 * the component decodes to an 8 bit color format by default. 941 * <p> 942 * The test is applicable for video components only. 943 */ 944 @CddTest(requirements = {"5.1.7/C-4-2"}) 945 @SmallTest 946 @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS) testDefaultOutputColorFormat()947 public void testDefaultOutputColorFormat() throws IOException, InterruptedException { 948 Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T); 949 Assume.assumeTrue("Test is applicable for video decoders", mIsVideo); 950 951 MediaFormat format = setUpSource(mTestFile); 952 format.removeKey(MediaFormat.KEY_COLOR_FORMAT); 953 954 mOutputBuff = new OutputManager(); 955 mCodec = MediaCodec.createByCodecName(mCodecName); 956 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 957 configureCodec(format, true, true, false); 958 mCodec.start(); 959 doWork(1); 960 queueEOS(); 961 waitForAllOutputs(); 962 MediaFormat outputFormat = mCodec.getOutputFormat(); 963 endCodecSession(mCodec); 964 mCodec.release(); 965 966 assertTrue("Output format from decoder does not contain KEY_COLOR_FORMAT \n" + mTestConfig 967 + mTestEnv, outputFormat.containsKey(MediaFormat.KEY_COLOR_FORMAT)); 968 // 8-bit color formats 969 int[] defaultOutputColorFormatList = 970 new int[]{COLOR_FormatYUV420Flexible, COLOR_FormatYUV420Planar, 971 COLOR_FormatYUV420PackedPlanar, COLOR_FormatYUV420SemiPlanar}; 972 int outputColorFormat = outputFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT); 973 assertTrue(String.format("Unexpected output color format %x \n", outputColorFormat) 974 + mTestConfig + mTestEnv, 975 IntStream.of(defaultOutputColorFormatList).anyMatch(x -> x == outputColorFormat)); 976 } 977 } 978