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