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