1 /* 2 * Copyright (C) 2012 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.media; 18 19 import android.util.Log; 20 21 import android.media.MediaCodecInfo; 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.Map; 25 26 /** 27 * Allows you to enumerate available codecs, each specified as a {@link MediaCodecInfo} object, 28 * find a codec supporting a given format and query the capabilities 29 * of a given codec. 30 * <p>See {@link MediaCodecInfo} for sample usage. 31 */ 32 final public class MediaCodecList { 33 private static final String TAG = "MediaCodecList"; 34 35 /** 36 * Count the number of available (regular) codecs. 37 * 38 * @deprecated Use {@link #getCodecInfos} instead. 39 * 40 * @see #REGULAR_CODECS 41 */ getCodecCount()42 public static final int getCodecCount() { 43 initCodecList(); 44 return sRegularCodecInfos.length; 45 } 46 native_getCodecCount()47 private static native final int native_getCodecCount(); 48 49 /** 50 * Return the {@link MediaCodecInfo} object for the codec at 51 * the given {@code index} in the regular list. 52 * 53 * @deprecated Use {@link #getCodecInfos} instead. 54 * 55 * @see #REGULAR_CODECS 56 */ getCodecInfoAt(int index)57 public static final MediaCodecInfo getCodecInfoAt(int index) { 58 initCodecList(); 59 if (index < 0 || index > sRegularCodecInfos.length) { 60 throw new IllegalArgumentException(); 61 } 62 return sRegularCodecInfos[index]; 63 } 64 getGlobalSettings()65 /* package private */ static final Map<String, Object> getGlobalSettings() { 66 synchronized (sInitLock) { 67 if (sGlobalSettings == null) { 68 sGlobalSettings = native_getGlobalSettings(); 69 } 70 } 71 return sGlobalSettings; 72 } 73 74 private static Object sInitLock = new Object(); 75 private static MediaCodecInfo[] sAllCodecInfos; 76 private static MediaCodecInfo[] sRegularCodecInfos; 77 private static Map<String, Object> sGlobalSettings; 78 initCodecList()79 private static final void initCodecList() { 80 synchronized (sInitLock) { 81 if (sRegularCodecInfos == null) { 82 int count = native_getCodecCount(); 83 ArrayList<MediaCodecInfo> regulars = new ArrayList<MediaCodecInfo>(); 84 ArrayList<MediaCodecInfo> all = new ArrayList<MediaCodecInfo>(); 85 for (int index = 0; index < count; index++) { 86 try { 87 MediaCodecInfo info = getNewCodecInfoAt(index); 88 all.add(info); 89 info = info.makeRegular(); 90 if (info != null) { 91 regulars.add(info); 92 } 93 } catch (Exception e) { 94 Log.e(TAG, "Could not get codec capabilities", e); 95 } 96 } 97 sRegularCodecInfos = 98 regulars.toArray(new MediaCodecInfo[regulars.size()]); 99 sAllCodecInfos = 100 all.toArray(new MediaCodecInfo[all.size()]); 101 } 102 } 103 } 104 getNewCodecInfoAt(int index)105 private static MediaCodecInfo getNewCodecInfoAt(int index) { 106 String[] supportedTypes = getSupportedTypes(index); 107 MediaCodecInfo.CodecCapabilities[] caps = 108 new MediaCodecInfo.CodecCapabilities[supportedTypes.length]; 109 int typeIx = 0; 110 for (String type: supportedTypes) { 111 caps[typeIx++] = getCodecCapabilities(index, type); 112 } 113 return new MediaCodecInfo( 114 getCodecName(index), isEncoder(index), caps); 115 } 116 getCodecName(int index)117 /* package private */ static native final String getCodecName(int index); 118 isEncoder(int index)119 /* package private */ static native final boolean isEncoder(int index); 120 getSupportedTypes(int index)121 /* package private */ static native final String[] getSupportedTypes(int index); 122 123 /* package private */ static native final MediaCodecInfo.CodecCapabilities getCodecCapabilities(int index, String type)124 getCodecCapabilities(int index, String type); 125 native_getGlobalSettings()126 /* package private */ static native final Map<String, Object> native_getGlobalSettings(); 127 findCodecByName(String codec)128 /* package private */ static native final int findCodecByName(String codec); 129 130 /** @hide */ getInfoFor(String codec)131 public static MediaCodecInfo getInfoFor(String codec) { 132 initCodecList(); 133 return sAllCodecInfos[findCodecByName(codec)]; 134 } 135 native_init()136 private static native final void native_init(); 137 138 /** 139 * Use in {@link #MediaCodecList} to enumerate only codecs that are suitable 140 * for regular (buffer-to-buffer) decoding or encoding. 141 * 142 * <em>NOTE:</em> These are the codecs that are returned prior to API 21, 143 * using the now deprecated static methods. 144 */ 145 public static final int REGULAR_CODECS = 0; 146 147 /** 148 * Use in {@link #MediaCodecList} to enumerate all codecs, even ones that are 149 * not suitable for regular (buffer-to-buffer) decoding or encoding. These 150 * include codecs, for example, that only work with special input or output 151 * surfaces, such as secure-only or tunneled-only codecs. 152 * 153 * @see MediaCodecInfo.CodecCapabilities#isFormatSupported 154 * @see MediaCodecInfo.CodecCapabilities#FEATURE_SecurePlayback 155 * @see MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback 156 */ 157 public static final int ALL_CODECS = 1; 158 MediaCodecList()159 private MediaCodecList() { 160 this(REGULAR_CODECS); 161 } 162 163 private MediaCodecInfo[] mCodecInfos; 164 165 /** 166 * Create a list of media-codecs of a specific kind. 167 * @param kind Either {@code REGULAR_CODECS} or {@code ALL_CODECS}. 168 */ MediaCodecList(int kind)169 public MediaCodecList(int kind) { 170 initCodecList(); 171 if (kind == REGULAR_CODECS) { 172 mCodecInfos = sRegularCodecInfos; 173 } else { 174 mCodecInfos = sAllCodecInfos; 175 } 176 } 177 178 /** 179 * Returns the list of {@link MediaCodecInfo} objects for the list 180 * of media-codecs. 181 */ getCodecInfos()182 public final MediaCodecInfo[] getCodecInfos() { 183 return Arrays.copyOf(mCodecInfos, mCodecInfos.length); 184 } 185 186 static { 187 System.loadLibrary("media_jni"); native_init()188 native_init(); 189 190 // mediaserver is not yet alive here 191 } 192 193 /** 194 * Find a decoder supporting a given {@link MediaFormat} in the list 195 * of media-codecs. 196 * 197 * <p class=note> 198 * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, 199 * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE 200 * frame rate}. Use 201 * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> 202 * to clear any existing frame rate setting in the format. 203 * 204 * @see MediaCodecList.CodecCapabilities.isFormatSupported for format keys 205 * considered per android versions when evaluating suitable codecs. 206 * 207 * @param format A decoder media format with optional feature directives. 208 * @throws IllegalArgumentException if format is not a valid media format. 209 * @throws NullPointerException if format is null. 210 * @return the name of a decoder that supports the given format and feature 211 * requests, or {@code null} if no such codec has been found. 212 */ findDecoderForFormat(MediaFormat format)213 public final String findDecoderForFormat(MediaFormat format) { 214 return findCodecForFormat(false /* encoder */, format); 215 } 216 217 /** 218 * Find an encoder supporting a given {@link MediaFormat} in the list 219 * of media-codecs. 220 * 221 * <p class=note> 222 * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, 223 * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE 224 * frame rate}. Use 225 * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> 226 * to clear any existing frame rate setting in the format. 227 * 228 * @see MediaCodecList.CodecCapabilities.isFormatSupported for format keys 229 * considered per android versions when evaluating suitable codecs. 230 * 231 * @param format An encoder media format with optional feature directives. 232 * @throws IllegalArgumentException if format is not a valid media format. 233 * @throws NullPointerException if format is null. 234 * @return the name of an encoder that supports the given format and feature 235 * requests, or {@code null} if no such codec has been found. 236 */ findEncoderForFormat(MediaFormat format)237 public final String findEncoderForFormat(MediaFormat format) { 238 return findCodecForFormat(true /* encoder */, format); 239 } 240 findCodecForFormat(boolean encoder, MediaFormat format)241 private String findCodecForFormat(boolean encoder, MediaFormat format) { 242 String mime = format.getString(MediaFormat.KEY_MIME); 243 for (MediaCodecInfo info: mCodecInfos) { 244 if (info.isEncoder() != encoder) { 245 continue; 246 } 247 try { 248 MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime); 249 if (caps != null && caps.isFormatSupported(format)) { 250 return info.getName(); 251 } 252 } catch (IllegalArgumentException e) { 253 // type is not supported 254 } 255 } 256 return null; 257 } 258 } 259