blob: 596532b5b3dc50bb6c2169ad018425c609464385 [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;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
import android.media.MediaFormat;
import android.util.Pair;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class MultiCodecPerfTestBase {
private static final String LOG_TAG = MultiCodecPerfTestBase.class.getSimpleName();
static final boolean[] boolStates = {true, false};
static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
static final int REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 = 2;
// 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
static final double FPS_TOLERANCE_FACTOR = 0.95;
static ArrayList<String> mMimeList = new ArrayList<String>();
static Map<String, String> mTestFiles = new HashMap<>();
static {
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4");
mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4");
// Test VP9 and AV1 as well for Build.VERSION_CODES.S
if (Utils.isSPerfClass()) {
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9);
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm");
mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4");
}
}
String mMime;
String mTestFile;
final boolean mIsAsync;
double mMaxFrameRate;
@Before
public void isPerformanceClass() {
assumeTrue("Test requires performance class.", Utils.isPerfClass());
}
public MultiCodecPerfTestBase(String mime, String testFile, boolean isAsync) {
mMime = mime;
mTestFile = testFile;
mIsAsync = isAsync;
}
// Returns the list of hardware codecs supporting the 720p 30fps format.
public static ArrayList<String> getHardwareCodecsFor720p(String mime, boolean isEncoder) {
MediaFormat fmt = MediaFormat.createVideoFormat(mime, 1280, 720);
fmt.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
ArrayList<MediaFormat> formatsList = new ArrayList<>();
formatsList.add(fmt);
return selectHardwareCodecs(mime, formatsList, null, isEncoder);
}
// Returns the max number of 720p 30 fps instances that the given list of mimeCodecPairs
// supports. It also checks that the each codec supports 720p 180 fps PerformancePoint.
public int checkAndGetMaxSupportedInstancesFor720p(
ArrayList<Pair<String, String>> mimeCodecPairs) throws IOException {
int[] maxInstances = new int[mimeCodecPairs.size()];
int[] maxFrameRates = new int[mimeCodecPairs.size()];
int[] maxMacroBlockRates = new int[mimeCodecPairs.size()];
int loopCount = 0;
for (Pair<String, String> mimeCodecPair : mimeCodecPairs) {
MediaCodec codec = MediaCodec.createByCodecName(mimeCodecPair.second);
MediaCodecInfo.CodecCapabilities cap = codec.getCodecInfo()
.getCapabilitiesForType(mimeCodecPair.first);
List<PerformancePoint> pps = cap.getVideoCapabilities().getSupportedPerformancePoints();
assertTrue(pps.size() > 0);
int requiredFrameRate = 180;
// VP9 requires 60 fps at 720p and minimum of 2 instances
if (mimeCodecPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
requiredFrameRate = 60;
}
maxInstances[loopCount] = cap.getMaxSupportedInstances();
PerformancePoint PP720p = new PerformancePoint(1280, 720, requiredFrameRate);
maxMacroBlockRates[loopCount] = 0;
boolean supports720pPerformance = false;
for (PerformancePoint pp : pps) {
if (pp.covers(PP720p)) {
supports720pPerformance = true;
if (pp.getMaxMacroBlockRate() > maxMacroBlockRates[loopCount]) {
maxMacroBlockRates[loopCount] = (int) pp.getMaxMacroBlockRate();
maxFrameRates[loopCount] = pp.getMaxFrameRate();
}
}
}
codec.release();
assertTrue("Codec " + mimeCodecPair.second + " doesn't support 720p " +
requiredFrameRate + " performance point", supports720pPerformance);
loopCount++;
}
Arrays.sort(maxInstances);
Arrays.sort(maxFrameRates);
Arrays.sort(maxMacroBlockRates);
int minOfMaxInstances = maxInstances[0];
int minOfMaxFrameRates = maxFrameRates[0];
int minOfMaxMacroBlockRates = maxMacroBlockRates[0];
// Allow a tolerance in expected frame rate
mMaxFrameRate = minOfMaxFrameRates * FPS_TOLERANCE_FACTOR;
// Calculate how many 720p 30fps max instances it can support from it's mMaxFrameRate
// amd maxMacroBlockRate. (720p is 3,600 macro blocks assuming 16x16 macroblocks)
return Math.min(minOfMaxInstances, Math.min((int) (minOfMaxFrameRates / 30.0),
(int) (minOfMaxMacroBlockRates / 3600.0 / 30)));
}
}