| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.media; |
| |
| import android.util.Log; |
| |
| import android.media.MediaCodecInfo; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Map; |
| |
| /** |
| * Allows you to enumerate available codecs, each specified as a {@link MediaCodecInfo} object, |
| * find a codec supporting a given format and query the capabilities |
| * of a given codec. |
| * <p>See {@link MediaCodecInfo} for sample usage. |
| */ |
| final public class MediaCodecList { |
| private static final String TAG = "MediaCodecList"; |
| |
| /** |
| * Count the number of available (regular) codecs. |
| * |
| * @deprecated Use {@link #getCodecInfos} instead. |
| * |
| * @see #REGULAR_CODECS |
| */ |
| public static final int getCodecCount() { |
| initCodecList(); |
| return sRegularCodecInfos.length; |
| } |
| |
| private static native final int native_getCodecCount(); |
| |
| /** |
| * Return the {@link MediaCodecInfo} object for the codec at |
| * the given {@code index} in the regular list. |
| * |
| * @deprecated Use {@link #getCodecInfos} instead. |
| * |
| * @see #REGULAR_CODECS |
| */ |
| public static final MediaCodecInfo getCodecInfoAt(int index) { |
| initCodecList(); |
| if (index < 0 || index > sRegularCodecInfos.length) { |
| throw new IllegalArgumentException(); |
| } |
| return sRegularCodecInfos[index]; |
| } |
| |
| /* package private */ static final Map<String, Object> getGlobalSettings() { |
| synchronized (sInitLock) { |
| if (sGlobalSettings == null) { |
| sGlobalSettings = native_getGlobalSettings(); |
| } |
| } |
| return sGlobalSettings; |
| } |
| |
| private static Object sInitLock = new Object(); |
| private static MediaCodecInfo[] sAllCodecInfos; |
| private static MediaCodecInfo[] sRegularCodecInfos; |
| private static Map<String, Object> sGlobalSettings; |
| |
| private static final void initCodecList() { |
| synchronized (sInitLock) { |
| if (sRegularCodecInfos == null) { |
| int count = native_getCodecCount(); |
| ArrayList<MediaCodecInfo> regulars = new ArrayList<MediaCodecInfo>(); |
| ArrayList<MediaCodecInfo> all = new ArrayList<MediaCodecInfo>(); |
| for (int index = 0; index < count; index++) { |
| try { |
| MediaCodecInfo info = getNewCodecInfoAt(index); |
| all.add(info); |
| info = info.makeRegular(); |
| if (info != null) { |
| regulars.add(info); |
| } |
| } catch (Exception e) { |
| Log.e(TAG, "Could not get codec capabilities", e); |
| } |
| } |
| sRegularCodecInfos = |
| regulars.toArray(new MediaCodecInfo[regulars.size()]); |
| sAllCodecInfos = |
| all.toArray(new MediaCodecInfo[all.size()]); |
| } |
| } |
| } |
| |
| private static MediaCodecInfo getNewCodecInfoAt(int index) { |
| String[] supportedTypes = getSupportedTypes(index); |
| MediaCodecInfo.CodecCapabilities[] caps = |
| new MediaCodecInfo.CodecCapabilities[supportedTypes.length]; |
| int typeIx = 0; |
| for (String type: supportedTypes) { |
| caps[typeIx++] = getCodecCapabilities(index, type); |
| } |
| return new MediaCodecInfo( |
| getCodecName(index), getCanonicalName(index), getAttributes(index), caps); |
| } |
| |
| /* package private */ static native final String getCodecName(int index); |
| |
| /* package private */ static native final String getCanonicalName(int index); |
| |
| /* package private */ static native final int getAttributes(int index); |
| |
| /* package private */ static native final String[] getSupportedTypes(int index); |
| |
| /* package private */ static native final MediaCodecInfo.CodecCapabilities |
| getCodecCapabilities(int index, String type); |
| |
| /* package private */ static native final Map<String, Object> native_getGlobalSettings(); |
| |
| /* package private */ static native final int findCodecByName(String codec); |
| |
| /** @hide */ |
| public static MediaCodecInfo getInfoFor(String codec) { |
| initCodecList(); |
| return sAllCodecInfos[findCodecByName(codec)]; |
| } |
| |
| private static native final void native_init(); |
| |
| /** |
| * Use in {@link #MediaCodecList} to enumerate only codecs that are suitable |
| * for regular (buffer-to-buffer) decoding or encoding. |
| * |
| * <em>NOTE:</em> These are the codecs that are returned prior to API 21, |
| * using the now deprecated static methods. |
| */ |
| public static final int REGULAR_CODECS = 0; |
| |
| /** |
| * Use in {@link #MediaCodecList} to enumerate all codecs, even ones that are |
| * not suitable for regular (buffer-to-buffer) decoding or encoding. These |
| * include codecs, for example, that only work with special input or output |
| * surfaces, such as secure-only or tunneled-only codecs. |
| * |
| * @see MediaCodecInfo.CodecCapabilities#isFormatSupported |
| * @see MediaCodecInfo.CodecCapabilities#FEATURE_SecurePlayback |
| * @see MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback |
| */ |
| public static final int ALL_CODECS = 1; |
| |
| private MediaCodecList() { |
| this(REGULAR_CODECS); |
| } |
| |
| private MediaCodecInfo[] mCodecInfos; |
| |
| /** |
| * Create a list of media-codecs of a specific kind. |
| * @param kind Either {@code REGULAR_CODECS} or {@code ALL_CODECS}. |
| */ |
| public MediaCodecList(int kind) { |
| initCodecList(); |
| if (kind == REGULAR_CODECS) { |
| mCodecInfos = sRegularCodecInfos; |
| } else { |
| mCodecInfos = sAllCodecInfos; |
| } |
| } |
| |
| /** |
| * Returns the list of {@link MediaCodecInfo} objects for the list |
| * of media-codecs. |
| */ |
| public final MediaCodecInfo[] getCodecInfos() { |
| return Arrays.copyOf(mCodecInfos, mCodecInfos.length); |
| } |
| |
| static { |
| System.loadLibrary("media_jni"); |
| native_init(); |
| |
| // mediaserver is not yet alive here |
| } |
| |
| /** |
| * Find a decoder supporting a given {@link MediaFormat} in the list |
| * of media-codecs. |
| * |
| * <p class=note> |
| * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, |
| * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE |
| * frame rate}. Use |
| * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> |
| * to clear any existing frame rate setting in the format. |
| * |
| * @see MediaCodecInfo.CodecCapabilities#isFormatSupported(MediaFormat) for format keys |
| * considered per android versions when evaluating suitable codecs. |
| * |
| * @param format A decoder media format with optional feature directives. |
| * @throws IllegalArgumentException if format is not a valid media format. |
| * @throws NullPointerException if format is null. |
| * @return the name of a decoder that supports the given format and feature |
| * requests, or {@code null} if no such codec has been found. |
| */ |
| public final String findDecoderForFormat(MediaFormat format) { |
| return findCodecForFormat(false /* encoder */, format); |
| } |
| |
| /** |
| * Find an encoder supporting a given {@link MediaFormat} in the list |
| * of media-codecs. |
| * |
| * <p class=note> |
| * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, |
| * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE |
| * frame rate}. Use |
| * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> |
| * to clear any existing frame rate setting in the format. |
| * |
| * @see MediaCodecInfo.CodecCapabilities#isFormatSupported(MediaFormat) for format keys |
| * considered per android versions when evaluating suitable codecs. |
| * |
| * @param format An encoder media format with optional feature directives. |
| * @throws IllegalArgumentException if format is not a valid media format. |
| * @throws NullPointerException if format is null. |
| * @return the name of an encoder that supports the given format and feature |
| * requests, or {@code null} if no such codec has been found. |
| */ |
| public final String findEncoderForFormat(MediaFormat format) { |
| return findCodecForFormat(true /* encoder */, format); |
| } |
| |
| private String findCodecForFormat(boolean encoder, MediaFormat format) { |
| String mime = format.getString(MediaFormat.KEY_MIME); |
| for (MediaCodecInfo info: mCodecInfos) { |
| if (info.isEncoder() != encoder) { |
| continue; |
| } |
| try { |
| MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime); |
| if (caps != null && caps.isFormatSupported(format)) { |
| return info.getName(); |
| } |
| } catch (IllegalArgumentException e) { |
| // type is not supported |
| } |
| } |
| return null; |
| } |
| } |