MediaCodecList.java revision 217474682ab9c551f331a598cf99d4e8d50f2a8d
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    private static native final void native_init();
120
121    /**
122     * Use in {@link #MediaCodecList} to enumerate only codecs that are suitable
123     * for regular (buffer-to-buffer) decoding or encoding.
124     *
125     * <em>NOTE:</em> These are the codecs that are returned prior to API 21,
126     * using the now deprecated static methods.
127     */
128    public static final int REGULAR_CODECS = 0;
129
130    /**
131     * Use in {@link #MediaCodecList} to enumerate all codecs, even ones that are
132     * not suitable for regular (buffer-to-buffer) decoding or encoding.  These
133     * include codecs, for example, that only work with special input or output
134     * surfaces, such as secure-only or tunneled-only codecs.
135     *
136     * @see MediaCodecInfo.CodecCapabilities#isFormatSupported
137     * @see MediaCodecInfo.CodecCapabilities#FEATURE_SecurePlayback
138     * @see MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback
139     */
140    public static final int ALL_CODECS = 1;
141
142    private MediaCodecList() {
143        this(REGULAR_CODECS);
144    }
145
146    private MediaCodecInfo[] mCodecInfos;
147
148    /**
149     * Create a list of media-codecs of a specific kind.
150     * @param kind Either {@code REGULAR_CODECS} or {@code ALL_CODECS}.
151     */
152    public MediaCodecList(int kind) {
153        initCodecList();
154        if (kind == REGULAR_CODECS) {
155            mCodecInfos = sRegularCodecInfos;
156        } else {
157            mCodecInfos = sAllCodecInfos;
158        }
159    }
160
161    /**
162     * Returns the list of {@link MediaCodecInfo} objects for the list
163     * of media-codecs.
164     */
165    public final MediaCodecInfo[] getCodecInfos() {
166        return Arrays.copyOf(mCodecInfos, mCodecInfos.length);
167    }
168
169    static {
170        System.loadLibrary("media_jni");
171        native_init();
172
173        // mediaserver is not yet alive here
174    }
175
176    /**
177     * Find a decoder supporting a given {@link MediaFormat} in the list
178     * of media-codecs.
179     *
180     * @param format A decoder media format with optional feature directives.
181     * @throws IllegalArgumentException if format is not a valid media format.
182     * @throws NullPointerException if format is null.
183     * @return the name of a decoder that supports the given format and feature
184     *         requests, or {@code null} if no such codec has been found.
185     */
186    public final String findDecoderForFormat(MediaFormat format) {
187        return findCodecForFormat(false /* encoder */, format);
188    }
189
190    /**
191     * Find an encoder supporting a given {@link MediaFormat} in the list
192     * of media-codecs.
193     *
194     * @param format An encoder media format with optional feature directives.
195     * @throws IllegalArgumentException if format is not a valid media format.
196     * @throws NullPointerException if format is null.
197     * @return the name of an encoder that supports the given format and feature
198     *         requests, or {@code null} if no such codec has been found.
199     */
200    public final String findEncoderForFormat(MediaFormat format) {
201        return findCodecForFormat(false /* encoder */, format);
202    }
203
204    private String findCodecForFormat(boolean encoder, MediaFormat format) {
205        String mime = format.getString(MediaFormat.KEY_MIME);
206        for (MediaCodecInfo info: mCodecInfos) {
207            if (info.isEncoder() != encoder) {
208                continue;
209            }
210            try {
211                MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
212                if (caps != null && caps.isFormatSupported(format)) {
213                    return info.getName();
214                }
215            } catch (IllegalArgumentException e) {
216                // type is not supported
217            }
218        }
219        return null;
220    }
221}
222