blob: 71cbd61cb7a2df4653c411e76d548cf165704b7a [file] [log] [blame]
/*
* Copyright (C) 2013 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.cts;
import android.content.pm.PackageManager;
import android.cts.util.MediaUtils;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.AudioCapabilities;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecInfo.VideoCapabilities;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import static android.media.MediaFormat.MIMETYPE_VIDEO_AVC;
import static android.media.MediaFormat.MIMETYPE_VIDEO_H263;
import static android.media.MediaFormat.MIMETYPE_VIDEO_HEVC;
import static android.media.MediaFormat.MIMETYPE_VIDEO_MPEG4;
import static android.media.MediaFormat.MIMETYPE_VIDEO_VP8;
import static android.media.MediaFormat.MIMETYPE_VIDEO_VP9;
import android.media.MediaPlayer;
import android.os.Build;
import android.util.Log;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
import java.util.Vector;
/**
* Basic sanity test of data returned by MediaCodeCapabilities.
*/
public class MediaCodecCapabilitiesTest extends MediaPlayerTestBase {
private static final String TAG = "MediaCodecCapabilitiesTest";
private static final int PLAY_TIME_MS = 30000;
private static final int TIMEOUT_US = 1000000; // 1 sec
private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
private final MediaCodecList mRegularCodecs =
new MediaCodecList(MediaCodecList.REGULAR_CODECS);
private final MediaCodecList mAllCodecs =
new MediaCodecList(MediaCodecList.ALL_CODECS);
private final MediaCodecInfo[] mRegularInfos =
mRegularCodecs.getCodecInfos();
private final MediaCodecInfo[] mAllInfos =
mAllCodecs.getCodecInfos();
// Android device implementations with H.264 encoders, MUST support Baseline Profile Level 3.
// SHOULD support Main Profile/ Level 4, if supported the device must also support Main
// Profile/Level 4 decoding.
public void testH264EncoderProfileAndLevel() throws Exception {
if (!MediaUtils.checkEncoder(MIMETYPE_VIDEO_AVC)) {
return; // skip
}
assertTrue(
"H.264 must support Baseline Profile Level 3",
hasEncoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3));
if (hasEncoder(MIMETYPE_VIDEO_AVC, AVCProfileMain, AVCLevel4)) {
assertTrue(
"H.264 decoder must support Main Profile Level 4 if it can encode it",
hasDecoder(MIMETYPE_VIDEO_AVC, AVCProfileMain, AVCLevel4));
}
}
// Android device implementations with H.264 decoders, MUST support Baseline Profile Level 3.
// Android Television Devices MUST support High Profile Level 4.2.
public void testH264DecoderProfileAndLevel() throws Exception {
if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_AVC)) {
return; // skip
}
assertTrue(
"H.264 must support Baseline Profile Level 3",
hasDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3));
if (isTv()) {
assertTrue(
"H.264 must support High Profile Level 4.2 on TV",
checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel42));
}
}
// Android device implementations with H.263 encoders, MUST support Level 45.
public void testH263EncoderProfileAndLevel() throws Exception {
if (!MediaUtils.checkEncoder(MIMETYPE_VIDEO_H263)) {
return; // skip
}
assertTrue(
"H.263 must support Level 45",
hasEncoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level45));
}
// Android device implementations with H.263 decoders, MUST support Level 30.
public void testH263DecoderProfileAndLevel() throws Exception {
if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_H263)) {
return; // skip
}
assertTrue(
"H.263 must support Level 30",
hasDecoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level30));
}
// Android device implementations with MPEG-4 decoders, MUST support Simple Profile Level 3.
public void testMpeg4DecoderProfileAndLevel() throws Exception {
if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_MPEG4)) {
return; // skip
}
assertTrue(
"MPEG-4 must support Simple Profile Level 3",
hasDecoder(MIMETYPE_VIDEO_MPEG4, MPEG4ProfileSimple, MPEG4Level3));
}
// Android device implementations, when supporting H.265 codec MUST support the Main Profile
// Level 3 Main tier.
// Android Television Devices MUST support the Main Profile Level 4.1 Main tier.
// When the UHD video decoding profile is supported, it MUST support Main10 Level 5 Main
// Tier profile.
public void testH265DecoderProfileAndLevel() throws Exception {
if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_HEVC)) {
return; // skip
}
assertTrue(
"H.265 must support Main Profile Main Tier Level 3",
hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel3));
if (isTv()) {
assertTrue(
"H.265 must support Main Profile Main Tier Level 4.1 on TV",
hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel41));
}
if (isTv() && MediaUtils.canDecodeVideo(MIMETYPE_VIDEO_HEVC, 3840, 2160, 30)) {
assertTrue(
"H.265 must support Main10 Profile Main Tier Level 5 if UHD is supported",
hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain10, HEVCMainTierLevel5));
}
}
public void testAvcBaseline1() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel1)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testAvcBaseline12() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel12)) {
return; // skip
}
playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
+ "&itag=160&source=youtube&user=android-device-test"
+ "&sparams=ip,ipbits,expire,id,itag,source,user"
+ "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD."
+ "702DE9BA7AF96785FD6930AD2DD693A0486C880E"
+ "&key=ik0", 256, 144, PLAY_TIME_MS);
}
public void testAvcBaseline30() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3)) {
return; // skip
}
playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
+ "&itag=18&source=youtube&user=android-device-test"
+ "&sparams=ip,ipbits,expire,id,itag,source,user"
+ "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA."
+ "7A83031734CB1EDCE06766B6228842F954927960"
+ "&key=ik0", 640, 360, PLAY_TIME_MS);
}
public void testAvcHigh31() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel31)) {
return; // skip
}
playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
+ "&itag=22&source=youtube&user=android-device-test"
+ "&sparams=ip,ipbits,expire,id,itag,source,user"
+ "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&signature=179525311196616BD8E1381759B0E5F81A9E91B5."
+ "C4A50E44059FEBCC6BBC78E3B3A4E0E0065777"
+ "&key=ik0", 1280, 720, PLAY_TIME_MS);
}
public void testAvcHigh40() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel4)) {
return; // skip
}
if (Build.VERSION.SDK_INT < 18) {
MediaUtils.skipTest(TAG, "fragmented mp4 not supported");
return;
}
playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
+ "&itag=137&source=youtube&user=android-device-test"
+ "&sparams=ip,ipbits,expire,id,itag,source,user"
+ "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&signature=B0976085596DD42DEA3F08307F76587241CB132B."
+ "043B719C039E8B92F45391ADC0BE3665E2332930"
+ "&key=ik0", 1920, 1080, PLAY_TIME_MS);
}
public void testHevcMain1() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel1)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain2() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel2)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain21() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel21)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain3() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel3)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain31() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel31)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain4() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel4)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain41() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel41)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain5() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel5)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
public void testHevcMain51() throws Exception {
if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel51)) {
return; // skip
}
// TODO: add a test stream
MediaUtils.skipTest(TAG, "no test stream");
}
private boolean checkDecoder(String mime, int profile, int level) {
if (!hasDecoder(mime, profile, level)) {
MediaUtils.skipTest(TAG, "no " + mime + " decoder for profile "
+ profile + " and level " + level);
return false;
}
return true;
}
private boolean hasDecoder(String mime, int profile, int level) {
return supports(mime, false /* isEncoder */, profile, level);
}
private boolean hasEncoder(String mime, int profile, int level) {
return supports(mime, true /* isEncoder */, profile, level);
}
private boolean supports(
String mime, boolean isEncoder, int profile, int level) {
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo info : mcl.getCodecInfos()) {
if (isEncoder != info.isEncoder()) {
continue;
}
try {
CodecCapabilities caps = info.getCapabilitiesForType(mime);
for (CodecProfileLevel pl : caps.profileLevels) {
if (pl.profile != profile) {
continue;
}
// H.263 levels are not completely ordered:
// Level45 support only implies Level10 support
if (mime.equalsIgnoreCase(MIMETYPE_VIDEO_H263)) {
if (pl.level != level && pl.level == H263Level45 && level > H263Level10) {
continue;
}
}
if (pl.level >= level) {
return true;
}
}
} catch (IllegalArgumentException e) {
}
}
return false;
}
private boolean isVideoMime(String mime) {
return mime.toLowerCase().startsWith("video/");
}
private Set<String> requiredAdaptiveFormats() {
Set<String> adaptiveFormats = new HashSet<String>();
adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_AVC);
adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_VP8);
adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_VP9);
return adaptiveFormats;
}
public void testHaveAdaptiveVideoDecoderForAllSupportedFormats() {
Set<String> supportedFormats = new HashSet<String>();
boolean skipped = true;
// gather all supported video formats
for (MediaCodecInfo info : mAllInfos) {
if (info.isEncoder()) {
continue;
}
for (String mime : info.getSupportedTypes()) {
if (isVideoMime(mime)) {
supportedFormats.add(mime);
}
}
}
// limit to CDD-required formats for now
supportedFormats.retainAll(requiredAdaptiveFormats());
// check if there is an adaptive decoder for each
for (String mime : supportedFormats) {
skipped = false;
// implicit assumption that QVGA video is always valid.
MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
format.setFeatureEnabled(CodecCapabilities.FEATURE_AdaptivePlayback, true);
String codec = mAllCodecs.findDecoderForFormat(format);
assertTrue(
"could not find adaptive decoder for " + mime, codec != null);
}
if (skipped) {
MediaUtils.skipTest("no video decoders that are required to be adaptive found");
}
}
public void testAllVideoDecodersAreAdaptive() {
Set<String> adaptiveFormats = requiredAdaptiveFormats();
boolean skipped = true;
for (MediaCodecInfo info : mAllInfos) {
if (info.isEncoder()) {
continue;
}
for (String mime : info.getSupportedTypes()) {
if (!isVideoMime(mime)
// limit to CDD-required formats for now
|| !adaptiveFormats.contains(mime)) {
continue;
}
skipped = false;
CodecCapabilities caps = info.getCapabilitiesForType(mime);
assertTrue(
info.getName() + " is not adaptive for " + mime,
caps.isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback));
}
}
if (skipped) {
MediaUtils.skipTest("no video decoders that are required to be adaptive found");
}
}
private MediaFormat createReasonableVideoFormat(
CodecCapabilities caps, String mime, boolean encoder, int width, int height) {
VideoCapabilities vidCaps = caps.getVideoCapabilities();
MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
if (encoder) {
// bitrate
int maxWidth = vidCaps.getSupportedWidths().getUpper();
int maxHeight = vidCaps.getSupportedHeightsFor(width).getUpper();
int maxRate = vidCaps.getSupportedFrameRatesFor(width, height).getUpper().intValue();
int bitrate = vidCaps.getBitrateRange().clamp(
(int)(vidCaps.getBitrateRange().getUpper()
/ Math.sqrt((double)maxWidth * maxHeight / width / height)));
Log.i(TAG, "reasonable bitrate for " + width + "x" + height + "@" + maxRate
+ " " + mime + " = " + bitrate);
format.setInteger(format.KEY_BIT_RATE, bitrate);
format.setInteger(format.KEY_FRAME_RATE, maxRate);
format.setInteger(format.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
}
return format;
}
public void testSecureCodecsAdvertiseSecurePlayback() throws IOException {
boolean skipped = true;
for (MediaCodecInfo info : mAllInfos) {
boolean isEncoder = info.isEncoder();
if (isEncoder || !info.getName().endsWith(".secure")) {
continue;
}
for (String mime : info.getSupportedTypes()) {
if (!isVideoMime(mime)) {
continue;
}
skipped = false;
CodecCapabilities caps = info.getCapabilitiesForType(mime);
assertTrue(
info.getName() + " does not advertise secure playback",
caps.isFeatureSupported(CodecCapabilities.FEATURE_SecurePlayback));
}
}
if (skipped) {
MediaUtils.skipTest("no video decoders found ending in .secure");
}
}
public void testAllNonTunneledVideoCodecsSupportFlexibleYUV() throws IOException {
boolean skipped = true;
for (MediaCodecInfo info : mAllInfos) {
boolean isEncoder = info.isEncoder();
for (String mime: info.getSupportedTypes()) {
if (!isVideoMime(mime)) {
continue;
}
CodecCapabilities caps = info.getCapabilitiesForType(mime);
if (caps.isFeatureRequired(CodecCapabilities.FEATURE_TunneledPlayback)
|| caps.isFeatureRequired(CodecCapabilities.FEATURE_SecurePlayback)) {
continue;
}
skipped = false;
boolean found = false;
for (int c : caps.colorFormats) {
if (c == caps.COLOR_FormatYUV420Flexible) {
found = true;
break;
}
}
assertTrue(
info.getName() + " does not advertise COLOR_FormatYUV420Flexible",
found);
MediaCodec codec = null;
MediaFormat format = null;
try {
codec = MediaCodec.createByCodecName(info.getName());
// implicit assumption that QVGA video is always valid.
format = createReasonableVideoFormat(caps, mime, isEncoder, 176, 144);
format.setInteger(
MediaFormat.KEY_COLOR_FORMAT,
caps.COLOR_FormatYUV420Flexible);
codec.configure(format, null /* surface */, null /* crypto */,
isEncoder ? codec.CONFIGURE_FLAG_ENCODE : 0);
MediaFormat configuredFormat =
isEncoder ? codec.getInputFormat() : codec.getOutputFormat();
Log.d(TAG, "color format is " + configuredFormat.getInteger(
MediaFormat.KEY_COLOR_FORMAT));
if (isEncoder) {
codec.start();
int ix = codec.dequeueInputBuffer(TIMEOUT_US);
assertNotNull(
info.getName() + " encoder has non-flexYUV input buffer #" + ix,
codec.getInputImage(ix));
} else {
// TODO: test these on various decoders (need test streams)
}
} finally {
if (codec != null) {
codec.release();
}
}
}
}
if (skipped) {
MediaUtils.skipTest("no non-tunneled/non-secure video decoders found");
}
}
private static MediaFormat createMinFormat(String mime, CodecCapabilities caps) {
MediaFormat format;
if (caps.getVideoCapabilities() != null) {
VideoCapabilities vcaps = caps.getVideoCapabilities();
int minWidth = vcaps.getSupportedWidths().getLower();
int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower();
int minBitrate = vcaps.getBitrateRange().getLower();
format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]);
format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
} else {
AudioCapabilities acaps = caps.getAudioCapabilities();
int minSampleRate = acaps.getSupportedSampleRateRanges()[0].getLower();
int minChannelCount = 1;
int minBitrate = acaps.getBitrateRange().getLower();
format = MediaFormat.createAudioFormat(mime, minSampleRate, minChannelCount);
format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
}
return format;
}
private static int getActualMax(
boolean isEncoder, String name, String mime, CodecCapabilities caps, int max) {
int flag = isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0;
MediaFormat format = createMinFormat(mime, caps);
Log.d(TAG, "Test format " + format);
Vector<MediaCodec> codecs = new Vector<MediaCodec>();
MediaCodec codec = null;
for (int i = 0; i < max; ++i) {
try {
Log.d(TAG, "Create codec " + name + " #" + i);
codec = MediaCodec.createByCodecName(name);
codec.configure(format, null, null, flag);
codec.start();
codecs.add(codec);
codec = null;
} catch (IllegalArgumentException e) {
fail("Got unexpected IllegalArgumentException " + e.getMessage());
} catch (IOException e) {
fail("Got unexpected IOException " + e.getMessage());
} catch (MediaCodec.CodecException e) {
// ERROR_INSUFFICIENT_RESOURCE is expected as the test keep creating codecs.
// But other exception should be treated as failure.
if (e.getErrorCode() == MediaCodec.CodecException.ERROR_INSUFFICIENT_RESOURCE) {
Log.d(TAG, "Got CodecException with ERROR_INSUFFICIENT_RESOURCE.");
break;
} else {
fail("Unexpected CodecException " + e.getDiagnosticInfo());
}
} finally {
if (codec != null) {
Log.d(TAG, "release codec");
codec.release();
codec = null;
}
}
}
int actualMax = codecs.size();
for (int i = 0; i < codecs.size(); ++i) {
Log.d(TAG, "release codec #" + i);
codecs.get(i).release();
}
codecs.clear();
return actualMax;
}
private boolean knownTypes(String type) {
return (type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3 ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3 ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263 ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2 ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4 ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8 ) ||
type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9 ));
}
public void testGetMaxSupportedInstances() {
final int MAX_INSTANCES = 32;
StringBuilder xmlOverrides = new StringBuilder();
MediaCodecList allCodecs = new MediaCodecList(MediaCodecList.ALL_CODECS);
for (MediaCodecInfo info : allCodecs.getCodecInfos()) {
Log.d(TAG, "codec: " + info.getName());
Log.d(TAG, " isEncoder = " + info.isEncoder());
String[] types = info.getSupportedTypes();
for (int j = 0; j < types.length; ++j) {
if (!knownTypes(types[j])) {
Log.d(TAG, "skipping unknown type " + types[j]);
continue;
}
Log.d(TAG, "calling getCapabilitiesForType " + types[j]);
CodecCapabilities caps = info.getCapabilitiesForType(types[j]);
int max = caps.getMaxSupportedInstances();
Log.d(TAG, "getMaxSupportedInstances returns " + max);
assertTrue(max > 0);
int actualMax = getActualMax(
info.isEncoder(), info.getName(), types[j], caps, MAX_INSTANCES);
Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) {
String codec = "<MediaCodec name=\"" + info.getName() +
"\" type=\"" + types[j] + "\" >";
String limit = " <Limit name=\"concurrent-instances\" max=\"" +
actualMax + "\" />";
xmlOverrides.append(codec);
xmlOverrides.append("\n");
xmlOverrides.append(limit);
xmlOverrides.append("\n");
xmlOverrides.append("</MediaCodec>\n");
}
}
}
if (xmlOverrides.length() > 0) {
String failMessage = "In order to pass the test, please publish following " +
"codecs' concurrent instances limit in /etc/media_codecs.xml: \n";
fail(failMessage + xmlOverrides.toString());
}
}
}