1 /* 2 * Copyright (C) 2015 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 package com.android.compatibility.common.deviceinfo; 17 18 import android.annotation.TargetApi; 19 import android.media.MediaCodecInfo; 20 import android.media.MediaCodecInfo.AudioCapabilities; 21 import android.media.MediaCodecInfo.CodecCapabilities; 22 import android.media.MediaCodecInfo.CodecProfileLevel; 23 import android.media.MediaCodecInfo.VideoCapabilities; 24 import android.media.MediaCodecList; 25 import android.os.Build; 26 import android.util.Range; 27 28 import com.android.compatibility.common.util.ApiLevelUtil; 29 import com.android.compatibility.common.util.DeviceInfoStore; 30 31 import java.util.Arrays; 32 33 /** 34 * Media information collector. 35 */ 36 public final class MediaDeviceInfo extends DeviceInfo { 37 38 @Override 39 @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) collectDeviceInfo(DeviceInfoStore store)40 protected void collectDeviceInfo(DeviceInfoStore store) throws Exception { 41 MediaCodecList allCodecs = new MediaCodecList(MediaCodecList.ALL_CODECS); 42 store.startArray("media_codec_info"); 43 for (MediaCodecInfo info : allCodecs.getCodecInfos()) { 44 45 store.startGroup(); 46 store.addResult("name", info.getName()); 47 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q)) { 48 store.addResult("canonical", info.getCanonicalName()); 49 } 50 store.addResult("encoder", info.isEncoder()); 51 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q)) { 52 store.addResult("alias", info.isAlias()); 53 store.addResult("software", info.isSoftwareOnly()); 54 store.addResult("hardware", info.isHardwareAccelerated()); 55 store.addResult("vendor", info.isVendor()); 56 } 57 58 store.startArray("supported_type"); 59 for (String type : info.getSupportedTypes()) { 60 store.startGroup(); 61 store.addResult("type", type); 62 CodecCapabilities codecCapabilities = info.getCapabilitiesForType(type); 63 if (codecCapabilities.profileLevels.length > 0) { 64 store.startArray("codec_profile_level"); 65 for (CodecProfileLevel profileLevel : codecCapabilities.profileLevels) { 66 store.startGroup(); 67 store.addResult("level", profileLevel.level); 68 store.addResult("profile", profileLevel.profile); 69 store.endGroup(); 70 } 71 store.endArray(); // codec_profile_level 72 } 73 if (codecCapabilities.colorFormats.length > 0) { 74 store.addArrayResult("codec_color_format", codecCapabilities.colorFormats); 75 } 76 store.addResult("supported_secure_playback", codecCapabilities.isFeatureSupported( 77 CodecCapabilities.FEATURE_SecurePlayback)); 78 store.addResult("supported_hdr_editing", codecCapabilities.isFeatureSupported( 79 CodecCapabilities.FEATURE_HdrEditing)); 80 VideoCapabilities videoCapabilities = codecCapabilities.getVideoCapabilities(); 81 if (videoCapabilities != null) { 82 store.startGroup("supported_resolutions"); 83 store.addResult( 84 "supported_360p_30fps", 85 videoCapabilities.areSizeAndRateSupported(640, 360, 30)); 86 store.addResult( 87 "supported_480p_30fps", 88 videoCapabilities.areSizeAndRateSupported(720, 480, 30)); 89 store.addResult( 90 "supported_720p_30fps", 91 videoCapabilities.areSizeAndRateSupported(1280, 720, 30)); 92 store.addResult( 93 "supported_1080p_30fps", 94 videoCapabilities.areSizeAndRateSupported(1920, 1080, 30)); 95 // The QHD/WQHD 2560x1440 resolution is used to create YouTube and PlayMovies 96 // 2k content, so use that resolution to determine if a device supports 2k. 97 store.addResult( 98 "supported_2k_30fps", 99 videoCapabilities.areSizeAndRateSupported(2560, 1440, 30)); 100 store.addResult( 101 "supported_4k_30fps", 102 videoCapabilities.areSizeAndRateSupported(3840, 2160, 30)); 103 store.addResult( 104 "supported_8k_30fps", 105 videoCapabilities.areSizeAndRateSupported(7680, 4320, 30)); 106 store.addResult( 107 "supported_360p_60fps", 108 videoCapabilities.areSizeAndRateSupported(640, 360, 60)); 109 store.addResult( 110 "supported_480p_60fps", 111 videoCapabilities.areSizeAndRateSupported(720, 480, 60)); 112 store.addResult( 113 "supported_720p_60fps", 114 videoCapabilities.areSizeAndRateSupported(1280, 720, 60)); 115 store.addResult( 116 "supported_1080p_60fps", 117 videoCapabilities.areSizeAndRateSupported(1920, 1080, 60)); 118 store.addResult( 119 "supported_2k_60fps", 120 videoCapabilities.areSizeAndRateSupported(2560, 1440, 60)); 121 store.addResult( 122 "supported_4k_60fps", 123 videoCapabilities.areSizeAndRateSupported(3840, 2160, 60)); 124 store.addResult( 125 "supported_8k_60fps", 126 videoCapabilities.areSizeAndRateSupported(7680, 4320, 60)); 127 store.endGroup(); // supported_resolutions 128 store.addResult("width_alignment", videoCapabilities.getWidthAlignment()); 129 store.addResult("height_alignment", videoCapabilities.getHeightAlignment()); 130 // get min & max resolution 131 Range<Integer> widthRange = videoCapabilities.getSupportedWidths(); 132 int minWidth = widthRange.getLower(); 133 int minPixelCount = minWidth 134 * videoCapabilities.getSupportedHeightsFor(minWidth).getLower(); 135 int maxWidth = widthRange.getUpper(); 136 int maxPixelCount = maxWidth 137 * videoCapabilities.getSupportedHeightsFor(maxWidth).getUpper(); 138 store.addResult("min_pixel_count", minPixelCount); 139 store.addResult("max_pixel_count", maxPixelCount); 140 } 141 AudioCapabilities audioCapabilities = codecCapabilities.getAudioCapabilities(); 142 if (audioCapabilities != null) { 143 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q)) { 144 int minSampleRate = -1, maxSampleRate = -1; 145 int[] discreteSampleRates = audioCapabilities.getSupportedSampleRates(); 146 if (discreteSampleRates != null) { // codec supports only discrete sample rates 147 minSampleRate = Arrays.stream(discreteSampleRates).min().getAsInt(); 148 maxSampleRate = Arrays.stream(discreteSampleRates).max().getAsInt(); 149 } else { // codec supports continuous sample rates 150 Range<Integer>[] sampleRateRanges = 151 audioCapabilities.getSupportedSampleRateRanges(); 152 minSampleRate = sampleRateRanges[0].getLower(); 153 maxSampleRate = sampleRateRanges[sampleRateRanges.length - 1].getUpper(); 154 } 155 store.addResult("min_sample_rate", minSampleRate); 156 store.addResult("max_sample_rate", maxSampleRate); 157 } 158 159 store.addResult("max_channel_count", 160 audioCapabilities.getMaxInputChannelCount()); 161 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 162 store.addResult("min_channel_count", 163 audioCapabilities.getMinInputChannelCount()); 164 } 165 } 166 store.endGroup(); 167 } 168 store.endArray(); 169 store.endGroup(); 170 } 171 172 store.endArray(); // media_codec_profile 173 } 174 } 175