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