blob: 175ff541149a606728a0a570427218daa3453144 [file] [log] [blame]
/*
* Copyright (C) 2021 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.mediapc.cts.common;
import static android.util.DisplayMetrics.DENSITY_400;
import static org.junit.Assume.assumeTrue;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
import android.media.MediaFormat;
import android.os.Build;
import android.os.SystemProperties;
import android.util.Log;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiLevelUtil;
import java.io.IOException;
import java.util.List;
/**
* Test utilities.
*/
public class Utils {
private static final int sPc;
private static final String TAG = "PerformanceClassTestUtils";
private static final String MEDIA_PERF_CLASS_KEY = "media-performance-class";
public static final int DISPLAY_DPI;
public static final int MIN_DISPLAY_CANDIDATE_DPI = DENSITY_400;
public static final int DISPLAY_LONG_PIXELS;
public static final int MIN_DISPLAY_LONG_CANDIDATE_PIXELS = 1920;
public static final int DISPLAY_SHORT_PIXELS;
public static final int MIN_DISPLAY_SHORT_CANDIDATE_PIXELS = 1080;
public static final long TOTAL_MEMORY_MB;
// Media performance requires 6 GB minimum RAM, but keeping the following to 5 GB
// as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
public static final long MIN_MEMORY_PERF_CLASS_CANDIDATE_MB = 5 * 1024;
// Android T Media performance requires 8 GB min RAM, so setting lower as above
public static final long MIN_MEMORY_PERF_CLASS_T_MB = 7 * 1024;
private static final boolean MEETS_AVC_CODEC_PRECONDITIONS;
static {
// with a default-media-performance-class that can be configured through a command line
// argument.
android.os.Bundle args;
try {
args = InstrumentationRegistry.getArguments();
} catch (Exception e) {
args = null;
}
if (args != null) {
String mediaPerfClassArg = args.getString(MEDIA_PERF_CLASS_KEY);
if (mediaPerfClassArg != null) {
Log.d(TAG, "Running the tests with performance class set to " + mediaPerfClassArg);
sPc = Integer.parseInt(mediaPerfClassArg);
} else {
sPc = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)
? Build.VERSION.MEDIA_PERFORMANCE_CLASS
: SystemProperties.getInt("ro.odm.build.media_performance_class", 0);
}
Log.d(TAG, "performance class is " + sPc);
} else {
sPc = 0;
}
Context context;
try {
context = InstrumentationRegistry.getInstrumentation().getContext();
} catch (Exception e) {
context = null;
}
// When used from ItsService, context will be null
if (context != null) {
WindowManager windowManager = context.getSystemService(WindowManager.class);
WindowMetrics metrics = windowManager.getMaximumWindowMetrics();
Rect displayBounds = metrics.getBounds();
int widthPixels = displayBounds.width();
int heightPixels = displayBounds.height();
DISPLAY_DPI = context.getResources().getConfiguration().densityDpi;
DISPLAY_LONG_PIXELS = Math.max(widthPixels, heightPixels);
DISPLAY_SHORT_PIXELS = Math.min(widthPixels, heightPixels);
ActivityManager activityManager = context.getSystemService(ActivityManager.class);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
} else {
DISPLAY_DPI = 0;
DISPLAY_LONG_PIXELS = 0;
DISPLAY_SHORT_PIXELS = 0;
TOTAL_MEMORY_MB = 0;
}
MEETS_AVC_CODEC_PRECONDITIONS = meetsAvcCodecPreconditions();
}
/**
* First defined media performance class.
*/
private static final int FIRST_PERFORMANCE_CLASS = Build.VERSION_CODES.R;
public static boolean isRPerfClass() {
return sPc == Build.VERSION_CODES.R;
}
public static boolean isSPerfClass() {
return sPc == Build.VERSION_CODES.S;
}
public static boolean isTPerfClass() {
return sPc == Build.VERSION_CODES.TIRAMISU;
}
public static boolean isUPerfClass() {
return sPc == Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
}
/**
* Latest defined media performance class.
*/
private static final int LAST_PERFORMANCE_CLASS = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
public static boolean isHandheld() {
// handheld nature is not exposed to package manager, for now
// we check for touchscreen and NOT watch and NOT tv
PackageManager pm =
InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
return pm.hasSystemFeature(pm.FEATURE_TOUCHSCREEN)
&& !pm.hasSystemFeature(pm.FEATURE_WATCH)
&& !pm.hasSystemFeature(pm.FEATURE_TELEVISION)
&& !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
}
private static boolean meetsAvcCodecPreconditions(boolean isEncoder) {
// Latency tests need the following instances of codecs at 30 fps
// 1920x1080 encoder in MediaRecorder for load conditions
// 1920x1080 decoder and 1920x1080 encoder for load conditions
// 1920x1080 encoder for initialization test
// Since there is no way to know if encoder and decoder are supported concurrently at their
// maximum load, we will test the above combined requirements are met for both encoder and
// decoder (so a minimum of 4 instances required for both encoder and decoder)
int minInstancesRequired = 4;
int width = 1920;
int height = 1080;
double fps = 30 /* encoder for media recorder */
+ 30 /* 1080p decoder for transcoder */
+ 30 /* 1080p encoder for transcoder */
+ 30 /* 1080p encoder for latency test */;
String avcMediaType = MediaFormat.MIMETYPE_VIDEO_AVC;
PerformancePoint pp1080p = new PerformancePoint(width, height, (int) fps);
MediaCodec codec;
try {
codec = isEncoder ? MediaCodec.createEncoderByType(avcMediaType) :
MediaCodec.createDecoderByType(avcMediaType);
} catch (IOException e) {
Log.d(TAG, "Unable to create codec " + e);
return false;
}
MediaCodecInfo info = codec.getCodecInfo();
MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(avcMediaType);
List<PerformancePoint> pps =
caps.getVideoCapabilities().getSupportedPerformancePoints();
if (pps == null || pps.size() == 0) {
Log.w(TAG, info.getName() + " doesn't advertise performance points. Assuming codec "
+ "meets the requirements");
codec.release();
return true;
}
boolean supportsRequiredRate = false;
for (PerformancePoint pp : pps) {
if (pp.covers(pp1080p)) {
supportsRequiredRate = true;
}
}
boolean supportsRequiredSize = caps.getVideoCapabilities().isSizeSupported(width, height);
boolean supportsRequiredInstances = caps.getMaxSupportedInstances() >= minInstancesRequired;
codec.release();
Log.d(TAG, info.getName() + " supports required FPS : " + supportsRequiredRate
+ ", supports required size : " + supportsRequiredSize
+ ", supports required instances : " + supportsRequiredInstances);
return supportsRequiredRate && supportsRequiredSize && supportsRequiredInstances;
}
private static boolean meetsAvcCodecPreconditions() {
return meetsAvcCodecPreconditions(/* isEncoder */ true)
&& meetsAvcCodecPreconditions(/* isEncoder */ false);
}
public static int getPerfClass() {
return sPc;
}
public static boolean isPerfClass() {
return sPc >= FIRST_PERFORMANCE_CLASS &&
sPc <= LAST_PERFORMANCE_CLASS;
}
public static boolean meetsPerformanceClassPreconditions() {
if (isPerfClass()) {
return true;
}
// If device doesn't advertise performance class, check if this can be ruled out as a
// candidate for performance class tests.
if (!isHandheld()
|| TOTAL_MEMORY_MB < MIN_MEMORY_PERF_CLASS_CANDIDATE_MB
|| DISPLAY_DPI < MIN_DISPLAY_CANDIDATE_DPI
|| DISPLAY_LONG_PIXELS < MIN_DISPLAY_LONG_CANDIDATE_PIXELS
|| DISPLAY_SHORT_PIXELS < MIN_DISPLAY_SHORT_CANDIDATE_PIXELS
|| !MEETS_AVC_CODEC_PRECONDITIONS) {
return false;
}
return true;
}
public static void assumeDeviceMeetsPerformanceClassPreconditions() {
assumeTrue(
"Test skipped because the device does not meet the hardware requirements for "
+ "performance class.",
meetsPerformanceClassPreconditions());
}
}