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