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.common.cts; 18 19 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing; 20 import static android.media.MediaCodecInfo.CodecProfileLevel.*; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assert.fail; 27 28 import android.content.Context; 29 import android.hardware.camera2.CameraAccessException; 30 import android.hardware.camera2.CameraCharacteristics; 31 import android.hardware.camera2.CameraManager; 32 import android.hardware.camera2.CameraMetadata; 33 import android.hardware.camera2.params.DynamicRangeProfiles; 34 import android.hardware.display.DisplayManager; 35 import android.media.MediaCodec; 36 import android.media.MediaCodecInfo; 37 import android.media.MediaCodecInfo.CodecCapabilities; 38 import android.media.MediaCodecInfo.CodecProfileLevel; 39 import android.media.MediaCodecList; 40 import android.media.MediaFormat; 41 import android.os.Build; 42 import android.os.Bundle; 43 import android.os.PersistableBundle; 44 import android.os.SystemProperties; 45 import android.util.Log; 46 import android.util.Pair; 47 import android.view.Display; 48 import android.view.Surface; 49 50 import androidx.test.platform.app.InstrumentationRegistry; 51 52 import com.android.compatibility.common.util.ApiLevelUtil; 53 import com.android.compatibility.common.util.MediaUtils; 54 55 import org.junit.After; 56 import org.junit.Assume; 57 import org.junit.Before; 58 import org.junit.Rule; 59 import org.junit.rules.TestName; 60 61 import java.io.IOException; 62 import java.nio.ByteBuffer; 63 import java.util.ArrayList; 64 import java.util.Arrays; 65 import java.util.Comparator; 66 import java.util.HashMap; 67 import java.util.HashSet; 68 import java.util.List; 69 import java.util.Map; 70 import java.util.Set; 71 import java.util.regex.Matcher; 72 import java.util.regex.Pattern; 73 import java.util.stream.IntStream; 74 import java.util.stream.Stream; 75 76 /** 77 * This class comprises of routines that are generic to media codec component trying and testing. 78 * <p> 79 * A media codec component essentially processes input data to generate output data. The 80 * component uses a set of input and output buffers. At a simplistic level, the client requests 81 * (or receive) an empty input buffer, fills it up with data and sends it to the codec for 82 * processing. The codec uses up the data and transforms it into one of its empty output 83 * buffers. Finally, the client asks (or receive) a filled output buffer, consume its contents and 84 * release it back to the codec. 85 * <p> 86 * The type of data that a component receives and sends is dependent on the component. For 87 * instance video encoders expect raw yuv/rgb data and send compressed data. A video decoder 88 * receives compressed access-unit and sends reconstructed yuv. But the processes surrounding 89 * this enqueue and dequeue remain common to all components. Operations like configure, requesting 90 * the component for an empty input buffer, feeding the component a filled input buffer, 91 * requesting the component for an output buffer, releasing the processed output buffer, Sending 92 * state transition commands, waiting on component to send all outputs, closing the component and 93 * releasing the resources, ... remain more or less identical to all components. The routines 94 * that manage these generic processes are maintained by this class. Not only the methods that 95 * are responsible for component trying but also methods that test its functionality are covered 96 * here. A video component is expected to give same number of outputs as inputs. The output 97 * buffer timestamps of an audio component or a decoder component is expected to be strictly 98 * increasing. The routines that enforce these generic rules of all components at all times are 99 * part of this class. Besides these, mediaType specific constants, helper utilities to test 100 * specific components or mediaTypes are covered here. 101 * <p> 102 * enqueueInput and dequeueOutput are routines responsible for filling the input buffer and 103 * handing the received output buffer respectively. These shall be component specific, hence they 104 * are abstract methods. Any client intending to use this class shall implement these methods 105 * basing on the component under test. 106 * <p> 107 * In simple terms, the CodecTestBase is a wrapper class comprising generic routines for 108 * component trying and testing. 109 */ 110 public abstract class CodecTestBase { 111 public static final boolean IS_Q = ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.Q; 112 public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R); 113 public static final boolean IS_AT_LEAST_T = 114 ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU); 115 //TODO(b/248315681) Remove codenameEquals() check once devices return correct version for U 116 public static final boolean IS_AT_LEAST_U = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU) 117 || ApiLevelUtil.codenameEquals("UpsideDownCake"); 118 public static final boolean IS_BEFORE_U = !IS_AT_LEAST_U; 119 public static final boolean FIRST_SDK_IS_AT_LEAST_T = 120 ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU); 121 public static final boolean VNDK_IS_AT_LEAST_T = 122 SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT) 123 >= Build.VERSION_CODES.TIRAMISU; 124 public static final boolean VNDK_IS_BEFORE_U = 125 SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT) 126 < Build.VERSION_CODES.UPSIDE_DOWN_CAKE; 127 public static final boolean VNDK_IS_AT_MOST_U = 128 SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT) 129 <= Build.VERSION_CODES.UPSIDE_DOWN_CAKE; 130 public static final boolean BOARD_SDK_IS_AT_LEAST_T = 131 SystemProperties.getInt("ro.board.api_level", Build.VERSION_CODES.CUR_DEVELOPMENT) 132 >= Build.VERSION_CODES.TIRAMISU; 133 public static final boolean IS_HDR_EDITING_SUPPORTED; 134 public static final boolean IS_HDR_CAPTURE_SUPPORTED; 135 private static final String LOG_TAG = CodecTestBase.class.getSimpleName(); 136 137 public static final ArrayList<String> HDR_INFO_IN_BITSTREAM_CODECS = new ArrayList<>(); 138 public static final String HDR_STATIC_INFO = 139 "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 a0 0f 32 00 10 27 df 0d"; 140 public static final String HDR_STATIC_INCORRECT_INFO = 141 "00 d0 84 80 3e c2 33 c4 86 10 27 d0 07 13 3d 42 40 a0 0f 32 00 10 27 df 0d"; 142 public static final String CODEC_PREFIX_KEY = "codec-prefix"; 143 public static final String MEDIA_TYPE_PREFIX_KEY = "media-type-prefix"; 144 public static final String MEDIA_TYPE_SEL_KEY = "media-type-sel"; 145 public static final Map<String, String> CODEC_SEL_KEY_MEDIA_TYPE_MAP = new HashMap<>(); 146 public static final Map<String, String> DEFAULT_ENCODERS = new HashMap<>(); 147 public static final Map<String, String> DEFAULT_DECODERS = new HashMap<>(); 148 public static final HashMap<String, int[]> PROFILE_MAP = new HashMap<>(); 149 public static final HashMap<String, int[]> PROFILE_SDR_MAP = new HashMap<>(); 150 public static final HashMap<String, int[]> PROFILE_HLG_MAP = new HashMap<>(); 151 public static final HashMap<String, int[]> PROFILE_HDR10_MAP = new HashMap<>(); 152 public static final HashMap<String, int[]> PROFILE_HDR10_PLUS_MAP = new HashMap<>(); 153 public static final HashMap<String, int[]> PROFILE_HDR_MAP = new HashMap<>(); 154 public static final boolean ENABLE_LOGS = false; 155 public static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000; 156 public static final int PER_TEST_TIMEOUT_SMALL_TEST_MS = 60000; 157 public static final int UNSPECIFIED = 0; 158 // Maintain Timeouts in sync with their counterpart in NativeMediaCommon.h 159 // block at most 5ms while looking for io buffers 160 public static final long Q_DEQ_TIMEOUT_US = 5000; 161 // max poll counter before test aborts and returns error 162 public static final int RETRY_LIMIT = 100; 163 public static final String INVALID_CODEC = "unknown.codec_"; 164 static final int[] MPEG2_PROFILES = new int[]{MPEG2ProfileSimple, MPEG2ProfileMain, 165 MPEG2Profile422, MPEG2ProfileSNR, MPEG2ProfileSpatial, MPEG2ProfileHigh}; 166 static final int[] MPEG4_PROFILES = new int[]{MPEG4ProfileSimple, MPEG4ProfileSimpleScalable, 167 MPEG4ProfileCore, MPEG4ProfileMain, MPEG4ProfileNbit, MPEG4ProfileScalableTexture, 168 MPEG4ProfileSimpleFace, MPEG4ProfileSimpleFBA, MPEG4ProfileBasicAnimated, 169 MPEG4ProfileHybrid, MPEG4ProfileAdvancedRealTime, MPEG4ProfileCoreScalable, 170 MPEG4ProfileAdvancedCoding, MPEG4ProfileAdvancedCore, MPEG4ProfileAdvancedScalable, 171 MPEG4ProfileAdvancedSimple}; 172 static final int[] H263_PROFILES = new int[]{H263ProfileBaseline, H263ProfileH320Coding, 173 H263ProfileBackwardCompatible, H263ProfileISWV2, H263ProfileISWV3, 174 H263ProfileHighCompression, H263ProfileInternet, H263ProfileInterlace, 175 H263ProfileHighLatency}; 176 static final int[] VP8_PROFILES = new int[]{VP8ProfileMain}; 177 static final int[] AVC_SDR_PROFILES = new int[]{AVCProfileBaseline, AVCProfileMain, 178 AVCProfileExtended, AVCProfileHigh, AVCProfileConstrainedBaseline, 179 AVCProfileConstrainedHigh}; 180 static final int[] AVC_HLG_PROFILES = new int[]{AVCProfileHigh10}; 181 static final int[] AVC_HDR_PROFILES = AVC_HLG_PROFILES; 182 static final int[] AVC_PROFILES = combine(AVC_SDR_PROFILES, AVC_HDR_PROFILES); 183 static final int[] VP9_SDR_PROFILES = new int[]{VP9Profile0}; 184 static final int[] VP9_HLG_PROFILES = new int[]{VP9Profile2}; 185 static final int[] VP9_HDR10_PROFILES = new int[]{VP9Profile2HDR}; 186 static final int[] VP9_HDR10_PLUS_PROFILES = new int[]{VP9Profile2HDR10Plus}; 187 static final int[] VP9_HDR_PROFILES = 188 combine(VP9_HLG_PROFILES, combine(VP9_HDR10_PROFILES, VP9_HDR10_PLUS_PROFILES)); 189 static final int[] VP9_PROFILES = combine(VP9_SDR_PROFILES, VP9_HDR_PROFILES); 190 static final int[] HEVC_SDR_PROFILES = new int[]{HEVCProfileMain}; 191 static final int[] HEVC_HLG_PROFILES = new int[]{HEVCProfileMain10}; 192 static final int[] HEVC_HDR10_PROFILES = new int[]{HEVCProfileMain10HDR10}; 193 static final int[] HEVC_HDR10_PLUS_PROFILES = new int[]{HEVCProfileMain10HDR10Plus}; 194 static final int[] HEVC_HDR_PROFILES = 195 combine(HEVC_HLG_PROFILES, combine(HEVC_HDR10_PROFILES, HEVC_HDR10_PLUS_PROFILES)); 196 static final int[] HEVC_PROFILES = combine(HEVC_SDR_PROFILES, HEVC_HDR_PROFILES); 197 static final int[] AV1_SDR_PROFILES = new int[]{AV1ProfileMain8}; 198 static final int[] AV1_HLG_PROFILES = new int[]{AV1ProfileMain10}; 199 static final int[] AV1_HDR10_PROFILES = new int[]{AV1ProfileMain10HDR10}; 200 static final int[] AV1_HDR10_PLUS_PROFILES = new int[]{AV1ProfileMain10HDR10Plus}; 201 static final int[] AV1_HDR_PROFILES = 202 combine(AV1_HLG_PROFILES, combine(AV1_HDR10_PROFILES, AV1_HDR10_PLUS_PROFILES)); 203 static final int[] AV1_PROFILES = combine(AV1_SDR_PROFILES, AV1_HDR_PROFILES); 204 static final int[] AAC_PROFILES = new int[]{AACObjectMain, AACObjectLC, AACObjectSSR, 205 AACObjectLTP, AACObjectHE, AACObjectScalable, AACObjectERLC, AACObjectERScalable, 206 AACObjectLD, AACObjectELD, AACObjectXHE}; 207 public static final Context CONTEXT = 208 InstrumentationRegistry.getInstrumentation().getTargetContext(); 209 210 public static final int MAX_DISPLAY_HEIGHT_CURRENT = 211 Arrays.stream(CONTEXT.getSystemService(DisplayManager.class).getDisplays()) 212 .map(Display::getSupportedModes) 213 .flatMap(Stream::of) 214 .max(Comparator.comparing(Display.Mode::getPhysicalHeight)) 215 .orElseThrow(() -> new RuntimeException("Failed to determine max height")) 216 .getPhysicalHeight(); 217 public static final int MAX_DISPLAY_WIDTH_CURRENT = 218 Arrays.stream(CONTEXT.getSystemService(DisplayManager.class).getDisplays()) 219 .map(Display::getSupportedModes) 220 .flatMap(Stream::of) 221 .max(Comparator.comparing(Display.Mode::getPhysicalHeight)) 222 .orElseThrow(() -> new RuntimeException("Failed to determine max height")) 223 .getPhysicalWidth(); 224 public static final int MAX_DISPLAY_WIDTH_LAND = 225 Math.max(MAX_DISPLAY_WIDTH_CURRENT, MAX_DISPLAY_HEIGHT_CURRENT); 226 public static final int MAX_DISPLAY_HEIGHT_LAND = 227 Math.min(MAX_DISPLAY_WIDTH_CURRENT, MAX_DISPLAY_HEIGHT_CURRENT); 228 229 public static final String HDR10_INFO_SCENE_A = 230 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 231 + "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 232 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 233 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00"; 234 public static final String HDR10_INFO_SCENE_B = 235 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 236 + "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 237 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 238 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00"; 239 public static final String HDR10_INFO_SCENE_C = 240 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 241 + "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 242 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 243 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00"; 244 public static final String HDR10_INFO_SCENE_D = 245 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 246 + "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 247 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 248 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00"; 249 250 public static final String HDR10_INCORRECT_INFO_SCENE_A = 251 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 252 + "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 253 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 254 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 00"; 255 public static final String HDR10_INCORRECT_INFO_SCENE_B = 256 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 257 + "0a 00 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 258 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 259 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 01"; 260 public static final String HDR10_INCORRECT_INFO_SCENE_C = 261 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 262 + "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 263 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 264 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 02"; 265 public static final String HDR10_INCORRECT_INFO_SCENE_D = 266 "b5 00 3c 00 01 04 00 40 00 0c 80 4e 20 27 10 00" 267 + "0e 80 00 24 08 00 00 28 00 00 50 00 28 c8 00 c9" 268 + "90 02 aa 58 05 ca d0 0c 0a f8 16 83 18 9c 18 00" 269 + "40 78 13 64 d5 7c 2e 2c c3 59 de 79 6e c3 c2 03"; 270 271 public static String mediaTypeSelKeys; 272 public static String codecPrefix; 273 public static String mediaTypePrefix; 274 275 public enum SupportClass { 276 CODEC_ALL, // All codecs must support 277 CODEC_ANY, // At least one codec must support 278 CODEC_DEFAULT, // Default codec must support 279 CODEC_HW, // If the component is hardware, then it must support 280 CODEC_SHOULD, // Codec support is optional, but recommended 281 CODEC_HW_RECOMMENDED, // Codec support is optional, but strongly recommended if component 282 // is hardware accelerated 283 CODEC_OPTIONAL; // Codec support is optional 284 toString(SupportClass supportRequirements)285 public static String toString(SupportClass supportRequirements) { 286 switch (supportRequirements) { 287 case CODEC_ALL: 288 return "CODEC_ALL"; 289 case CODEC_ANY: 290 return "CODEC_ANY"; 291 case CODEC_DEFAULT: 292 return "CODEC_DEFAULT"; 293 case CODEC_HW: 294 return "CODEC_HW"; 295 case CODEC_SHOULD: 296 return "CODEC_SHOULD"; 297 case CODEC_HW_RECOMMENDED: 298 return "CODEC_HW_RECOMMENDED"; 299 case CODEC_OPTIONAL: 300 return "CODEC_OPTIONAL"; 301 default: 302 return "Unknown support class"; 303 } 304 } 305 } 306 307 public enum ComponentClass { 308 ALL, 309 SOFTWARE, 310 HARDWARE; 311 toString(ComponentClass selectSwitch)312 public static String toString(ComponentClass selectSwitch) { 313 switch (selectSwitch) { 314 case ALL: 315 return "all"; 316 case SOFTWARE: 317 return "software only"; 318 case HARDWARE: 319 return "hardware accelerated"; 320 default: 321 return "Unknown select switch"; 322 } 323 } 324 } 325 CodecTestBase(String encoder, String mediaType, String allTestParams)326 public CodecTestBase(String encoder, String mediaType, String allTestParams) { 327 mCodecName = encoder; 328 mMediaType = mediaType; 329 mAllTestParams = allTestParams; 330 mAsyncHandle = new CodecAsyncHandler(); 331 mIsAudio = mMediaType.startsWith("audio/"); 332 mIsVideo = mMediaType.startsWith("video/"); 333 } 334 335 protected final String mCodecName; 336 protected final String mMediaType; 337 protected final String mAllTestParams; // logging 338 339 protected final boolean mIsAudio; 340 protected final boolean mIsVideo; 341 protected final CodecAsyncHandler mAsyncHandle; 342 protected boolean mIsCodecInAsyncMode; 343 protected boolean mSawInputEOS; 344 protected boolean mSawOutputEOS; 345 protected boolean mSignalEOSWithLastFrame; 346 protected int mInputCount; 347 protected int mOutputCount; 348 protected long mPrevOutputPts; 349 protected boolean mSignalledOutFormatChanged; 350 protected MediaFormat mOutFormat; 351 352 protected StringBuilder mTestConfig = new StringBuilder(); 353 protected StringBuilder mTestEnv = new StringBuilder(); 354 355 protected boolean mSaveToMem; 356 protected OutputManager mOutputBuff; 357 358 protected MediaCodec mCodec; 359 protected Surface mSurface; 360 // NOTE: mSurface is a place holder of current Surface used by the CodecTestBase. 361 // This doesn't own the handle. The ownership with instances that manage 362 // SurfaceView or TextureView, ... They hold the responsibility of calling release(). 363 protected CodecTestActivity mActivity; 364 365 public static final MediaCodecList MEDIA_CODEC_LIST_ALL; 366 public static final MediaCodecList MEDIA_CODEC_LIST_REGULAR; 367 static { 368 MEDIA_CODEC_LIST_ALL = new MediaCodecList(MediaCodecList.ALL_CODECS); 369 MEDIA_CODEC_LIST_REGULAR = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 370 IS_HDR_CAPTURE_SUPPORTED = isHDRCaptureSupported(); 371 IS_HDR_EDITING_SUPPORTED = isHDREditingSupported(); 372 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vp8", MediaFormat.MIMETYPE_VIDEO_VP8); 373 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vp9", MediaFormat.MIMETYPE_VIDEO_VP9); 374 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("av1", MediaFormat.MIMETYPE_VIDEO_AV1); 375 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("avc", MediaFormat.MIMETYPE_VIDEO_AVC); 376 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("hevc", MediaFormat.MIMETYPE_VIDEO_HEVC); 377 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("mpeg4", MediaFormat.MIMETYPE_VIDEO_MPEG4); 378 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("h263", MediaFormat.MIMETYPE_VIDEO_H263); 379 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("mpeg2", MediaFormat.MIMETYPE_VIDEO_MPEG2); 380 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vraw", MediaFormat.MIMETYPE_VIDEO_RAW); 381 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("amrnb", MediaFormat.MIMETYPE_AUDIO_AMR_NB); 382 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("amrwb", MediaFormat.MIMETYPE_AUDIO_AMR_WB); 383 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("mp3", MediaFormat.MIMETYPE_AUDIO_MPEG); 384 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("aac", MediaFormat.MIMETYPE_AUDIO_AAC); 385 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vorbis", MediaFormat.MIMETYPE_AUDIO_VORBIS); 386 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("opus", MediaFormat.MIMETYPE_AUDIO_OPUS); 387 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("g711alaw", MediaFormat.MIMETYPE_AUDIO_G711_ALAW); 388 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("g711mlaw", MediaFormat.MIMETYPE_AUDIO_G711_MLAW); 389 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("araw", MediaFormat.MIMETYPE_AUDIO_RAW); 390 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("flac", MediaFormat.MIMETYPE_AUDIO_FLAC); 391 CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("gsm", MediaFormat.MIMETYPE_AUDIO_MSGSM); 392 393 android.os.Bundle args = InstrumentationRegistry.getArguments(); 394 mediaTypeSelKeys = args.getString(MEDIA_TYPE_SEL_KEY); 395 codecPrefix = args.getString(CODEC_PREFIX_KEY); 396 mediaTypePrefix = args.getString(MEDIA_TYPE_PREFIX_KEY); 397 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_SDR_PROFILES)398 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_SDR_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_SDR_PROFILES)399 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_SDR_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES)400 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES)401 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES)402 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES)403 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_SDR_PROFILES)404 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_SDR_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_SDR_PROFILES)405 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_SDR_PROFILES); PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES)406 PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES); 407 PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HLG_PROFILES)408 PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HLG_PROFILES); PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HLG_PROFILES)409 PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HLG_PROFILES); PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HLG_PROFILES)410 PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HLG_PROFILES); PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HLG_PROFILES)411 PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HLG_PROFILES); 412 PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PROFILES)413 PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PROFILES); PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PROFILES)414 PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PROFILES); PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PROFILES)415 PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PROFILES); 416 PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PLUS_PROFILES)417 PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PLUS_PROFILES); PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PLUS_PROFILES)418 PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PLUS_PROFILES); PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PLUS_PROFILES)419 PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PLUS_PROFILES); 420 PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HDR_PROFILES)421 PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HDR_PROFILES); PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR_PROFILES)422 PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR_PROFILES); PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR_PROFILES)423 PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR_PROFILES); PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR_PROFILES)424 PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR_PROFILES); 425 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_PROFILES)426 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_PROFILES)427 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES)428 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES)429 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES)430 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES)431 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_PROFILES)432 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_PROFILES)433 PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_PROFILES); PROFILE_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES)434 PROFILE_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES); 435 436 HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_AV1); 437 HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_AVC); 438 HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_HEVC); 439 } 440 combine(int[] first, int[] second)441 static int[] combine(int[] first, int[] second) { 442 int[] result = Arrays.copyOf(first, first.length + second.length); 443 System.arraycopy(second, 0, result, first.length, second.length); 444 return result; 445 } 446 isMediaTypeLossless(String mediaType)447 public static boolean isMediaTypeLossless(String mediaType) { 448 if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) return true; 449 if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)) return true; 450 return false; 451 } 452 453 // some media types decode a pre-roll amount before playback. This would mean that decoding 454 // after seeking may not return the exact same values as would be obtained by decoding the 455 // stream straight through isMediaTypeOutputUnAffectedBySeek(String mediaType)456 public static boolean isMediaTypeOutputUnAffectedBySeek(String mediaType) { 457 if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) return true; 458 if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)) return true; 459 if (mediaType.startsWith("video/")) return true; 460 return false; 461 } 462 hasDecoder(String mediaType)463 public static boolean hasDecoder(String mediaType) { 464 return CodecTestBase.selectCodecs(mediaType, null, null, false).size() != 0; 465 } 466 hasEncoder(String mediaType)467 public static boolean hasEncoder(String mediaType) { 468 return CodecTestBase.selectCodecs(mediaType, null, null, true).size() != 0; 469 } 470 checkFormatSupport(String codecName, String mediaType, boolean isEncoder, ArrayList<MediaFormat> formats, String[] features, SupportClass supportRequirements)471 public static void checkFormatSupport(String codecName, String mediaType, boolean isEncoder, 472 ArrayList<MediaFormat> formats, String[] features, SupportClass supportRequirements) 473 throws IOException { 474 if (!areFormatsSupported(codecName, mediaType, formats)) { 475 switch (supportRequirements) { 476 case CODEC_ALL: 477 fail("format(s) not supported by codec: " + codecName + " for mediaType : " 478 + mediaType + " formats: " + formats); 479 break; 480 case CODEC_ANY: 481 if (selectCodecs(mediaType, formats, features, isEncoder).isEmpty()) { 482 fail("format(s) not supported by any component for mediaType : " + mediaType 483 + " formats: " + formats); 484 } 485 break; 486 case CODEC_DEFAULT: 487 if (isDefaultCodec(codecName, mediaType, isEncoder)) { 488 fail("format(s) not supported by default codec : " + codecName 489 + "for mediaType : " + mediaType + " formats: " + formats); 490 } 491 break; 492 case CODEC_HW: 493 if (isHardwareAcceleratedCodec(codecName)) { 494 fail("format(s) not supported by codec: " + codecName + " for mediaType : " 495 + mediaType + " formats: " + formats); 496 } 497 break; 498 case CODEC_SHOULD: 499 Assume.assumeTrue(String.format("format(s) not supported by codec: %s for" 500 + " mediaType : %s. It is recommended to support it", 501 codecName, mediaType), false); 502 break; 503 case CODEC_HW_RECOMMENDED: 504 Assume.assumeTrue(String.format( 505 "format(s) not supported by codec: %s for mediaType : %s. It is %s " 506 + "recommended to support it", codecName, mediaType, 507 isHardwareAcceleratedCodec(codecName) ? "strongly" : ""), false); 508 break; 509 case CODEC_OPTIONAL: 510 default: 511 // the later assumeTrue() ensures we skip the test for unsupported codecs 512 break; 513 } 514 Assume.assumeTrue("format(s) not supported by codec: " + codecName + " for mediaType : " 515 + mediaType, false); 516 } 517 } 518 isFeatureSupported(String name, String mediaType, String feature)519 public static boolean isFeatureSupported(String name, String mediaType, String feature) 520 throws IOException { 521 MediaCodec codec = MediaCodec.createByCodecName(name); 522 MediaCodecInfo.CodecCapabilities codecCapabilities = 523 codec.getCodecInfo().getCapabilitiesForType(mediaType); 524 boolean isSupported = codecCapabilities.isFeatureSupported(feature); 525 codec.release(); 526 return isSupported; 527 } 528 isHDRCaptureSupported()529 public static boolean isHDRCaptureSupported() { 530 // If the device supports HDR, hlg support should always return true 531 if (!MediaUtils.hasCamera()) return false; 532 CameraManager cm = CONTEXT.getSystemService(CameraManager.class); 533 try { 534 String[] cameraIds = cm.getCameraIdList(); 535 for (String id : cameraIds) { 536 CameraCharacteristics ch = cm.getCameraCharacteristics(id); 537 int[] caps = ch.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 538 if (IntStream.of(caps).anyMatch(x -> x 539 == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) { 540 Set<Long> profiles = 541 ch.get(CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES) 542 .getSupportedProfiles(); 543 if (profiles.contains(DynamicRangeProfiles.HLG10)) return true; 544 } 545 } 546 } catch (CameraAccessException e) { 547 Log.e(LOG_TAG, "encountered " + e.getMessage() 548 + " marking hdr capture to be available to catch your attention"); 549 return true; 550 } 551 return false; 552 } 553 isHDREditingSupported()554 public static boolean isHDREditingSupported() { 555 for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_REGULAR.getCodecInfos()) { 556 if (!codecInfo.isEncoder()) { 557 continue; 558 } 559 for (String mediaType : codecInfo.getSupportedTypes()) { 560 CodecCapabilities caps = codecInfo.getCapabilitiesForType(mediaType); 561 if (caps != null && caps.isFeatureSupported(FEATURE_HdrEditing)) { 562 return true; 563 } 564 } 565 } 566 return false; 567 } 568 doesAnyFormatHaveHDRProfile(String mediaType, ArrayList<MediaFormat> formats)569 public static boolean doesAnyFormatHaveHDRProfile(String mediaType, 570 ArrayList<MediaFormat> formats) { 571 int[] profileArray = PROFILE_HDR_MAP.get(mediaType); 572 if (profileArray != null) { 573 for (MediaFormat format : formats) { 574 assertEquals(mediaType, format.getString(MediaFormat.KEY_MIME)); 575 int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1); 576 if (IntStream.of(profileArray).anyMatch(x -> x == profile)) return true; 577 } 578 } 579 return false; 580 } 581 doesCodecSupportHDRProfile(String codecName, String mediaType)582 public static boolean doesCodecSupportHDRProfile(String codecName, String mediaType) { 583 int[] hdrProfiles = PROFILE_HDR_MAP.get(mediaType); 584 if (hdrProfiles == null) { 585 return false; 586 } 587 for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_REGULAR.getCodecInfos()) { 588 if (!codecName.equals(codecInfo.getName())) { 589 continue; 590 } 591 CodecCapabilities caps = codecInfo.getCapabilitiesForType(mediaType); 592 if (caps == null) { 593 return false; 594 } 595 for (CodecProfileLevel pl : caps.profileLevels) { 596 if (IntStream.of(hdrProfiles).anyMatch(x -> x == pl.profile)) { 597 return true; 598 } 599 } 600 } 601 return false; 602 } 603 canDisplaySupportHDRContent()604 public static boolean canDisplaySupportHDRContent() { 605 DisplayManager displayManager = CONTEXT.getSystemService(DisplayManager.class); 606 return displayManager.getDisplay(Display.DEFAULT_DISPLAY).getHdrCapabilities() 607 .getSupportedHdrTypes().length > 0; 608 } 609 areFormatsSupported(String name, String mediaType, ArrayList<MediaFormat> formats)610 public static boolean areFormatsSupported(String name, String mediaType, 611 ArrayList<MediaFormat> formats) throws IOException { 612 MediaCodec codec = MediaCodec.createByCodecName(name); 613 MediaCodecInfo.CodecCapabilities codecCapabilities = 614 codec.getCodecInfo().getCapabilitiesForType(mediaType); 615 boolean isSupported = true; 616 if (formats != null) { 617 for (int i = 0; i < formats.size() && isSupported; i++) { 618 isSupported = codecCapabilities.isFormatSupported(formats.get(i)); 619 } 620 } 621 codec.release(); 622 return isSupported; 623 } 624 hasSupportForColorFormat(String name, String mediaType, int colorFormat)625 public static boolean hasSupportForColorFormat(String name, String mediaType, int colorFormat) 626 throws IOException { 627 MediaCodec codec = MediaCodec.createByCodecName(name); 628 MediaCodecInfo.CodecCapabilities cap = 629 codec.getCodecInfo().getCapabilitiesForType(mediaType); 630 boolean hasSupport = false; 631 for (int c : cap.colorFormats) { 632 if (c == colorFormat) { 633 hasSupport = true; 634 break; 635 } 636 } 637 codec.release(); 638 return hasSupport; 639 } 640 isDefaultCodec(String codecName, String mediaType, boolean isEncoder)641 public static boolean isDefaultCodec(String codecName, String mediaType, boolean isEncoder) 642 throws IOException { 643 Map<String, String> mDefaultCodecs = isEncoder ? DEFAULT_ENCODERS : DEFAULT_DECODERS; 644 if (mDefaultCodecs.containsKey(mediaType)) { 645 return mDefaultCodecs.get(mediaType).equalsIgnoreCase(codecName); 646 } 647 MediaCodec codec = isEncoder ? MediaCodec.createEncoderByType(mediaType) 648 : MediaCodec.createDecoderByType(mediaType); 649 boolean isDefault = codec.getName().equalsIgnoreCase(codecName); 650 mDefaultCodecs.put(mediaType, codec.getName()); 651 codec.release(); 652 return isDefault; 653 } 654 isVendorCodec(String codecName)655 public static boolean isVendorCodec(String codecName) { 656 for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) { 657 if (codecName.equals(codecInfo.getName())) { 658 return codecInfo.isVendor(); 659 } 660 } 661 return false; 662 } 663 isSoftwareCodec(String codecName)664 public static boolean isSoftwareCodec(String codecName) { 665 for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) { 666 if (codecName.equals(codecInfo.getName())) { 667 return codecInfo.isSoftwareOnly(); 668 } 669 } 670 return false; 671 } 672 isHardwareAcceleratedCodec(String codecName)673 public static boolean isHardwareAcceleratedCodec(String codecName) { 674 for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) { 675 if (codecName.equals(codecInfo.getName())) { 676 return codecInfo.isHardwareAccelerated(); 677 } 678 } 679 return false; 680 } 681 paramToString(Object[] param)682 protected static String paramToString(Object[] param) { 683 StringBuilder paramStr = new StringBuilder("[ "); 684 for (int j = 0; j < param.length - 1; j++) { 685 Object o = param[j]; 686 if (o == null) { 687 paramStr.append("null, "); 688 } else if (o instanceof String[]) { 689 int length = Math.min(((String[]) o).length, 3); 690 paramStr.append("{"); 691 for (int i = 0; i < length; i++) { 692 paramStr.append(((String[]) o)[i]).append(", "); 693 } 694 paramStr.delete(paramStr.length() - 2, paramStr.length()) 695 .append(length == ((String[]) o).length ? "}, " : ", ... }, "); 696 } else if (o instanceof int[]) { 697 paramStr.append("{"); 698 for (int i = 0; i < ((int[]) o).length; i++) { 699 paramStr.append(((int[]) o)[i]).append(", "); 700 } 701 paramStr.delete(paramStr.length() - 2, paramStr.length()).append("}, "); 702 } else if (o instanceof Map) { 703 int length = 0; 704 paramStr.append("{ "); 705 Map map = (Map) o; 706 for (Object key : map.keySet()) { 707 paramStr.append(key).append(" = ").append(map.get(key)).append(", "); 708 length++; 709 if (length > 1) break; 710 } 711 paramStr.delete(paramStr.length() - 2, paramStr.length()) 712 .append(length == map.size() ? "}, " : ", ... }, "); 713 } else if (o instanceof EncoderConfigParams[]) { 714 int length = Math.min(((EncoderConfigParams[]) o).length, 3); 715 paramStr.append("{"); 716 for (int i = 0; i < ((EncoderConfigParams[]) o).length; i++) { 717 paramStr.append(((EncoderConfigParams[]) o)[i]).append(", "); 718 } 719 paramStr.delete(paramStr.length() - 2, paramStr.length()) 720 .append(length == ((EncoderConfigParams[]) o).length ? "}, " : ", ... }, "); 721 } else paramStr.append(o).append(", "); 722 } 723 paramStr.delete(paramStr.length() - 2, paramStr.length()).append(" ]"); 724 return paramStr.toString(); 725 } 726 compileRequiredMediaTypeList(boolean isEncoder, boolean needAudio, boolean needVideo)727 public static ArrayList<String> compileRequiredMediaTypeList(boolean isEncoder, 728 boolean needAudio, boolean needVideo) { 729 Set<String> list = new HashSet<>(); 730 if (!isEncoder) { 731 if (MediaUtils.hasAudioOutput() && needAudio) { 732 // sec 5.1.2 733 list.add(MediaFormat.MIMETYPE_AUDIO_AAC); 734 list.add(MediaFormat.MIMETYPE_AUDIO_FLAC); 735 list.add(MediaFormat.MIMETYPE_AUDIO_MPEG); 736 list.add(MediaFormat.MIMETYPE_AUDIO_VORBIS); 737 list.add(MediaFormat.MIMETYPE_AUDIO_RAW); 738 list.add(MediaFormat.MIMETYPE_AUDIO_OPUS); 739 } 740 if (MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv() 741 || MediaUtils.isAutomotive()) { 742 // sec 2.2.2, 2.3.2, 2.5.2 743 if (needAudio) { 744 list.add(MediaFormat.MIMETYPE_AUDIO_AAC); 745 } 746 if (needVideo) { 747 list.add(MediaFormat.MIMETYPE_VIDEO_AVC); 748 list.add(MediaFormat.MIMETYPE_VIDEO_MPEG4); 749 list.add(MediaFormat.MIMETYPE_VIDEO_H263); 750 list.add(MediaFormat.MIMETYPE_VIDEO_VP8); 751 list.add(MediaFormat.MIMETYPE_VIDEO_VP9); 752 } 753 } 754 if (MediaUtils.isHandheld() || MediaUtils.isTablet()) { 755 // sec 2.2.2 756 if (needAudio) { 757 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_NB); 758 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_WB); 759 } 760 if (needVideo) { 761 list.add(MediaFormat.MIMETYPE_VIDEO_HEVC); 762 if (IS_AT_LEAST_U) { 763 list.add(MediaFormat.MIMETYPE_VIDEO_AV1); 764 } 765 } 766 } 767 if (MediaUtils.isTv() && needVideo) { 768 // sec 2.3.2 769 list.add(MediaFormat.MIMETYPE_VIDEO_HEVC); 770 list.add(MediaFormat.MIMETYPE_VIDEO_MPEG2); 771 if (IS_AT_LEAST_U) { 772 list.add(MediaFormat.MIMETYPE_VIDEO_AV1); 773 } 774 } 775 } else { 776 if (MediaUtils.hasMicrophone() && needAudio) { 777 // sec 5.1.1 778 // TODO(b/154423550) 779 // list.add(MediaFormat.MIMETYPE_AUDIO_RAW); 780 list.add(MediaFormat.MIMETYPE_AUDIO_FLAC); 781 list.add(MediaFormat.MIMETYPE_AUDIO_OPUS); 782 } 783 if (MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv() 784 || MediaUtils.isAutomotive()) { 785 // sec 2.2.2, 2.3.2, 2.5.2 786 if (needAudio) { 787 list.add(MediaFormat.MIMETYPE_AUDIO_AAC); 788 } 789 if (needVideo) { 790 if ((MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv()) 791 && IS_AT_LEAST_U) { 792 list.add(MediaFormat.MIMETYPE_VIDEO_AV1); 793 } 794 list.add(MediaFormat.MIMETYPE_VIDEO_AVC); 795 list.add(MediaFormat.MIMETYPE_VIDEO_VP8); 796 } 797 } 798 if ((MediaUtils.isHandheld() || MediaUtils.isTablet()) && needAudio) { 799 // sec 2.2.2 800 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_NB); 801 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_WB); 802 } 803 } 804 return new ArrayList<>(list); 805 } 806 compileCompleteTestMediaTypesList(boolean isEncoder, boolean needAudio, boolean needVideo)807 private static ArrayList<String> compileCompleteTestMediaTypesList(boolean isEncoder, 808 boolean needAudio, boolean needVideo) { 809 ArrayList<String> mediaTypes = new ArrayList<>(); 810 if (mediaTypeSelKeys == null) { 811 ArrayList<String> cddRequiredMediaTypesList = 812 compileRequiredMediaTypeList(isEncoder, needAudio, needVideo); 813 MediaCodecInfo[] codecInfos = MEDIA_CODEC_LIST_REGULAR.getCodecInfos(); 814 for (MediaCodecInfo codecInfo : codecInfos) { 815 if (codecInfo.isEncoder() != isEncoder) continue; 816 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue; 817 String[] types = codecInfo.getSupportedTypes(); 818 for (String type : types) { 819 if (mediaTypePrefix != null && !type.startsWith(mediaTypePrefix)) { 820 continue; 821 } 822 if (!needAudio && type.startsWith("audio/")) continue; 823 if (!needVideo && type.startsWith("video/")) continue; 824 if (!mediaTypes.contains(type)) { 825 mediaTypes.add(type); 826 } 827 } 828 } 829 if (mediaTypePrefix != null) { 830 return mediaTypes; 831 } 832 // feature_video_output is not exposed to package manager. Testing for video output 833 // ports, such as VGA, HDMI, DisplayPort, or a wireless port for display is also not 834 // direct. 835 /* sec 5.2: device implementations include an embedded screen display with the 836 diagonal length of at least 2.5 inches or include a video output port or declare the 837 support of a camera */ 838 if (isEncoder && needVideo 839 && (MediaUtils.hasCamera() || MediaUtils.getScreenSizeInInches() >= 2.5) 840 && !mediaTypes.contains(MediaFormat.MIMETYPE_VIDEO_AVC) 841 && !mediaTypes.contains(MediaFormat.MIMETYPE_VIDEO_VP8)) { 842 // Add required cdd mediaTypes here so that respective codec tests fail. 843 mediaTypes.add(MediaFormat.MIMETYPE_VIDEO_AVC); 844 mediaTypes.add(MediaFormat.MIMETYPE_VIDEO_VP8); 845 Log.e(LOG_TAG, "device must support at least one of VP8 or AVC video encoders"); 846 } 847 for (String mediaType : cddRequiredMediaTypesList) { 848 if (!mediaTypes.contains(mediaType)) { 849 // Add required cdd mediaTypes here so that respective codec tests fail. 850 mediaTypes.add(mediaType); 851 Log.e(LOG_TAG, "no codec found for mediaType " + mediaType 852 + " as required by cdd"); 853 } 854 } 855 } else { 856 for (Map.Entry<String, String> entry : CODEC_SEL_KEY_MEDIA_TYPE_MAP.entrySet()) { 857 String key = entry.getKey(); 858 String value = entry.getValue(); 859 if (mediaTypeSelKeys.contains(key) && !mediaTypes.contains(value)) { 860 mediaTypes.add(value); 861 } 862 } 863 } 864 return mediaTypes; 865 } 866 prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs)867 public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList, 868 boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs) { 869 return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, 870 mustTestAllCodecs, ComponentClass.ALL); 871 } 872 prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs, ComponentClass selectSwitch)873 public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList, 874 boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs, 875 ComponentClass selectSwitch) { 876 ArrayList<String> mediaTypes = compileCompleteTestMediaTypesList(isEncoder, 877 needAudio, needVideo); 878 ArrayList<String> cddRequiredMediaTypesList = 879 compileRequiredMediaTypeList(isEncoder, needAudio, needVideo); 880 final List<Object[]> argsList = new ArrayList<>(); 881 int argLength = exhaustiveArgsList.get(0).length; 882 for (String mediaType : mediaTypes) { 883 ArrayList<String> totalListOfCodecs = 884 selectCodecs(mediaType, null, null, isEncoder, selectSwitch); 885 ArrayList<String> listOfCodecs = new ArrayList<>(); 886 if (codecPrefix != null) { 887 for (String codec : totalListOfCodecs) { 888 if (codec.startsWith(codecPrefix)) { 889 listOfCodecs.add(codec); 890 } 891 } 892 } else { 893 listOfCodecs = totalListOfCodecs; 894 } 895 if (mustTestAllCodecs && listOfCodecs.size() == 0 && codecPrefix == null) { 896 listOfCodecs.add(INVALID_CODEC + mediaType); 897 } 898 boolean miss = true; 899 for (Object[] arg : exhaustiveArgsList) { 900 if (mediaType.equals(arg[0])) { 901 for (String codec : listOfCodecs) { 902 Object[] argUpdate = new Object[argLength + 2]; 903 argUpdate[0] = codec; 904 System.arraycopy(arg, 0, argUpdate, 1, argLength); 905 argUpdate[argLength + 1] = paramToString(argUpdate); 906 argsList.add(argUpdate); 907 } 908 miss = false; 909 } 910 } 911 if (miss && mustTestAllCodecs) { 912 if (!cddRequiredMediaTypesList.contains(mediaType)) { 913 Log.w(LOG_TAG, "no test vectors available for optional mediaType type " 914 + mediaType); 915 continue; 916 } 917 for (String codec : listOfCodecs) { 918 Object[] argUpdate = new Object[argLength + 2]; 919 argUpdate[0] = codec; 920 argUpdate[1] = mediaType; 921 System.arraycopy(exhaustiveArgsList.get(0), 1, argUpdate, 2, argLength - 1); 922 argUpdate[argLength + 1] = paramToString(argUpdate); 923 argsList.add(argUpdate); 924 } 925 } 926 } 927 return argsList; 928 } 929 selectCodecs(String mediaType, ArrayList<MediaFormat> formats, String[] features, boolean isEncoder)930 public static ArrayList<String> selectCodecs(String mediaType, ArrayList<MediaFormat> formats, 931 String[] features, boolean isEncoder) { 932 return selectCodecs(mediaType, formats, features, isEncoder, ComponentClass.ALL); 933 } 934 selectCodecs(String mediaType, ArrayList<MediaFormat> formats, String[] features, boolean isEncoder, ComponentClass selectSwitch)935 public static ArrayList<String> selectCodecs(String mediaType, ArrayList<MediaFormat> formats, 936 String[] features, boolean isEncoder, ComponentClass selectSwitch) { 937 MediaCodecInfo[] codecInfos = MEDIA_CODEC_LIST_REGULAR.getCodecInfos(); 938 ArrayList<String> listOfCodecs = new ArrayList<>(); 939 for (MediaCodecInfo codecInfo : codecInfos) { 940 if (codecInfo.isEncoder() != isEncoder) continue; 941 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue; 942 if (selectSwitch == ComponentClass.HARDWARE && !codecInfo.isHardwareAccelerated()) { 943 continue; 944 } else if (selectSwitch == ComponentClass.SOFTWARE && !codecInfo.isSoftwareOnly()) { 945 continue; 946 } 947 String[] types = codecInfo.getSupportedTypes(); 948 for (String type : types) { 949 if (type.equalsIgnoreCase(mediaType)) { 950 boolean isOk = true; 951 MediaCodecInfo.CodecCapabilities codecCapabilities = 952 codecInfo.getCapabilitiesForType(type); 953 if (formats != null) { 954 for (MediaFormat format : formats) { 955 if (!codecCapabilities.isFormatSupported(format)) { 956 isOk = false; 957 break; 958 } 959 } 960 } 961 if (features != null) { 962 for (String feature : features) { 963 if (!codecCapabilities.isFeatureSupported(feature)) { 964 isOk = false; 965 break; 966 } 967 } 968 } 969 if (isOk) listOfCodecs.add(codecInfo.getName()); 970 } 971 } 972 } 973 return listOfCodecs; 974 } 975 getWidth(MediaFormat format)976 public static int getWidth(MediaFormat format) { 977 int width = format.getInteger(MediaFormat.KEY_WIDTH, -1); 978 if (format.containsKey("crop-left") && format.containsKey("crop-right")) { 979 width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left"); 980 } 981 return width; 982 } 983 getHeight(MediaFormat format)984 public static int getHeight(MediaFormat format) { 985 int height = format.getInteger(MediaFormat.KEY_HEIGHT, -1); 986 if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) { 987 height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top"); 988 } 989 return height; 990 } 991 loadByteArrayFromString(final String str)992 public static byte[] loadByteArrayFromString(final String str) { 993 if (str == null) { 994 return null; 995 } 996 Pattern pattern = Pattern.compile("[0-9a-fA-F]{2}"); 997 Matcher matcher = pattern.matcher(str); 998 // allocate a large enough byte array first 999 byte[] tempArray = new byte[str.length() / 2]; 1000 int i = 0; 1001 while (matcher.find()) { 1002 tempArray[i++] = (byte) Integer.parseInt(matcher.group(), 16); 1003 } 1004 return Arrays.copyOfRange(tempArray, 0, i); 1005 } 1006 byteArrayToHexString(byte[] bytes)1007 public static String byteArrayToHexString(byte[] bytes) { 1008 final char[] hexArray = 1009 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 1010 char[] hexChars = new char[bytes.length * 3]; 1011 int v; 1012 for (int j = 0; j < bytes.length; j++) { 1013 v = bytes[j] & 0xFF; 1014 hexChars[j * 3] = hexArray[v >>> 4]; 1015 hexChars[j * 3 + 1] = hexArray[v & 0x0F]; 1016 hexChars[j * 3 + 2] = ' '; 1017 } 1018 return new String(hexChars); 1019 } 1020 enqueueInput(int bufferIndex)1021 protected abstract void enqueueInput(int bufferIndex) throws IOException; 1022 dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)1023 protected abstract void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info); 1024 1025 @Rule 1026 public final TestName mTestName = new TestName(); 1027 1028 @Before setUpCodecTestBase()1029 public void setUpCodecTestBase() { 1030 mTestConfig.setLength(0); 1031 mTestConfig.append("\n################## Test Details ####################\n"); 1032 mTestConfig.append("Test Name :- ").append(mTestName.getMethodName()).append("\n"); 1033 mTestConfig.append("Test Parameters :- ").append(mAllTestParams).append("\n"); 1034 if (mCodecName != null && mCodecName.startsWith(INVALID_CODEC)) { 1035 fail("no valid component available for current test \n" + mTestConfig); 1036 } 1037 } 1038 1039 @After tearDownCodecTestBase()1040 public void tearDownCodecTestBase() { 1041 mSurface = null; 1042 if (mActivity != null) { 1043 mActivity.finish(); 1044 mActivity = null; 1045 } 1046 if (mCodec != null) { 1047 mCodec.release(); 1048 mCodec = null; 1049 } 1050 } 1051 configureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame, boolean isEncoder)1052 protected void configureCodec(MediaFormat format, boolean isAsync, 1053 boolean signalEOSWithLastFrame, boolean isEncoder) { 1054 resetContext(isAsync, signalEOSWithLastFrame); 1055 mAsyncHandle.setCallBack(mCodec, isAsync); 1056 // signalEOS flag has nothing to do with configure. We are using this flag to try all 1057 // available configure apis 1058 if (signalEOSWithLastFrame) { 1059 mCodec.configure(format, mSurface, null, 1060 isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0); 1061 } else { 1062 mCodec.configure(format, mSurface, isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0, 1063 null); 1064 } 1065 mTestEnv.setLength(0); 1066 mTestEnv.append("################### Test Environment #####################\n"); 1067 mTestEnv.append(String.format("Component under test :- %s \n", mCodecName)); 1068 mTestEnv.append("Format under test :- ").append(format).append("\n"); 1069 mTestEnv.append(String.format("Component operating in :- %s mode \n", 1070 (isAsync ? "asynchronous" : "synchronous"))); 1071 mTestEnv.append(String.format("Component received input eos :- %s \n", 1072 (signalEOSWithLastFrame ? "with full buffer" : "with empty buffer"))); 1073 if (ENABLE_LOGS) { 1074 Log.v(LOG_TAG, "codec configured"); 1075 } 1076 } 1077 getOutputManager()1078 public OutputManager getOutputManager() { 1079 return mOutputBuff; 1080 } 1081 getOutputFormat()1082 public MediaFormat getOutputFormat() { 1083 return mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat() : mOutFormat; 1084 } 1085 getOutputCount()1086 public int getOutputCount() { 1087 return mOutputCount; 1088 } 1089 flushCodec()1090 protected void flushCodec() { 1091 mCodec.flush(); 1092 // TODO(b/147576107): is it ok to clearQueues right away or wait for some signal 1093 mAsyncHandle.clearQueues(); 1094 mSawInputEOS = false; 1095 mSawOutputEOS = false; 1096 mInputCount = 0; 1097 mOutputCount = 0; 1098 mPrevOutputPts = Long.MIN_VALUE; 1099 if (ENABLE_LOGS) { 1100 Log.v(LOG_TAG, "codec flushed"); 1101 } 1102 } 1103 reConfigureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame, boolean isEncoder)1104 protected void reConfigureCodec(MediaFormat format, boolean isAsync, 1105 boolean signalEOSWithLastFrame, boolean isEncoder) { 1106 /* TODO(b/147348711) */ 1107 if (false) mCodec.stop(); 1108 else mCodec.reset(); 1109 configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder); 1110 } 1111 resetContext(boolean isAsync, boolean signalEOSWithLastFrame)1112 protected void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) { 1113 mAsyncHandle.resetContext(); 1114 mIsCodecInAsyncMode = isAsync; 1115 mSawInputEOS = false; 1116 mSawOutputEOS = false; 1117 mSignalEOSWithLastFrame = signalEOSWithLastFrame; 1118 mInputCount = 0; 1119 mOutputCount = 0; 1120 mPrevOutputPts = Long.MIN_VALUE; 1121 mSignalledOutFormatChanged = false; 1122 } 1123 enqueueEOS(int bufferIndex)1124 protected void enqueueEOS(int bufferIndex) { 1125 if (!mSawInputEOS) { 1126 mCodec.queueInputBuffer(bufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 1127 mSawInputEOS = true; 1128 if (ENABLE_LOGS) { 1129 Log.v(LOG_TAG, "Queued End of Stream"); 1130 } 1131 } 1132 } 1133 doWork(int frameLimit)1134 protected void doWork(int frameLimit) throws InterruptedException, IOException { 1135 int frameCount = 0; 1136 if (mIsCodecInAsyncMode) { 1137 // dequeue output after inputEOS is expected to be done in waitForAllOutputs() 1138 while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < frameLimit) { 1139 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork(); 1140 if (element != null) { 1141 int bufferID = element.first; 1142 MediaCodec.BufferInfo info = element.second; 1143 if (info != null) { 1144 // <id, info> corresponds to output callback. Handle it accordingly 1145 dequeueOutput(bufferID, info); 1146 } else { 1147 // <id, null> corresponds to input callback. Handle it accordingly 1148 enqueueInput(bufferID); 1149 frameCount++; 1150 } 1151 } 1152 } 1153 } else { 1154 MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo(); 1155 // dequeue output after inputEOS is expected to be done in waitForAllOutputs() 1156 while (!mSawInputEOS && frameCount < frameLimit) { 1157 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US); 1158 if (outputBufferId >= 0) { 1159 dequeueOutput(outputBufferId, outInfo); 1160 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 1161 mOutFormat = mCodec.getOutputFormat(); 1162 mSignalledOutFormatChanged = true; 1163 } 1164 int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US); 1165 if (inputBufferId != -1) { 1166 enqueueInput(inputBufferId); 1167 frameCount++; 1168 } 1169 } 1170 } 1171 } 1172 queueEOS()1173 protected void queueEOS() throws InterruptedException { 1174 if (mIsCodecInAsyncMode) { 1175 while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) { 1176 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork(); 1177 if (element != null) { 1178 int bufferID = element.first; 1179 MediaCodec.BufferInfo info = element.second; 1180 if (info != null) { 1181 dequeueOutput(bufferID, info); 1182 } else { 1183 enqueueEOS(element.first); 1184 } 1185 } 1186 } 1187 } else { 1188 MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo(); 1189 while (!mSawInputEOS) { 1190 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US); 1191 if (outputBufferId >= 0) { 1192 dequeueOutput(outputBufferId, outInfo); 1193 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 1194 mOutFormat = mCodec.getOutputFormat(); 1195 mSignalledOutFormatChanged = true; 1196 } 1197 int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US); 1198 if (inputBufferId != -1) { 1199 enqueueEOS(inputBufferId); 1200 } 1201 } 1202 } 1203 } 1204 waitForAllOutputs()1205 protected void waitForAllOutputs() throws InterruptedException { 1206 if (mIsCodecInAsyncMode) { 1207 while (!mAsyncHandle.hasSeenError() && !mSawOutputEOS) { 1208 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getOutput(); 1209 if (element != null) { 1210 dequeueOutput(element.first, element.second); 1211 } 1212 } 1213 } else { 1214 MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo(); 1215 while (!mSawOutputEOS) { 1216 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US); 1217 if (outputBufferId >= 0) { 1218 dequeueOutput(outputBufferId, outInfo); 1219 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 1220 mOutFormat = mCodec.getOutputFormat(); 1221 mSignalledOutFormatChanged = true; 1222 } 1223 } 1224 } 1225 validateTestState(); 1226 } 1227 validateTestState()1228 void validateTestState() { 1229 assertFalse("Encountered error in async mode. \n" + mTestConfig + mTestEnv 1230 + mAsyncHandle.getErrMsg(), mAsyncHandle.hasSeenError()); 1231 if (mInputCount > 0) { 1232 assertTrue(String.format("fed %d input frames, received no output frames \n", 1233 mInputCount) + mTestConfig + mTestEnv, mOutputCount > 0); 1234 } 1235 /*if (mInputCount == 0 && mInputCount != mOutputCount) { 1236 String msg = String.format("The number of output frames received is not same as number " 1237 + "of input frames queued. Output count is %d, Input count is %d \n", 1238 mOutputCount, mInputCount); 1239 // check the pts lists to see what frames are dropped, the below call is needed to 1240 // get useful error messages 1241 boolean unused = mOutputBuff.isOutPtsListIdenticalToInpPtsList(true); 1242 fail(msg + mTestConfig + mTestEnv + mOutputBuff.getErrMsg()); 1243 }*/ 1244 } 1245 insertHdrDynamicInfo(byte[] info)1246 protected void insertHdrDynamicInfo(byte[] info) { 1247 final Bundle params = new Bundle(); 1248 params.putByteArray(MediaFormat.KEY_HDR10_PLUS_INFO, info); 1249 mCodec.setParameters(params); 1250 } 1251 isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat)1252 public boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) { 1253 if (inpFormat == null || outFormat == null) return false; 1254 String inpMediaType = inpFormat.getString(MediaFormat.KEY_MIME); 1255 String outMediaType = outFormat.getString(MediaFormat.KEY_MIME); 1256 // not comparing input and output mediaTypes because for a codec, mediaType is raw on one 1257 // side and encoded type on the other 1258 if (outMediaType.startsWith("audio/")) { 1259 return (inpFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -1) 1260 == outFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -2)) 1261 && (inpFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE, -1) 1262 == outFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE, -2)) 1263 && inpMediaType.startsWith("audio/"); 1264 } else if (outMediaType.startsWith("video/")) { 1265 return getWidth(inpFormat) == getWidth(outFormat) 1266 && getHeight(inpFormat) == getHeight(outFormat) 1267 && inpMediaType.startsWith("video/"); 1268 } 1269 return true; 1270 } 1271 validateMetrics(String codec)1272 protected PersistableBundle validateMetrics(String codec) { 1273 PersistableBundle metrics = mCodec.getMetrics(); 1274 assertNotNull("error! MediaCodec.getMetrics() returns null \n" + mTestConfig + mTestEnv, 1275 metrics); 1276 assertEquals("error! metrics#MetricsConstants.CODEC is not as expected \n" + mTestConfig 1277 + mTestEnv, metrics.getString(MediaCodec.MetricsConstants.CODEC), codec); 1278 assertEquals("error! metrics#MetricsConstants.MODE is not as expected \n" + mTestConfig 1279 + mTestEnv, mIsAudio ? MediaCodec.MetricsConstants.MODE_AUDIO : 1280 MediaCodec.MetricsConstants.MODE_VIDEO, 1281 metrics.getString(MediaCodec.MetricsConstants.MODE)); 1282 return metrics; 1283 } 1284 validateMetrics(String codec, MediaFormat format)1285 protected PersistableBundle validateMetrics(String codec, MediaFormat format) { 1286 PersistableBundle metrics = validateMetrics(codec); 1287 if (mIsVideo) { 1288 assertEquals("error! metrics#MetricsConstants.WIDTH is not as expected\n" + mTestConfig 1289 + mTestEnv, metrics.getInt(MediaCodec.MetricsConstants.WIDTH), 1290 getWidth(format)); 1291 assertEquals("error! metrics#MetricsConstants.HEIGHT is not as expected\n" + mTestConfig 1292 + mTestEnv, metrics.getInt(MediaCodec.MetricsConstants.HEIGHT), 1293 getHeight(format)); 1294 } 1295 assertEquals("error! metrics#MetricsConstants.SECURE is not as expected\n" + mTestConfig 1296 + mTestEnv, 0, metrics.getInt(MediaCodec.MetricsConstants.SECURE)); 1297 return metrics; 1298 } 1299 validateColorAspects(MediaFormat fmt, int range, int standard, int transfer)1300 public void validateColorAspects(MediaFormat fmt, int range, int standard, int transfer) { 1301 int colorRange = fmt.getInteger(MediaFormat.KEY_COLOR_RANGE, UNSPECIFIED); 1302 int colorStandard = fmt.getInteger(MediaFormat.KEY_COLOR_STANDARD, UNSPECIFIED); 1303 int colorTransfer = fmt.getInteger(MediaFormat.KEY_COLOR_TRANSFER, UNSPECIFIED); 1304 if (range > UNSPECIFIED) { 1305 assertEquals("error! color range mismatch \n" + mTestConfig + mTestEnv, range, 1306 colorRange); 1307 } 1308 if (standard > UNSPECIFIED) { 1309 assertEquals("error! color standard mismatch \n" + mTestConfig + mTestEnv, standard, 1310 colorStandard); 1311 } 1312 if (transfer > UNSPECIFIED) { 1313 assertEquals("error! color transfer mismatch \n" + mTestConfig + mTestEnv, transfer, 1314 colorTransfer); 1315 } 1316 } 1317 validateHDRInfo(String hdrInfoKey, ByteBuffer hdrInfoRef, ByteBuffer hdrInfoTest, Long framePts)1318 protected void validateHDRInfo(String hdrInfoKey, ByteBuffer hdrInfoRef, ByteBuffer hdrInfoTest, 1319 Long framePts) { 1320 if (!hdrInfoRef.equals(hdrInfoTest)) { 1321 StringBuilder msg = new StringBuilder( 1322 "################### Error Details #####################\n"); 1323 byte[] ref = new byte[hdrInfoRef.capacity()]; 1324 hdrInfoRef.get(ref); 1325 hdrInfoRef.rewind(); 1326 byte[] test = new byte[hdrInfoTest.capacity()]; 1327 hdrInfoTest.get(test); 1328 hdrInfoTest.rewind(); 1329 msg.append("ref info :- \n"); 1330 for (byte b : ref) { 1331 msg.append(String.format("%2x ", b)); 1332 } 1333 msg.append("\ntest info :- \n"); 1334 for (byte b : test) { 1335 msg.append(String.format("%2x ", b)); 1336 } 1337 fail("Frame pts " + framePts + ": error! mismatch seen between ref and test info of " 1338 + hdrInfoKey + "\n" + mTestConfig + mTestEnv + msg); 1339 } 1340 } 1341 validateHDRInfo(MediaFormat fmt, String hdrInfoKey, ByteBuffer hdrInfoRef, Long framePts)1342 protected void validateHDRInfo(MediaFormat fmt, String hdrInfoKey, ByteBuffer hdrInfoRef, 1343 Long framePts) { 1344 ByteBuffer hdrInfo = fmt.getByteBuffer(hdrInfoKey, null); 1345 assertNotNull("error! no " + hdrInfoKey + " present in format : " + fmt + "\n " 1346 + mTestConfig + mTestEnv, hdrInfo); 1347 validateHDRInfo(hdrInfoKey, hdrInfoRef, hdrInfo, framePts); 1348 } 1349 setUpSurface(CodecTestActivity activity)1350 protected void setUpSurface(CodecTestActivity activity) throws InterruptedException { 1351 activity.waitTillSurfaceIsCreated(); 1352 mSurface = activity.getSurface(); 1353 assertNotNull("Surface created is null \n" + mTestConfig + mTestEnv, mSurface); 1354 assertTrue("Surface created is invalid \n" + mTestConfig + mTestEnv, mSurface.isValid()); 1355 } 1356 } 1357