blob: d3fd2921d5a952a50a8ef25b2788bc34261ca3e3 [file] [log] [blame]
/*
* Copyright (C) 2022 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 Licnse.
*/
package android.mediapc.cts.common;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
import android.hardware.camera2.CameraMetadata;
import android.media.MediaFormat;
import android.os.Build;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.rules.TestName;
import java.util.HashSet;
import java.util.Set;
/**
* Logs a set of measurements and results for defined performance class requirements.
*/
public class PerformanceClassEvaluator {
private static final String TAG = PerformanceClassEvaluator.class.getSimpleName();
private final String mTestName;
private Set<Requirement> mRequirements;
public PerformanceClassEvaluator(TestName testName) {
Preconditions.checkNotNull(testName);
this.mTestName = testName.getMethodName();
this.mRequirements = new HashSet<Requirement>();
}
// used for requirements [7.1.1.1/H-1-1], [7.1.1.1/H-2-1]
public static class ResolutionRequirement extends Requirement {
private static final String TAG = ResolutionRequirement.class.getSimpleName();
private ResolutionRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setLongResolution(int longResolution) {
this.<Integer>setMeasuredValue(RequirementConstants.LONG_RESOLUTION, longResolution);
}
public void setShortResolution(int shortResolution) {
this.<Integer>setMeasuredValue(RequirementConstants.SHORT_RESOLUTION, shortResolution);
}
/**
* [7.1.1.1/H-1-1] MUST have screen resolution of at least 1080p.
*/
public static ResolutionRequirement createR7_1_1_1__H_1_1() {
RequiredMeasurement<Integer> long_resolution = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.LONG_RESOLUTION)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.R, 1920)
.build();
RequiredMeasurement<Integer> short_resolution = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.SHORT_RESOLUTION)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.R, 1080)
.build();
return new ResolutionRequirement(RequirementConstants.R7_1_1_1__H_1_1, long_resolution,
short_resolution);
}
/**
* [7.1.1.1/H-2-1] MUST have screen resolution of at least 1080p.
*/
public static ResolutionRequirement createR7_1_1_1__H_2_1() {
RequiredMeasurement<Integer> long_resolution = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.LONG_RESOLUTION)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.S, 1920)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1920)
.build();
RequiredMeasurement<Integer> short_resolution = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.SHORT_RESOLUTION)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.S, 1080)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1080)
.build();
return new ResolutionRequirement(RequirementConstants.R7_1_1_1__H_2_1, long_resolution,
short_resolution);
}
}
// used for requirements [7.1.1.3/H-1-1], [7.1.1.3/H-2-1]
public static class DensityRequirement extends Requirement {
private static final String TAG = DensityRequirement.class.getSimpleName();
private DensityRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setDisplayDensity(int displayDensity) {
this.<Integer>setMeasuredValue(RequirementConstants.DISPLAY_DENSITY, displayDensity);
}
/**
* [7.1.1.3/H-1-1] MUST have screen density of at least 400 dpi.
*/
public static DensityRequirement createR7_1_1_3__H_1_1() {
RequiredMeasurement<Integer> display_density = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.DISPLAY_DENSITY)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.R, 400)
.build();
return new DensityRequirement(RequirementConstants.R7_1_1_3__H_1_1, display_density);
}
/**
* [7.1.1.3/H-2-1] MUST have screen density of at least 400 dpi.
*/
public static DensityRequirement createR7_1_1_3__H_2_1() {
RequiredMeasurement<Integer> display_density = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.DISPLAY_DENSITY)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.S, 400)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 400)
.build();
return new DensityRequirement(RequirementConstants.R7_1_1_3__H_2_1, display_density);
}
}
// used for requirements [7.6.1/H-1-1], [7.6.1/H-2-1]
public static class MemoryRequirement extends Requirement {
private static final String TAG = MemoryRequirement.class.getSimpleName();
private MemoryRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setPhysicalMemory(long physicalMemory) {
this.<Long>setMeasuredValue(RequirementConstants.PHYSICAL_MEMORY, physicalMemory);
}
/**
* [7.6.1/H-1-1] MUST have at least 6 GB of physical memory.
*/
public static MemoryRequirement createR7_6_1__H_1_1() {
RequiredMeasurement<Long> physical_memory = RequiredMeasurement
.<Long>builder()
.setId(RequirementConstants.PHYSICAL_MEMORY)
.setPredicate(RequirementConstants.LONG_GTE)
// 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.
.addRequiredValue(Build.VERSION_CODES.R, 5L * 1024L)
.build();
return new MemoryRequirement(RequirementConstants.R7_6_1__H_1_1, physical_memory);
}
/**
* [7.6.1/H-2-1] MUST have at least 6/8 GB of physical memory.
*/
public static MemoryRequirement createR7_6_1__H_2_1() {
RequiredMeasurement<Long> physical_memory = RequiredMeasurement
.<Long>builder()
.setId(RequirementConstants.PHYSICAL_MEMORY)
.setPredicate(RequirementConstants.LONG_GTE)
// Media performance requires 6/8 GB minimum RAM, but keeping the following to
// 5/7 GB as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
.addRequiredValue(Build.VERSION_CODES.S, 5L * 1024L)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 7L * 1024L)
.build();
return new MemoryRequirement(RequirementConstants.R7_6_1__H_2_1, physical_memory);
}
}
public static class CodecInitLatencyRequirement extends Requirement {
private static final String TAG = CodecInitLatencyRequirement.class.getSimpleName();
private CodecInitLatencyRequirement(String id, RequiredMeasurement<?>... reqs) {
super(id, reqs);
}
public void setCodecInitLatencyMs(long codecInitLatencyMs) {
this.setMeasuredValue(RequirementConstants.CODEC_INIT_LATENCY, codecInitLatencyMs);
}
/**
* [2.2.7.1/5.1/H-1-7] MUST have a codec initialization latency of 65(R) / 50(S) / 40(T)
* ms or less for a 1080p or smaller video encoding session for all hardware video
* encoders when under load. Load here is defined as a concurrent 1080p to 720p
* video-only transcoding session using hardware video codecs together with the 1080p
* audio-video recording initialization.
*/
public static CodecInitLatencyRequirement createR5_1__H_1_7() {
RequiredMeasurement<Long> codec_init_latency =
RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
.setPredicate(RequirementConstants.LONG_LTE)
.addRequiredValue(Build.VERSION_CODES.R, 65L)
.addRequiredValue(Build.VERSION_CODES.S, 50L)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40L)
.build();
return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_7,
codec_init_latency);
}
/**
* [2.2.7.1/5.1/H-1-8] MUST have a codec initialization latency of 50(R) / 40(S) / 30(T)
* ms or less for a 128 kbps or lower bitrate audio encoding session for all audio
* encoders when under load. Load here is defined as a concurrent 1080p to 720p
* video-only transcoding session using hardware video codecs together with the 1080p
* audio-video recording initialization.
*/
public static CodecInitLatencyRequirement createR5_1__H_1_8() {
RequiredMeasurement<Long> codec_init_latency =
RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
.setPredicate(RequirementConstants.LONG_LTE)
.addRequiredValue(Build.VERSION_CODES.R, 50L)
.addRequiredValue(Build.VERSION_CODES.S, 40L)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 30L)
.build();
return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_8,
codec_init_latency);
}
/**
* [2.2.7.1/5.1/H-1-12] Codec initialization latency of 40ms or less for a 1080p or
* smaller video decoding session for all hardware video encoders when under load. Load
* here is defined as a concurrent 1080p to 720p video-only transcoding session using
* hardware video codecs together with the 1080p audio-video recording initialization.
*/
public static CodecInitLatencyRequirement createR5_1__H_1_12() {
RequiredMeasurement<Long> codec_init_latency =
RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
.setPredicate(RequirementConstants.LONG_LTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40L)
.build();
return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_12,
codec_init_latency);
}
/**
* [2.2.7.1/5.1/H-1-13] Codec initialization latency of 30ms or less for a 128kbps or
* lower bitrate audio decoding session for all audio encoders when under load. Load here
* is defined as a concurrent 1080p to 720p video-only transcoding session using hardware
* video codecs together with the 1080p audio-video recording initialization.
*/
public static CodecInitLatencyRequirement createR5_1__H_1_13() {
RequiredMeasurement<Long> codec_init_latency =
RequiredMeasurement.<Long>builder().setId(RequirementConstants.CODEC_INIT_LATENCY)
.setPredicate(RequirementConstants.LONG_LTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 30L)
.build();
return new CodecInitLatencyRequirement(RequirementConstants.R5_1__H_1_13,
codec_init_latency);
}
}
// used for requirements [2.2.7.1/5.3/H-1-1], [2.2.7.1/5.3/H-1-2]
public static class FrameDropRequirement extends Requirement {
private static final String TAG = FrameDropRequirement.class.getSimpleName();
private FrameDropRequirement(String id, RequiredMeasurement<?>... reqs) {
super(id, reqs);
}
public void setFramesDropped(int framesDropped) {
this.setMeasuredValue(RequirementConstants.FRAMES_DROPPED, framesDropped);
}
public void setFrameRate(double frameRate) {
this.setMeasuredValue(RequirementConstants.FRAME_RATE, frameRate);
}
/**
* [2.2.7.1/5.3/H-1-1] MUST NOT drop more than 1 frames in 10 seconds (i.e less than 0.333
* percent frame drop) for a 1080p 30 fps video session under load. Load is defined as a
* concurrent 1080p to 720p video-only transcoding session using hardware video codecs,
* as well as a 128 kbps AAC audio playback.
*/
public static FrameDropRequirement createR5_3__H_1_1_R() {
RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.FRAMES_DROPPED)
.setPredicate(RequirementConstants.INTEGER_LTE)
// MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
.addRequiredValue(Build.VERSION_CODES.R, 3)
.build();
RequiredMeasurement<Double> frameRate = RequiredMeasurement
.<Double>builder()
.setId(RequirementConstants.FRAME_RATE)
.setPredicate(RequirementConstants.DOUBLE_EQ)
.addRequiredValue(Build.VERSION_CODES.R, 30.0)
.build();
return new FrameDropRequirement(RequirementConstants.R5_3__H_1_1, frameDropped,
frameRate);
}
/**
* [2.2.7.1/5.3/H-1-2] MUST NOT drop more than 1 frame in 10 seconds during a video
* resolution change in a 30 fps video session under load. Load is defined as a
* concurrent 1080p to 720p video-only transcoding session using hardware video codecs,
* as well as a 128Kbps AAC audio playback.
*/
public static FrameDropRequirement createR5_3__H_1_2_R() {
RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.FRAMES_DROPPED)
.setPredicate(RequirementConstants.INTEGER_LTE)
// MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
.addRequiredValue(Build.VERSION_CODES.R, 3)
.build();
RequiredMeasurement<Double> frameRate = RequiredMeasurement
.<Double>builder()
.setId(RequirementConstants.FRAME_RATE)
.setPredicate(RequirementConstants.DOUBLE_EQ)
.addRequiredValue(Build.VERSION_CODES.R, 30.0)
.build();
return new FrameDropRequirement(RequirementConstants.R5_3__H_1_2, frameDropped,
frameRate);
}
/**
* [2.2.7.1/5.3/H-1-1] MUST NOT drop more than 2(S) / 1(T) frames in 10 seconds for a
* 1080p 60 fps video session under load. Load is defined as a concurrent 1080p to 720p
* video-only transcoding session using hardware video codecs, as well as a 128 kbps AAC
* audio playback.
*/
public static FrameDropRequirement createR5_3__H_1_1_ST() {
RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.FRAMES_DROPPED)
.setPredicate(RequirementConstants.INTEGER_LTE)
// MUST NOT drop more than 2 frame in 10 seconds so 6 frames for 30 seconds
.addRequiredValue(Build.VERSION_CODES.S, 6)
// MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 3)
.build();
RequiredMeasurement<Double> frameRate = RequiredMeasurement
.<Double>builder()
.setId(RequirementConstants.FRAME_RATE)
.setPredicate(RequirementConstants.DOUBLE_EQ)
.addRequiredValue(Build.VERSION_CODES.S, 60.0)
.build();
return new FrameDropRequirement(RequirementConstants.R5_3__H_1_1, frameDropped,
frameRate);
}
/**
* [2.2.7.1/5.3/H-1-2] MUST NOT drop more than 2(S) / 1(T) frames in 10 seconds during a
* video resolution change in a 60 fps video session under load. Load is defined as a
* concurrent 1080p to 720p video-only transcoding session using hardware video codecs,
* as well as a 128Kbps AAC audio playback.
*/
public static FrameDropRequirement createR5_3__H_1_2_ST() {
RequiredMeasurement<Integer> frameDropped = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.FRAMES_DROPPED)
.setPredicate(RequirementConstants.INTEGER_LTE)
// MUST NOT drop more than 2 frame in 10 seconds so 6 frames for 30 seconds
.addRequiredValue(Build.VERSION_CODES.S, 6)
// MUST NOT drop more than 1 frame in 10 seconds so 3 frames for 30 seconds
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 3)
.build();
RequiredMeasurement<Double> frameRate = RequiredMeasurement
.<Double>builder()
.setId(RequirementConstants.FRAME_RATE)
.setPredicate(RequirementConstants.DOUBLE_EQ)
.addRequiredValue(Build.VERSION_CODES.S, 60.0)
.build();
return new FrameDropRequirement(RequirementConstants.R5_3__H_1_2, frameDropped,
frameRate);
}
}
public static class VideoCodecRequirement extends Requirement {
private static final String TAG = VideoCodecRequirement.class.getSimpleName();
private VideoCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setAv1DecoderReq(boolean av1DecoderReqSatisfied) {
this.setMeasuredValue(RequirementConstants.AV1_DEC_REQ, av1DecoderReqSatisfied);
}
public void set4kHwDecoders(int num4kHwDecoders) {
this.setMeasuredValue(RequirementConstants.NUM_4k_HW_DEC, num4kHwDecoders);
}
public void set4kHwEncoders(int num4kHwEncoders) {
this.setMeasuredValue(RequirementConstants.NUM_4k_HW_ENC, num4kHwEncoders);
}
/**
* [2.2.7.1/5.1/H-1-15] Must have at least 1 HW video decoder supporting 4K60
*/
public static VideoCodecRequirement createR4k60HwDecoder() {
RequiredMeasurement<Integer> requirement = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.NUM_4k_HW_DEC)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
.build();
return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_15, requirement);
}
/**
* [2.2.7.1/5.1/H-1-16] Must have at least 1 HW video encoder supporting 4K60
*/
public static VideoCodecRequirement createR4k60HwEncoder() {
RequiredMeasurement<Integer> requirement = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.NUM_4k_HW_ENC)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
.build();
return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_16, requirement);
}
/**
* [2.2.7.1/5.1/H-1-14] AV1 Hardware decoder: Main 10, Level 4.1, Film Grain
*/
public static VideoCodecRequirement createRAV1DecoderReq() {
RequiredMeasurement<Boolean> requirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.AV1_DEC_REQ)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new VideoCodecRequirement(RequirementConstants.R5_1__H_1_14, requirement);
}
}
// used for requirements [2.2.7.1/5.1/H-1-1], [2.2.7.1/5.1/H-1-2], [2.2.7.1/5.1/H-1-3],
// [2.2.7.1/5.1/H-1-4], [2.2.7.1/5.1/H-1-5], [2.2.7.1/5.1/H-1-6], [2.2.7.1/5.1/H-1-9],
// [2.2.7.1/5.1/H-1-10]
public static class ConcurrentCodecRequirement extends Requirement {
private static final String TAG = ConcurrentCodecRequirement.class.getSimpleName();
// allowed tolerance in measured fps vs expected fps in percentage, i.e. codecs achieving
// fps that is greater than (FPS_TOLERANCE_FACTOR * expectedFps) will be considered as
// passing the test
private static final double FPS_TOLERANCE_FACTOR = 0.95;
private static final double FPS_30_TOLERANCE = 30.0 * FPS_TOLERANCE_FACTOR;
static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
static final int REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 = 2;
private ConcurrentCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setConcurrentInstances(int concurrentInstances) {
this.setMeasuredValue(RequirementConstants.CONCURRENT_SESSIONS,
concurrentInstances);
}
public void setConcurrentFps(double achievedFps) {
this.setMeasuredValue(RequirementConstants.CONCURRENT_FPS, achievedFps);
}
// copied from android.mediapc.cts.getReqMinConcurrentInstances due to build issues on aosp
public static int getReqMinConcurrentInstances(int performanceClass, String mimeType1,
String mimeType2, int resolution) {
ArrayList<String> MEDIAPC_CONCURRENT_CODECS_R = new ArrayList<>(
Arrays.asList(MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC));
ArrayList<String> MEDIAPC_CONCURRENT_CODECS = new ArrayList<>(Arrays
.asList(MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
MediaFormat.MIMETYPE_VIDEO_VP9, MediaFormat.MIMETYPE_VIDEO_AV1));
if (performanceClass >= Build.VERSION_CODES.TIRAMISU) {
return resolution >= 1080 ? REQUIRED_MIN_CONCURRENT_INSTANCES : 0;
} else if (performanceClass == Build.VERSION_CODES.S) {
if (resolution >= 1080) {
return 0;
}
if (MEDIAPC_CONCURRENT_CODECS.contains(mimeType1) && MEDIAPC_CONCURRENT_CODECS
.contains(mimeType2)) {
if (MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mimeType1)
|| MediaFormat.MIMETYPE_VIDEO_VP9.equalsIgnoreCase(mimeType2)) {
return REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
} else {
return REQUIRED_MIN_CONCURRENT_INSTANCES;
}
} else {
return 0;
}
} else if (performanceClass == Build.VERSION_CODES.R) {
if (resolution >= 1080) {
return 0;
}
if (MEDIAPC_CONCURRENT_CODECS_R.contains(mimeType1) && MEDIAPC_CONCURRENT_CODECS_R
.contains(mimeType2)) {
return REQUIRED_MIN_CONCURRENT_INSTANCES;
} else {
return 0;
}
} else {
return 0;
}
}
private static double getReqMinConcurrentFps(int performanceClass, String mimeType1,
String mimeType2, int resolution) {
return FPS_30_TOLERANCE * getReqMinConcurrentInstances(performanceClass, mimeType1,
mimeType2, resolution);
}
/**
* [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
* sessions that can be run concurrently in any codec combination via the
* CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
* .getSupportedPerformancePoints() methods.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_1_720p(String mimeType1,
String mimeType2, int resolution) {
RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.CONCURRENT_SESSIONS)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.R,
getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
resolution))
.addRequiredValue(Build.VERSION_CODES.S,
getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
resolution))
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_1, maxInstances);
}
/**
* [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
* sessions that can be run concurrently in any codec combination via the
* CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
* .getSupportedPerformancePoints() methods.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_1_1080p() {
RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.CONCURRENT_SESSIONS)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_1, maxInstances);
}
/**
* [2.2.7.1/5.1/H-1-2] MUST support 6 instances of hardware video decoder sessions (AVC,
* HEVC, VP9* or later) in any codec combination running concurrently at 720p(R,S)
* resolution@30 fps.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_2_720p(String mimeType1,
String mimeType2, int resolution) {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
.addRequiredValue(Build.VERSION_CODES.R,
getReqMinConcurrentFps(Build.VERSION_CODES.R, mimeType1, mimeType2, resolution))
.addRequiredValue(Build.VERSION_CODES.S,
getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution))
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_2,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-2] MUST support 6 instances of hardware video decoder sessions (AVC,
* HEVC, VP9* or later) in any codec combination running concurrently at 1080p(T)
* resolution@30 fps.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_2_1080p() {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_2,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-3] MUST advertise the maximum number of hardware video encoder
* sessions that can be run concurrently in any codec combination via the
* CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
* .getSupportedPerformancePoints() methods.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_3_720p(String mimeType1,
String mimeType2, int resolution) {
RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.CONCURRENT_SESSIONS)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.R,
getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
resolution))
.addRequiredValue(Build.VERSION_CODES.S,
getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
resolution))
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_3, maxInstances);
}
/**
* [2.2.7.1/5.1/H-1-3] MUST advertise the maximum number of hardware video encoder
* sessions that can be run concurrently in any codec combination via the
* CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
* .getSupportedPerformancePoints() methods.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_3_1080p() {
RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.CONCURRENT_SESSIONS)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_3, maxInstances);
}
/**
* [2.2.7.1/5.1/H-1-4] MUST support 6 instances of hardware video encoder sessions (AVC,
* HEVC, VP9* or later) in any codec combination running concurrently at 720p(R,S)
* resolution@30 fps.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_4_720p() {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
// Requirement not asserted since encoder test runs in byte buffer mode
.addRequiredValue(Build.VERSION_CODES.R, 0.0)
.addRequiredValue(Build.VERSION_CODES.S, 0.0)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_4,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-4] MUST support 6 instances of hardware video encoder sessions (AVC,
* HEVC, VP9* or later) in any codec combination running concurrently at 1080p(T)
* resolution@30 fps.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_4_1080p() {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
// Requirement not asserted since encoder test runs in byte buffer mode
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 0.0)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_4,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-5] MUST advertise the maximum number of hardware video encoder and
* decoder sessions that can be run concurrently in any codec combination via the
* CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
* .getSupportedPerformancePoints() methods.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_5_720p(String mimeType1,
String mimeType2, int resolution) {
RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.CONCURRENT_SESSIONS)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.R,
getReqMinConcurrentInstances(Build.VERSION_CODES.R, mimeType1, mimeType2,
resolution))
.addRequiredValue(Build.VERSION_CODES.S,
getReqMinConcurrentInstances(Build.VERSION_CODES.S, mimeType1, mimeType2,
resolution))
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_5, maxInstances);
}
/**
* [2.2.7.1/5.1/H-1-5] MUST advertise the maximum number of hardware video encoder and
* decoder sessions that can be run concurrently in any codec combination via the
* CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
* .getSupportedPerformancePoints() methods.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_5_1080p() {
RequiredMeasurement<Integer> maxInstances = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.CONCURRENT_SESSIONS)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_5, maxInstances);
}
/**
* [2.2.7.1/5.1/H-1-6] Support 6 instances of hardware video decoder and hardware video
* encoder sessions (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently
* at 720p(R,S) /1080p(T) @30fps resolution.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_6_720p(String mimeType1,
String mimeType2, int resolution) {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
// Test transcoding, fps calculated for encoder and decoder combined so req / 2
.addRequiredValue(Build.VERSION_CODES.R,
getReqMinConcurrentFps(Build.VERSION_CODES.R, mimeType1, mimeType2, resolution)
/ 2)
.addRequiredValue(Build.VERSION_CODES.S,
getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution)
/ 2)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_6,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-6] Support 6 instances of hardware video decoder and hardware video
* encoder sessions (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently
* at 720p(R,S) /1080p(T) @30fps resolution.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_6_1080p() {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
// Test transcoding, fps calculated for encoder and decoder combined so req / 2
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE / 2)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_6,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-9] Support 2 instances of secure hardware video decoder sessions
* (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently at 1080p
* resolution@30fps.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_9() {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 2 * FPS_30_TOLERANCE)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_9,
reqConcurrentFps);
}
/**
* [2.2.7.1/5.1/H-1-10] Support 3 instances of non-secure hardware video decoder sessions
* together with 1 instance of secure hardware video decoder session (4 instances total)
* (AVC, HEVC, VP9 or AV1) in any codec combination running concurrently at 1080p
* resolution@30fps.
*/
public static ConcurrentCodecRequirement createR5_1__H_1_10() {
RequiredMeasurement<Double> reqConcurrentFps = RequiredMeasurement.<Double>builder()
.setId(RequirementConstants.CONCURRENT_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 4 * FPS_30_TOLERANCE)
.build();
return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_10,
reqConcurrentFps);
}
}
// used for requirements [2.2.7.1/5.1/H-1-11], [2.2.7.1/5.7/H-1-2]
public static class SecureCodecRequirement extends Requirement {
private static final String TAG = SecureCodecRequirement.class.getSimpleName();
private SecureCodecRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setSecureReqSatisfied(boolean secureReqSatisfied) {
this.setMeasuredValue(RequirementConstants.SECURE_REQ_SATISFIED, secureReqSatisfied);
}
public void setNumCryptoHwSecureAllDec(int numCryptoHwSecureAllDec) {
this.setMeasuredValue(RequirementConstants.NUM_CRYPTO_HW_SECURE_ALL_SUPPORT,
numCryptoHwSecureAllDec);
}
/**
* [2.2.7.1/5.7/H-1-2] MUST support MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL with the below
* content decryption capabilities.
*/
public static SecureCodecRequirement createR5_7__H_1_2() {
RequiredMeasurement<Integer> hw_secure_all = RequiredMeasurement.<Integer>builder()
.setId(RequirementConstants.NUM_CRYPTO_HW_SECURE_ALL_SUPPORT)
.setPredicate(RequirementConstants.INTEGER_GTE)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1)
.build();
return new SecureCodecRequirement(RequirementConstants.R5_7__H_1_2, hw_secure_all);
}
/**
* [2.2.7.1/5.1/H-1-11] Must support secure decoder when a corresponding AVC/VP9/HEVC or AV1
* hardware decoder is available
*/
public static SecureCodecRequirement createR5_1__H_1_11() {
RequiredMeasurement<Boolean> requirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.SECURE_REQ_SATISFIED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new SecureCodecRequirement(RequirementConstants.R5_1__H_1_11, requirement);
}
}
public static class PrimaryCameraRequirement extends Requirement {
private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
private static final String TAG = PrimaryCameraRequirement.class.getSimpleName();
private PrimaryCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setPrimaryCameraSupported(boolean hasPrimaryCamera) {
this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_AVAILABLE,
hasPrimaryCamera);
}
public void setResolution(long resolution) {
this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_RESOLUTION,
resolution);
}
public void setVideoSizeReqSatisfied(boolean videoSizeReqSatisfied) {
this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED,
videoSizeReqSatisfied);
}
public void setVideoFps(double videoFps) {
this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS, videoFps);
}
/**
* [2.2.7.2/7.5/H-1-1] MUST have a primary rear facing camera with a resolution of at
* least 12 megapixels supporting video capture at 4k@30fps
*/
public static PrimaryCameraRequirement createRearPrimaryCamera() {
RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.R, true)
.addRequiredValue(Build.VERSION_CODES.S, true)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
.<Long>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
.setPredicate(RequirementConstants.LONG_GTE)
.addRequiredValue(Build.VERSION_CODES.R, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
.addRequiredValue(Build.VERSION_CODES.S, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
.build();
RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.R, true)
.addRequiredValue(Build.VERSION_CODES.S, true)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Double> videoFps = RequiredMeasurement
.<Double>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
.addRequiredValue(Build.VERSION_CODES.R, 29.9)
.addRequiredValue(Build.VERSION_CODES.S, 29.9)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
.build();
return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_1,
hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
videoFps);
}
/**
* [2.2.7.2/7.5/H-1-2] MUST have a primary front facing camera with a resolution of
* at least 4 megapixels supporting video capture at 1080p@30fps.
*/
public static PrimaryCameraRequirement createFrontPrimaryCamera() {
RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.R, true)
.addRequiredValue(Build.VERSION_CODES.S, true)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
.<Long>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
.setPredicate(RequirementConstants.LONG_GTE)
.addRequiredValue(Build.VERSION_CODES.R, MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION)
.addRequiredValue(Build.VERSION_CODES.S, MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU,
MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
.build();
RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.R, true)
.addRequiredValue(Build.VERSION_CODES.S, true)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Double> videoFps = RequiredMeasurement
.<Double>builder()
.setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
.setPredicate(RequirementConstants.DOUBLE_GTE)
.addRequiredValue(Build.VERSION_CODES.R, 29.9)
.addRequiredValue(Build.VERSION_CODES.S, 29.9)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
.build();
return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_2,
hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
videoFps);
}
}
public static class CameraTimestampSourceRequirement extends Requirement {
private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
private static final int TIMESTAMP_REALTIME =
CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
private CameraTimestampSourceRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearCameraTimestampSource(Integer timestampSource) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE,
timestampSource);
}
public void setFrontCameraTimestampSource(Integer timestampSource) {
this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE,
timestampSource);
}
/**
* [2.2.7.2/7.5/H-1-4] MUST support CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME
* for both primary cameras.
*/
public static CameraTimestampSourceRequirement createTimestampSourceReq() {
RequiredMeasurement<Integer> rearTimestampSource = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE)
.setPredicate(RequirementConstants.INTEGER_EQ)
.addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
.addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
.build();
RequiredMeasurement<Integer> frontTimestampSource = RequiredMeasurement
.<Integer>builder()
.setId(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE)
.setPredicate(RequirementConstants.INTEGER_EQ)
.addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
.addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
.build();
return new CameraTimestampSourceRequirement(RequirementConstants.R7_5__H_1_4,
rearTimestampSource, frontTimestampSource);
}
}
public static class CameraLatencyRequirement extends Requirement {
private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
private CameraLatencyRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearCameraLatency(float latency) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LATENCY, latency);
}
public void setFrontCameraLatency(float latency) {
this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LATENCY, latency);
}
/**
* [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p resolution
* as measured by the CTS camera PerformanceTest under ITS lighting conditions
* (3000K) for both primary cameras.
*/
public static CameraLatencyRequirement createJpegLatencyReq() {
RequiredMeasurement<Float> rearJpegLatency = RequiredMeasurement
.<Float>builder()
.setId(RequirementConstants.REAR_CAMERA_LATENCY)
.setPredicate(RequirementConstants.FLOAT_LTE)
.addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
.addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
.build();
RequiredMeasurement<Float> frontJpegLatency = RequiredMeasurement
.<Float>builder()
.setId(RequirementConstants.FRONT_CAMERA_LATENCY)
.setPredicate(RequirementConstants.FLOAT_LTE)
.addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
.addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
.build();
return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_5,
rearJpegLatency, frontJpegLatency);
}
/**
* [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first
* preview frame) < 600ms as measured by the CTS camera PerformanceTest under ITS lighting
* conditions (3000K) for both primary cameras.
*/
public static CameraLatencyRequirement createLaunchLatencyReq() {
RequiredMeasurement<Float> rearLaunchLatency = RequiredMeasurement
.<Float>builder()
.setId(RequirementConstants.REAR_CAMERA_LATENCY)
.setPredicate(RequirementConstants.FLOAT_LTE)
.addRequiredValue(Build.VERSION_CODES.R, 600.0f)
.addRequiredValue(Build.VERSION_CODES.S, 600.0f)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
.build();
RequiredMeasurement<Float> frontLaunchLatency = RequiredMeasurement
.<Float>builder()
.setId(RequirementConstants.FRONT_CAMERA_LATENCY)
.setPredicate(RequirementConstants.FLOAT_LTE)
.addRequiredValue(Build.VERSION_CODES.R, 600.0f)
.addRequiredValue(Build.VERSION_CODES.S, 600.0f)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
.build();
return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_6,
rearLaunchLatency, frontLaunchLatency);
}
}
public static class CameraRawRequirement extends Requirement {
private static final String TAG = CameraRawRequirement.class.getSimpleName();
private CameraRawRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearRawSupported(boolean rearRawSupported) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED,
rearRawSupported);
}
/**
* [2.2.7.2/7.5/H-1-8] MUST support CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW and
* android.graphics.ImageFormat.RAW_SENSOR for the primary back camera.
*/
public static CameraRawRequirement createRawReq() {
RequiredMeasurement<Boolean> requirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.S, true)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new CameraRawRequirement(RequirementConstants.R7_5__H_1_8, requirement);
}
}
public static class Camera240FpsRequirement extends Requirement {
private static final String TAG = Camera240FpsRequirement.class.getSimpleName();
private Camera240FpsRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRear240FpsSupported(boolean rear240FpsSupported) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED,
rear240FpsSupported);
}
/**
* [2.2.7.2/7.5/H-1-9] MUST have a rear-facing primary camera supporting 720p or 1080p @ 240fps.
*/
public static Camera240FpsRequirement create240FpsReq() {
RequiredMeasurement<Boolean> requirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new Camera240FpsRequirement(RequirementConstants.R7_5__H_1_9, requirement);
}
}
public static class UltraWideZoomRatioRequirement extends Requirement {
private static final String TAG =
UltraWideZoomRatioRequirement.class.getSimpleName();
private UltraWideZoomRatioRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
ultrawideZoomRatioReqMet);
}
public void setFrontUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
ultrawideZoomRatioReqMet);
}
/**
* [2.2.7.2/7.5/H-1-10] MUST have min ZOOM_RATIO < 1.0 for the primary cameras if
* there is an ultrawide RGB camera facing the same direction.
*/
public static UltraWideZoomRatioRequirement createUltrawideZoomRatioReq() {
RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new UltraWideZoomRatioRequirement(RequirementConstants.R7_5__H_1_10,
rearRequirement, frontRequirement);
}
}
public static class ConcurrentRearFrontRequirement extends Requirement {
private static final String TAG = ConcurrentRearFrontRequirement.class.getSimpleName();
private ConcurrentRearFrontRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setConcurrentRearFrontSupported(boolean concurrentRearFrontSupported) {
this.setMeasuredValue(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED,
concurrentRearFrontSupported);
}
/**
* [2.2.7.2/7.5/H-1-11] MUST implement concurrent front-back streaming on primary cameras.
*/
public static ConcurrentRearFrontRequirement createConcurrentRearFrontReq() {
RequiredMeasurement<Boolean> requirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new ConcurrentRearFrontRequirement(RequirementConstants.R7_5__H_1_11,
requirement);
}
}
public static class PreviewStabilizationRequirement extends Requirement {
private static final String TAG =
PreviewStabilizationRequirement.class.getSimpleName();
private PreviewStabilizationRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearPreviewStabilizationSupported(boolean supported) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
supported);
}
public void setFrontPreviewStabilizationSupported(boolean supported) {
this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
supported);
}
/**
* [2.2.7.2/7.5/H-1-12] MUST support CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
* for both primary front and primary back camera.
*/
public static PreviewStabilizationRequirement createPreviewStabilizationReq() {
RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new PreviewStabilizationRequirement(RequirementConstants.R7_5__H_1_12,
rearRequirement, frontRequirement);
}
}
public static class LogicalMultiCameraRequirement extends Requirement {
private static final String TAG =
LogicalMultiCameraRequirement.class.getSimpleName();
private LogicalMultiCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearLogicalMultiCameraReqMet(boolean reqMet) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
reqMet);
}
public void setFrontLogicalMultiCameraReqMet(boolean reqMet) {
this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
reqMet);
}
/**
* [2.2.7.2/7.5/H-1-13] MUST support LOGICAL_MULTI_CAMERA capability for the primary
* cameras if there are greater than 1 RGB cameras facing the same direction.
*/
public static LogicalMultiCameraRequirement createLogicalMultiCameraReq() {
RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new LogicalMultiCameraRequirement(RequirementConstants.R7_5__H_1_13,
rearRequirement, frontRequirement);
}
}
public static class StreamUseCaseRequirement extends Requirement {
private static final String TAG =
StreamUseCaseRequirement.class.getSimpleName();
private StreamUseCaseRequirement(String id, RequiredMeasurement<?> ... reqs) {
super(id, reqs);
}
public void setRearStreamUseCaseSupported(boolean supported) {
this.setMeasuredValue(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED,
supported);
}
public void setFrontStreamUseCaseSupported(boolean supported) {
this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED,
supported);
}
/**
* [2.2.7.2/7.5/H-1-14] MUST support STREAM_USE_CASE capability for both primary
* front and primary back camera.
*/
public static StreamUseCaseRequirement createStreamUseCaseReq() {
RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
.<Boolean>builder()
.setId(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED)
.setPredicate(RequirementConstants.BOOLEAN_EQ)
.addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
.build();
return new StreamUseCaseRequirement(RequirementConstants.R7_5__H_1_14,
rearRequirement, frontRequirement);
}
}
public <R extends Requirement> R addRequirement(R req) {
if (!this.mRequirements.add(req)) {
throw new IllegalStateException("Requirement " + req.id() + " already added");
}
return req;
}
public ResolutionRequirement addR7_1_1_1__H_1_1() {
return this.<ResolutionRequirement>addRequirement(
ResolutionRequirement.createR7_1_1_1__H_1_1());
}
public DensityRequirement addR7_1_1_3__H_1_1() {
return this.<DensityRequirement>addRequirement(DensityRequirement.createR7_1_1_3__H_1_1());
}
public MemoryRequirement addR7_6_1__H_1_1() {
return this.<MemoryRequirement>addRequirement(MemoryRequirement.createR7_6_1__H_1_1());
}
public ResolutionRequirement addR7_1_1_1__H_2_1() {
return this.<ResolutionRequirement>addRequirement(
ResolutionRequirement.createR7_1_1_1__H_2_1());
}
public DensityRequirement addR7_1_1_3__H_2_1() {
return this.<DensityRequirement>addRequirement(DensityRequirement.createR7_1_1_3__H_2_1());
}
public MemoryRequirement addR7_6_1__H_2_1() {
return this.<MemoryRequirement>addRequirement(MemoryRequirement.createR7_6_1__H_2_1());
}
public FrameDropRequirement addR5_3__H_1_1_R() {
return this.addRequirement(FrameDropRequirement.createR5_3__H_1_1_R());
}
public FrameDropRequirement addR5_3__H_1_2_R() {
return this.addRequirement(FrameDropRequirement.createR5_3__H_1_2_R());
}
public FrameDropRequirement addR5_3__H_1_1_ST() {
return this.addRequirement(FrameDropRequirement.createR5_3__H_1_1_ST());
}
public FrameDropRequirement addR5_3__H_1_2_ST() {
return this.addRequirement(FrameDropRequirement.createR5_3__H_1_2_ST());
}
public CodecInitLatencyRequirement addR5_1__H_1_7() {
return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_7());
}
public CodecInitLatencyRequirement addR5_1__H_1_8() {
return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_8());
}
public CodecInitLatencyRequirement addR5_1__H_1_12() {
return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_12());
}
public CodecInitLatencyRequirement addR5_1__H_1_13() {
return this.addRequirement(CodecInitLatencyRequirement.createR5_1__H_1_13());
}
public VideoCodecRequirement addR4k60HwEncoder() {
return this.addRequirement(VideoCodecRequirement.createR4k60HwEncoder());
}
public VideoCodecRequirement addR4k60HwDecoder() {
return this.addRequirement(VideoCodecRequirement.createR4k60HwDecoder());
}
public VideoCodecRequirement addRAV1DecoderReq() {
return this.addRequirement(VideoCodecRequirement.createRAV1DecoderReq());
}
public SecureCodecRequirement addR5_1__H_1_11() {
return this.addRequirement(SecureCodecRequirement.createR5_1__H_1_11());
}
public SecureCodecRequirement addR5_7__H_1_2() {
return this.addRequirement(SecureCodecRequirement.createR5_7__H_1_2());
}
public ConcurrentCodecRequirement addR5_1__H_1_1_720p(String mimeType1, String mimeType2,
int resolution) {
return this.addRequirement(
ConcurrentCodecRequirement.createR5_1__H_1_1_720p(mimeType1, mimeType2, resolution));
}
public ConcurrentCodecRequirement addR5_1__H_1_1_1080p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_1_1080p());
}
public ConcurrentCodecRequirement addR5_1__H_1_2_720p(String mimeType1, String mimeType2,
int resolution) {
return this.addRequirement(
ConcurrentCodecRequirement.createR5_1__H_1_2_720p(mimeType1, mimeType2, resolution));
}
public ConcurrentCodecRequirement addR5_1__H_1_2_1080p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_2_1080p());
}
public ConcurrentCodecRequirement addR5_1__H_1_3_720p(String mimeType1, String mimeType2,
int resolution) {
return this.addRequirement(
ConcurrentCodecRequirement.createR5_1__H_1_3_720p(mimeType1, mimeType2, resolution));
}
public ConcurrentCodecRequirement addR5_1__H_1_3_1080p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_3_1080p());
}
public ConcurrentCodecRequirement addR5_1__H_1_4_720p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_4_720p());
}
public ConcurrentCodecRequirement addR5_1__H_1_4_1080p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_4_1080p());
}
public ConcurrentCodecRequirement addR5_1__H_1_5_720p(String mimeType1, String mimeType2,
int resolution) {
return this.addRequirement(
ConcurrentCodecRequirement.createR5_1__H_1_5_720p(mimeType1, mimeType2, resolution));
}
public ConcurrentCodecRequirement addR5_1__H_1_5_1080p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_5_1080p());
}
public ConcurrentCodecRequirement addR5_1__H_1_6_720p(String mimeType1, String mimeType2,
int resolution) {
return this.addRequirement(
ConcurrentCodecRequirement.createR5_1__H_1_6_720p(mimeType1, mimeType2, resolution));
}
public ConcurrentCodecRequirement addR5_1__H_1_6_1080p() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_6_1080p());
}
public ConcurrentCodecRequirement addR5_1__H_1_9() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_9());
}
public ConcurrentCodecRequirement addR5_1__H_1_10() {
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_10());
}
public PrimaryCameraRequirement addPrimaryRearCameraReq() {
return this.addRequirement(PrimaryCameraRequirement.createRearPrimaryCamera());
}
public PrimaryCameraRequirement addPrimaryFrontCameraReq() {
return this.addRequirement(PrimaryCameraRequirement.createFrontPrimaryCamera());
}
public CameraTimestampSourceRequirement addR7_5__H_1_4() {
return this.addRequirement(CameraTimestampSourceRequirement.createTimestampSourceReq());
}
public CameraLatencyRequirement addR7_5__H_1_5() {
return this.addRequirement(CameraLatencyRequirement.createJpegLatencyReq());
}
public CameraLatencyRequirement addR7_5__H_1_6() {
return this.addRequirement(CameraLatencyRequirement.createLaunchLatencyReq());
}
public CameraRawRequirement addR7_5__H_1_8() {
return this.addRequirement(CameraRawRequirement.createRawReq());
}
public Camera240FpsRequirement addR7_5__H_1_9() {
return this.addRequirement(Camera240FpsRequirement.create240FpsReq());
}
public UltraWideZoomRatioRequirement addR7_5__H_1_10() {
return this.addRequirement(UltraWideZoomRatioRequirement.createUltrawideZoomRatioReq());
}
public ConcurrentRearFrontRequirement addR7_5__H_1_11() {
return this.addRequirement(ConcurrentRearFrontRequirement.createConcurrentRearFrontReq());
}
public PreviewStabilizationRequirement addR7_5__H_1_12() {
return this.addRequirement(PreviewStabilizationRequirement.createPreviewStabilizationReq());
}
public LogicalMultiCameraRequirement addR7_5__H_1_13() {
return this.addRequirement(LogicalMultiCameraRequirement.createLogicalMultiCameraReq());
}
public StreamUseCaseRequirement addR7_5__H_1_14() {
return this.addRequirement(StreamUseCaseRequirement.createStreamUseCaseReq());
}
public void submitAndCheck() {
boolean perfClassMet = submit();
// check performance class
assumeTrue("Build.VERSION.MEDIA_PERFORMANCE_CLASS is not declared", Utils.isPerfClass());
assertThat(perfClassMet).isTrue();
}
public boolean submit() {
boolean perfClassMet = true;
for (Requirement req: this.mRequirements) {
perfClassMet &= req.writeLogAndCheck(this.mTestName);
}
this.mRequirements.clear(); // makes sure report isn't submitted twice
return perfClassMet;
}
}