261 lines
9.5 KiB
Java
261 lines
9.5 KiB
Java
/*
|
|
* 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 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 {@link MediaCodecList#REGULAR_CODECS} or
|
|
* {@link MediaCodecList#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;
|
|
}
|
|
}
|