• 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 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