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