1*b7c941bbSAndroid Build Coastguard Worker /* 2*b7c941bbSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project 3*b7c941bbSAndroid Build Coastguard Worker * 4*b7c941bbSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*b7c941bbSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*b7c941bbSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*b7c941bbSAndroid Build Coastguard Worker * 8*b7c941bbSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*b7c941bbSAndroid Build Coastguard Worker * 10*b7c941bbSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*b7c941bbSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*b7c941bbSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*b7c941bbSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*b7c941bbSAndroid Build Coastguard Worker * limitations under the License. 15*b7c941bbSAndroid Build Coastguard Worker */ 16*b7c941bbSAndroid Build Coastguard Worker 17*b7c941bbSAndroid Build Coastguard Worker package android.videoencodingquality.cts; 18*b7c941bbSAndroid Build Coastguard Worker 19*b7c941bbSAndroid Build Coastguard Worker import static com.android.media.videoquality.bdrate.BdRateMain.verifyBdRate; 20*b7c941bbSAndroid Build Coastguard Worker 21*b7c941bbSAndroid Build Coastguard Worker import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters; 22*b7c941bbSAndroid Build Coastguard Worker import android.cts.host.utils.DeviceJUnit4Parameterized; 23*b7c941bbSAndroid Build Coastguard Worker import android.platform.test.annotations.AppModeFull; 24*b7c941bbSAndroid Build Coastguard Worker 25*b7c941bbSAndroid Build Coastguard Worker import com.android.compatibility.common.util.CddTest; 26*b7c941bbSAndroid Build Coastguard Worker import com.android.ddmlib.IDevice; 27*b7c941bbSAndroid Build Coastguard Worker import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 28*b7c941bbSAndroid Build Coastguard Worker import com.android.ddmlib.testrunner.TestResult.TestStatus; 29*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.config.Option; 30*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.config.OptionClass; 31*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.device.DeviceNotAvailableException; 32*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.device.ITestDevice; 33*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.log.LogUtil; 34*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.result.CollectingTestListener; 35*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.result.TestDescription; 36*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.result.TestResult; 37*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.result.TestRunResult; 38*b7c941bbSAndroid Build Coastguard Worker import com.android.tradefed.testtype.IDeviceTest; 39*b7c941bbSAndroid Build Coastguard Worker 40*b7c941bbSAndroid Build Coastguard Worker import org.json.JSONArray; 41*b7c941bbSAndroid Build Coastguard Worker import org.json.JSONObject; 42*b7c941bbSAndroid Build Coastguard Worker import org.junit.Assert; 43*b7c941bbSAndroid Build Coastguard Worker import org.junit.Assume; 44*b7c941bbSAndroid Build Coastguard Worker import org.junit.Test; 45*b7c941bbSAndroid Build Coastguard Worker import org.junit.runner.RunWith; 46*b7c941bbSAndroid Build Coastguard Worker import org.junit.runners.Parameterized; 47*b7c941bbSAndroid Build Coastguard Worker import org.junit.runners.Parameterized.UseParametersRunnerFactory; 48*b7c941bbSAndroid Build Coastguard Worker 49*b7c941bbSAndroid Build Coastguard Worker import java.io.BufferedReader; 50*b7c941bbSAndroid Build Coastguard Worker import java.io.File; 51*b7c941bbSAndroid Build Coastguard Worker import java.io.FileReader; 52*b7c941bbSAndroid Build Coastguard Worker import java.io.FileWriter; 53*b7c941bbSAndroid Build Coastguard Worker import java.io.IOException; 54*b7c941bbSAndroid Build Coastguard Worker import java.io.InputStreamReader; 55*b7c941bbSAndroid Build Coastguard Worker import java.nio.charset.StandardCharsets; 56*b7c941bbSAndroid Build Coastguard Worker import java.nio.file.Files; 57*b7c941bbSAndroid Build Coastguard Worker import java.nio.file.Paths; 58*b7c941bbSAndroid Build Coastguard Worker import java.util.ArrayList; 59*b7c941bbSAndroid Build Coastguard Worker import java.util.Arrays; 60*b7c941bbSAndroid Build Coastguard Worker import java.util.List; 61*b7c941bbSAndroid Build Coastguard Worker import java.util.Map; 62*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.TimeUnit; 63*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.locks.Condition; 64*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.locks.Lock; 65*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.locks.ReentrantLock; 66*b7c941bbSAndroid Build Coastguard Worker 67*b7c941bbSAndroid Build Coastguard Worker import javax.annotation.Nullable; 68*b7c941bbSAndroid Build Coastguard Worker 69*b7c941bbSAndroid Build Coastguard Worker /** 70*b7c941bbSAndroid Build Coastguard Worker * This class constitutes host-part of video encoding quality test (go/pc14-veq). This test is 71*b7c941bbSAndroid Build Coastguard Worker * aimed towards benchmarking encoders on the target device. 72*b7c941bbSAndroid Build Coastguard Worker * <p> 73*b7c941bbSAndroid Build Coastguard Worker * Video encoding quality test quantifies encoders on the test device by encoding a set of clips 74*b7c941bbSAndroid Build Coastguard Worker * at various configurations. The encoded output is analysed for vmaf and compared against 75*b7c941bbSAndroid Build Coastguard Worker * reference. This entire process is not carried on the device. The host side of the test 76*b7c941bbSAndroid Build Coastguard Worker * prepares the test environment by installing a VideoEncodingApp on the device. It also pushes 77*b7c941bbSAndroid Build Coastguard Worker * the test vectors and test configurations on to the device. The VideoEncodingApp transcodes the 78*b7c941bbSAndroid Build Coastguard Worker * input clips basing on the configurations shared. The host side of the test then pulls output 79*b7c941bbSAndroid Build Coastguard Worker * files from the device and analyses for vmaf. These values are compared against reference using 80*b7c941bbSAndroid Build Coastguard Worker * Bjontegaard metric. 81*b7c941bbSAndroid Build Coastguard Worker **/ 82*b7c941bbSAndroid Build Coastguard Worker @AppModeFull(reason = "Instant apps cannot access the SD card") 83*b7c941bbSAndroid Build Coastguard Worker @RunWith(DeviceJUnit4Parameterized.class) 84*b7c941bbSAndroid Build Coastguard Worker @UseParametersRunnerFactory(DeviceJUnit4ClassRunnerWithParameters.RunnerFactory.class) 85*b7c941bbSAndroid Build Coastguard Worker @OptionClass(alias = "pc-veq-test") 86*b7c941bbSAndroid Build Coastguard Worker public class CtsVideoEncodingQualityHostTest implements IDeviceTest { 87*b7c941bbSAndroid Build Coastguard Worker private static final String RES_URL = 88*b7c941bbSAndroid Build Coastguard Worker "https://storage.googleapis.com/android_media/cts/hostsidetests/pc14_veq/veqtests-1_4.tar.gz"; 89*b7c941bbSAndroid Build Coastguard Worker 90*b7c941bbSAndroid Build Coastguard Worker // variables related to host-side of the test 91*b7c941bbSAndroid Build Coastguard Worker private static final int MEDIA_PERFORMANCE_CLASS_14 = 34; 92*b7c941bbSAndroid Build Coastguard Worker private static final int MINIMUM_VALID_SDK = 31; 93*b7c941bbSAndroid Build Coastguard Worker // test is not valid before sdk 31, aka Android 12, aka Android S 94*b7c941bbSAndroid Build Coastguard Worker 95*b7c941bbSAndroid Build Coastguard Worker private static final Lock sLock = new ReentrantLock(); 96*b7c941bbSAndroid Build Coastguard Worker private static final Condition sCondition = sLock.newCondition(); 97*b7c941bbSAndroid Build Coastguard Worker private static boolean sIsTestSetUpDone = false; 98*b7c941bbSAndroid Build Coastguard Worker // install apk, push necessary resources to device to run the test. lock/condition 99*b7c941bbSAndroid Build Coastguard Worker // pair is to keep setupTestEnv() thread safe 100*b7c941bbSAndroid Build Coastguard Worker private static File sHostWorkDir; 101*b7c941bbSAndroid Build Coastguard Worker private static int sMpc; 102*b7c941bbSAndroid Build Coastguard Worker 103*b7c941bbSAndroid Build Coastguard Worker // Variables related to device-side of the test. These need to kept in sync with definitions of 104*b7c941bbSAndroid Build Coastguard Worker // VideoEncodingApp.apk 105*b7c941bbSAndroid Build Coastguard Worker private static final String DEVICE_SIDE_TEST_PACKAGE = "android.videoencoding.app"; 106*b7c941bbSAndroid Build Coastguard Worker private static final String DEVICE_SIDE_TEST_CLASS = 107*b7c941bbSAndroid Build Coastguard Worker "android.videoencoding.app.VideoTranscoderTest"; 108*b7c941bbSAndroid Build Coastguard Worker private static final String RUNNER = "androidx.test.runner.AndroidJUnitRunner"; 109*b7c941bbSAndroid Build Coastguard Worker private static final String TEST_CONFIG_INST_ARGS_KEY = "conf-json"; 110*b7c941bbSAndroid Build Coastguard Worker private static final long DEFAULT_SHELL_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5); 111*b7c941bbSAndroid Build Coastguard Worker private static final String TEST_TIMEOUT_INST_ARGS_KEY = "timeout_msec"; 112*b7c941bbSAndroid Build Coastguard Worker private static final long DEFAULT_TEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(3); 113*b7c941bbSAndroid Build Coastguard Worker 114*b7c941bbSAndroid Build Coastguard Worker // local variables related to host-side of the test 115*b7c941bbSAndroid Build Coastguard Worker private final String mJsonName; 116*b7c941bbSAndroid Build Coastguard Worker private ITestDevice mDevice; 117*b7c941bbSAndroid Build Coastguard Worker 118*b7c941bbSAndroid Build Coastguard Worker @Option(name = "force-to-run", description = "Force to run the test even if the device is not" 119*b7c941bbSAndroid Build Coastguard Worker + " a right performance class device.") 120*b7c941bbSAndroid Build Coastguard Worker private boolean mForceToRun = false; 121*b7c941bbSAndroid Build Coastguard Worker 122*b7c941bbSAndroid Build Coastguard Worker @Option(name = "skip-avc", description = "Skip avc encoder testing") 123*b7c941bbSAndroid Build Coastguard Worker private boolean mSkipAvc = false; 124*b7c941bbSAndroid Build Coastguard Worker 125*b7c941bbSAndroid Build Coastguard Worker @Option(name = "skip-hevc", description = "Skip hevc encoder testing") 126*b7c941bbSAndroid Build Coastguard Worker private boolean mSkipHevc = false; 127*b7c941bbSAndroid Build Coastguard Worker 128*b7c941bbSAndroid Build Coastguard Worker @Option(name = "skip-p", description = "Skip P only testing") 129*b7c941bbSAndroid Build Coastguard Worker private boolean mSkipP = false; 130*b7c941bbSAndroid Build Coastguard Worker 131*b7c941bbSAndroid Build Coastguard Worker @Option(name = "skip-b", description = "Skip B frame testing") 132*b7c941bbSAndroid Build Coastguard Worker private boolean mSkipB = false; 133*b7c941bbSAndroid Build Coastguard Worker 134*b7c941bbSAndroid Build Coastguard Worker @Option(name = "reset", description = "Start with a fresh directory.") 135*b7c941bbSAndroid Build Coastguard Worker private boolean mReset = false; 136*b7c941bbSAndroid Build Coastguard Worker 137*b7c941bbSAndroid Build Coastguard Worker @Option(name = "quick-check", description = "Run a quick check.") 138*b7c941bbSAndroid Build Coastguard Worker private boolean mQuickCheck = false; 139*b7c941bbSAndroid Build Coastguard Worker CtsVideoEncodingQualityHostTest(String jsonName, @SuppressWarnings("unused") String testLabel)140*b7c941bbSAndroid Build Coastguard Worker public CtsVideoEncodingQualityHostTest(String jsonName, 141*b7c941bbSAndroid Build Coastguard Worker @SuppressWarnings("unused") String testLabel) { 142*b7c941bbSAndroid Build Coastguard Worker mJsonName = jsonName; 143*b7c941bbSAndroid Build Coastguard Worker } 144*b7c941bbSAndroid Build Coastguard Worker 145*b7c941bbSAndroid Build Coastguard Worker private static final List<Object[]> AVC_VBR_B0_PARAMS = Arrays.asList(new Object[][]{ 146*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Beach-SO04-CRW02-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0.json", 147*b7c941bbSAndroid Build Coastguard Worker "Beach_SO04_CRW02_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 148*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-BirthdayHalfway-SI17-CRUW03-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0" 149*b7c941bbSAndroid Build Coastguard Worker + ".json", 150*b7c941bbSAndroid Build Coastguard Worker "BirthdayHalfway_SI17_CRUW03_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 151*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieTeenKitchenSocialMedia-SS01-CF01-P-420-8bit-SDR-1080p" 152*b7c941bbSAndroid Build Coastguard Worker + "-30fps_hw_avc_vbr_b0.json", 153*b7c941bbSAndroid Build Coastguard Worker "SelfieTeenKitchenSocialMedia_SS01_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_" 154*b7c941bbSAndroid Build Coastguard Worker + "vbr_b0"}, 155*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Waterfall-SO05-CRW01-P-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0.json", 156*b7c941bbSAndroid Build Coastguard Worker "Waterfall_SO05_CRW01_P_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 157*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieFamily-SF14-CF01-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0.json" 158*b7c941bbSAndroid Build Coastguard Worker , "SelfieFamily_SF14_CF01_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 159*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-River-SO03-CRW01-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0.json", 160*b7c941bbSAndroid Build Coastguard Worker "River_SO03_CRW01_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 161*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieGroupGarden-SF15-CF01-P-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0" 162*b7c941bbSAndroid Build Coastguard Worker + ".json", 163*b7c941bbSAndroid Build Coastguard Worker "SelfieGroupGarden_SF15_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 164*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-ConcertNear-SI10-CRW01-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b0.json" 165*b7c941bbSAndroid Build Coastguard Worker , "ConcertNear_SI10_CRW01_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b0"}, 166*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieCoupleCitySocialMedia-SS02-CF01-P-420-8bit-SDR" 167*b7c941bbSAndroid Build Coastguard Worker + "-1080p-30fps_hw_avc_vbr_b0.json", 168*b7c941bbSAndroid Build Coastguard Worker "SelfieCoupleCitySocialMedia_SS02_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_" 169*b7c941bbSAndroid Build Coastguard Worker + "vbr_b0"}}); 170*b7c941bbSAndroid Build Coastguard Worker 171*b7c941bbSAndroid Build Coastguard Worker private static final List<Object[]> AVC_VBR_B3_PARAMS = Arrays.asList(new Object[][]{ 172*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Beach-SO04-CRW02-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3.json", 173*b7c941bbSAndroid Build Coastguard Worker "Beach_SO04_CRW02_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 174*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-BirthdayHalfway-SI17-CRUW03-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3" 175*b7c941bbSAndroid Build Coastguard Worker + ".json", 176*b7c941bbSAndroid Build Coastguard Worker "BirthdayHalfway_SI17_CRUW03_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 177*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieTeenKitchenSocialMedia-SS01-CF01-P-420-8bit-SDR-1080p" 178*b7c941bbSAndroid Build Coastguard Worker + "-30fps_hw_avc_vbr_b3.json", 179*b7c941bbSAndroid Build Coastguard Worker "SelfieTeenKitchenSocialMedia_SS01_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_" 180*b7c941bbSAndroid Build Coastguard Worker + "vbr_b3"}, 181*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Waterfall-SO05-CRW01-P-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3.json", 182*b7c941bbSAndroid Build Coastguard Worker "Waterfall_SO05_CRW01_P_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 183*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieFamily-SF14-CF01-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3.json" 184*b7c941bbSAndroid Build Coastguard Worker , "SelfieFamily_SF14_CF01_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 185*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-River-SO03-CRW01-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3.json", 186*b7c941bbSAndroid Build Coastguard Worker "River_SO03_CRW01_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 187*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieGroupGarden-SF15-CF01-P-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3" 188*b7c941bbSAndroid Build Coastguard Worker + ".json", 189*b7c941bbSAndroid Build Coastguard Worker "SelfieGroupGarden_SF15_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 190*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-ConcertNear-SI10-CRW01-L-420-8bit-SDR-1080p-30fps_hw_avc_vbr_b3.json" 191*b7c941bbSAndroid Build Coastguard Worker , "ConcertNear_SI10_CRW01_L_420_8bit_SDR_1080p_30fps_hw_avc_vbr_b3"}, 192*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieCoupleCitySocialMedia-SS02-CF01-P-420-8bit-SDR" 193*b7c941bbSAndroid Build Coastguard Worker + "-1080p-30fps_hw_avc_vbr_b3.json", 194*b7c941bbSAndroid Build Coastguard Worker "SelfieCoupleCitySocialMedia_SS02_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_" 195*b7c941bbSAndroid Build Coastguard Worker + "vbr_b3"}}); 196*b7c941bbSAndroid Build Coastguard Worker 197*b7c941bbSAndroid Build Coastguard Worker private static final List<Object[]> HEVC_VBR_B0_PARAMS = Arrays.asList(new Object[][]{ 198*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Beach-SO04-CRW02-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0.json", 199*b7c941bbSAndroid Build Coastguard Worker "Beach_SO04_CRW02_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 200*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-BirthdayHalfway-SI17-CRUW03-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0" 201*b7c941bbSAndroid Build Coastguard Worker + ".json", 202*b7c941bbSAndroid Build Coastguard Worker "BirthdayHalfway_SI17_CRUW03_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 203*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieTeenKitchenSocialMedia-SS01-CF01-P-420-8bit-SDR-1080p" 204*b7c941bbSAndroid Build Coastguard Worker + "-30fps_hw_hevc_vbr_b0.json", 205*b7c941bbSAndroid Build Coastguard Worker "SelfieTeenKitchenSocialMedia_SS01_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_" 206*b7c941bbSAndroid Build Coastguard Worker + "vbr_b0"}, 207*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Waterfall-SO05-CRW01-P-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0.json", 208*b7c941bbSAndroid Build Coastguard Worker "Waterfall_SO05_CRW01_P_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 209*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieFamily-SF14-CF01-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0.json" 210*b7c941bbSAndroid Build Coastguard Worker , "SelfieFamily_SF14_CF01_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 211*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-River-SO03-CRW01-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0.json", 212*b7c941bbSAndroid Build Coastguard Worker "River_SO03_CRW01_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 213*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieGroupGarden-SF15-CF01-P-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0" 214*b7c941bbSAndroid Build Coastguard Worker + ".json", 215*b7c941bbSAndroid Build Coastguard Worker "SelfieGroupGarden_SF15_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 216*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-ConcertNear-SI10-CRW01-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b0.json" 217*b7c941bbSAndroid Build Coastguard Worker , "ConcertNear_SI10_CRW01_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b0"}, 218*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieCoupleCitySocialMedia-SS02-CF01-P-420-8bit-SDR" 219*b7c941bbSAndroid Build Coastguard Worker + "-1080p-30fps_hw_hevc_vbr_b0.json", 220*b7c941bbSAndroid Build Coastguard Worker "SelfieCoupleCitySocialMedia_SS02_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_" 221*b7c941bbSAndroid Build Coastguard Worker + "vbr_b0"}}); 222*b7c941bbSAndroid Build Coastguard Worker 223*b7c941bbSAndroid Build Coastguard Worker private static final List<Object[]> HEVC_VBR_B3_PARAMS = Arrays.asList(new Object[][]{ 224*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Beach-SO04-CRW02-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3.json", 225*b7c941bbSAndroid Build Coastguard Worker "Beach_SO04_CRW02_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"}, 226*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-BirthdayHalfway-SI17-CRUW03-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3" 227*b7c941bbSAndroid Build Coastguard Worker + ".json", 228*b7c941bbSAndroid Build Coastguard Worker "BirthdayHalfway_SI17_CRUW03_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"}, 229*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieTeenKitchenSocialMedia-SS01-CF01-P-420-8bit-SDR-1080p" 230*b7c941bbSAndroid Build Coastguard Worker + "-30fps_hw_hevc_vbr_b3.json", 231*b7c941bbSAndroid Build Coastguard Worker "SelfieTeenKitchenSocialMedia_SS01_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_" 232*b7c941bbSAndroid Build Coastguard Worker + "vbr_b3"}, 233*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-Waterfall-SO05-CRW01-P-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3.json", 234*b7c941bbSAndroid Build Coastguard Worker "Waterfall_SO05_CRW01_P_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"}, 235*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieFamily-SF14-CF01-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3.json" 236*b7c941bbSAndroid Build Coastguard Worker , "SelfieFamily_SF14_CF01_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"}, 237*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-River-SO03-CRW01-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3.json", 238*b7c941bbSAndroid Build Coastguard Worker "River_SO03_CRW01_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"}, 239*b7c941bbSAndroid Build Coastguard Worker // Abnormal curve, not monotonically increasing. 240*b7c941bbSAndroid Build Coastguard Worker /*{"AVICON-MOBILE-SelfieGroupGarden-SF15-CF01-P-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3" 241*b7c941bbSAndroid Build Coastguard Worker + ".json", 242*b7c941bbSAndroid Build Coastguard Worker "SelfieGroupGarden_SF15_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"},*/ 243*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-ConcertNear-SI10-CRW01-L-420-8bit-SDR-1080p-30fps_hw_hevc_vbr_b3.json" 244*b7c941bbSAndroid Build Coastguard Worker , "ConcertNear_SI10_CRW01_L_420_8bit_SDR_1080p_30fps_hw_hevc_vbr_b3"}, 245*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieCoupleCitySocialMedia-SS02-CF01-P-420-8bit-SDR" 246*b7c941bbSAndroid Build Coastguard Worker + "-1080p-30fps_hw_hevc_vbr_b3.json", 247*b7c941bbSAndroid Build Coastguard Worker "SelfieCoupleCitySocialMedia_SS02_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_" 248*b7c941bbSAndroid Build Coastguard Worker + "vbr_b3"}}); 249*b7c941bbSAndroid Build Coastguard Worker 250*b7c941bbSAndroid Build Coastguard Worker private static final List<Object[]> QUICK_RUN_PARAMS = Arrays.asList(new Object[][]{ 251*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieTeenKitchenSocialMedia-SS01-CF01-P-420-8bit-SDR-1080p" 252*b7c941bbSAndroid Build Coastguard Worker + "-30fps_hw_avc_vbr_b0.json", 253*b7c941bbSAndroid Build Coastguard Worker "SelfieTeenKitchenSocialMedia_SS01_CF01_P_420_8bit_SDR_1080p_30fps_hw_avc_" + 254*b7c941bbSAndroid Build Coastguard Worker "vbr_b0"}, 255*b7c941bbSAndroid Build Coastguard Worker {"AVICON-MOBILE-SelfieTeenKitchenSocialMedia-SS01-CF01-P-420-8bit-SDR-1080p" 256*b7c941bbSAndroid Build Coastguard Worker + "-30fps_hw_hevc_vbr_b0.json", 257*b7c941bbSAndroid Build Coastguard Worker "SelfieTeenKitchenSocialMedia_SS01_CF01_P_420_8bit_SDR_1080p_30fps_hw_hevc_" 258*b7c941bbSAndroid Build Coastguard Worker + "vbr_b0"}}); 259*b7c941bbSAndroid Build Coastguard Worker 260*b7c941bbSAndroid Build Coastguard Worker @Parameterized.Parameters(name = "{index}_{1}") input()261*b7c941bbSAndroid Build Coastguard Worker public static List<Object[]> input() { 262*b7c941bbSAndroid Build Coastguard Worker final List<Object[]> args = new ArrayList<>(); 263*b7c941bbSAndroid Build Coastguard Worker args.addAll(AVC_VBR_B0_PARAMS); 264*b7c941bbSAndroid Build Coastguard Worker args.addAll(AVC_VBR_B3_PARAMS); 265*b7c941bbSAndroid Build Coastguard Worker args.addAll(HEVC_VBR_B0_PARAMS); 266*b7c941bbSAndroid Build Coastguard Worker args.addAll(HEVC_VBR_B3_PARAMS); 267*b7c941bbSAndroid Build Coastguard Worker return args; 268*b7c941bbSAndroid Build Coastguard Worker } 269*b7c941bbSAndroid Build Coastguard Worker 270*b7c941bbSAndroid Build Coastguard Worker @Override setDevice(ITestDevice device)271*b7c941bbSAndroid Build Coastguard Worker public void setDevice(ITestDevice device) { 272*b7c941bbSAndroid Build Coastguard Worker mDevice = device; 273*b7c941bbSAndroid Build Coastguard Worker } 274*b7c941bbSAndroid Build Coastguard Worker 275*b7c941bbSAndroid Build Coastguard Worker @Override getDevice()276*b7c941bbSAndroid Build Coastguard Worker public ITestDevice getDevice() { 277*b7c941bbSAndroid Build Coastguard Worker return mDevice; 278*b7c941bbSAndroid Build Coastguard Worker } 279*b7c941bbSAndroid Build Coastguard Worker 280*b7c941bbSAndroid Build Coastguard Worker /** 281*b7c941bbSAndroid Build Coastguard Worker * Sets up the necessary environment for the video encoding quality test. 282*b7c941bbSAndroid Build Coastguard Worker */ setupTestEnv()283*b7c941bbSAndroid Build Coastguard Worker public void setupTestEnv() throws Exception { 284*b7c941bbSAndroid Build Coastguard Worker String sdkAsString = getDevice().getProperty("ro.build.version.sdk"); 285*b7c941bbSAndroid Build Coastguard Worker int sdk = Integer.parseInt(sdkAsString); 286*b7c941bbSAndroid Build Coastguard Worker Assume.assumeTrue("Test requires sdk >= " + MINIMUM_VALID_SDK 287*b7c941bbSAndroid Build Coastguard Worker + " test device has sdk = " + sdk, sdk >= MINIMUM_VALID_SDK); 288*b7c941bbSAndroid Build Coastguard Worker 289*b7c941bbSAndroid Build Coastguard Worker String pcAsString = getDevice().getProperty("ro.odm.build.media_performance_class"); 290*b7c941bbSAndroid Build Coastguard Worker try { 291*b7c941bbSAndroid Build Coastguard Worker sMpc = Integer.parseInt("0" + pcAsString); 292*b7c941bbSAndroid Build Coastguard Worker } catch (Exception e) { 293*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("Invalid pcAsString: " + pcAsString + ", exception: " + e); 294*b7c941bbSAndroid Build Coastguard Worker } 295*b7c941bbSAndroid Build Coastguard Worker 296*b7c941bbSAndroid Build Coastguard Worker Assume.assumeTrue("Performance class advertised by the test device is less than " 297*b7c941bbSAndroid Build Coastguard Worker + MEDIA_PERFORMANCE_CLASS_14, mForceToRun || sMpc >= MEDIA_PERFORMANCE_CLASS_14 298*b7c941bbSAndroid Build Coastguard Worker || (sMpc == 0 && sdk >= 34 /* Build.VERSION_CODES.UPSIDE_DOWN_CAKE */)); 299*b7c941bbSAndroid Build Coastguard Worker 300*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("Failed to install package on device : " + DEVICE_SIDE_TEST_PACKAGE, 301*b7c941bbSAndroid Build Coastguard Worker getDevice().isPackageInstalled(DEVICE_SIDE_TEST_PACKAGE)); 302*b7c941bbSAndroid Build Coastguard Worker 303*b7c941bbSAndroid Build Coastguard Worker // set up host-side working directory 304*b7c941bbSAndroid Build Coastguard Worker String tmpBase = System.getProperty("java.io.tmpdir"); 305*b7c941bbSAndroid Build Coastguard Worker String dirName = "CtsVideoEncodingQualityHostTest_" + getDevice().getSerialNumber(); 306*b7c941bbSAndroid Build Coastguard Worker String tmpDir = tmpBase + "/" + dirName; 307*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("tmpBase= " + tmpBase + " tmpDir =" + tmpDir); 308*b7c941bbSAndroid Build Coastguard Worker sHostWorkDir = new File(tmpDir); 309*b7c941bbSAndroid Build Coastguard Worker if (mReset || sHostWorkDir.isFile()) { 310*b7c941bbSAndroid Build Coastguard Worker File cwd = new File("."); 311*b7c941bbSAndroid Build Coastguard Worker runCommand("rm -rf " + tmpDir, cwd); 312*b7c941bbSAndroid Build Coastguard Worker } 313*b7c941bbSAndroid Build Coastguard Worker try { 314*b7c941bbSAndroid Build Coastguard Worker if (!sHostWorkDir.isDirectory()) { 315*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("Failed to create directory : " + sHostWorkDir.getAbsolutePath(), 316*b7c941bbSAndroid Build Coastguard Worker sHostWorkDir.mkdirs()); 317*b7c941bbSAndroid Build Coastguard Worker } 318*b7c941bbSAndroid Build Coastguard Worker } catch (SecurityException e) { 319*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.e("Unable to establish temp directory " + sHostWorkDir.getPath()); 320*b7c941bbSAndroid Build Coastguard Worker } 321*b7c941bbSAndroid Build Coastguard Worker 322*b7c941bbSAndroid Build Coastguard Worker // Clean up output folders before starting the test 323*b7c941bbSAndroid Build Coastguard Worker runCommand("rm -rf " + "output_*", sHostWorkDir); 324*b7c941bbSAndroid Build Coastguard Worker 325*b7c941bbSAndroid Build Coastguard Worker // Download the test suite tar file. 326*b7c941bbSAndroid Build Coastguard Worker downloadFile(RES_URL, sHostWorkDir); 327*b7c941bbSAndroid Build Coastguard Worker 328*b7c941bbSAndroid Build Coastguard Worker // Unpack the test suite tar file. 329*b7c941bbSAndroid Build Coastguard Worker String fileName = RES_URL.substring(RES_URL.lastIndexOf('/') + 1); 330*b7c941bbSAndroid Build Coastguard Worker int result = runCommand("tar xvzf " + fileName, sHostWorkDir); 331*b7c941bbSAndroid Build Coastguard Worker Assert.assertEquals("Failed to untar " + fileName, 0, result); 332*b7c941bbSAndroid Build Coastguard Worker 333*b7c941bbSAndroid Build Coastguard Worker // Push input files to device 334*b7c941bbSAndroid Build Coastguard Worker String deviceInDir = getDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE) 335*b7c941bbSAndroid Build Coastguard Worker + "/veq/input/"; 336*b7c941bbSAndroid Build Coastguard Worker String deviceJsonDir = deviceInDir + "json/"; 337*b7c941bbSAndroid Build Coastguard Worker String deviceSamplesDir = deviceInDir + "samples/"; 338*b7c941bbSAndroid Build Coastguard Worker Assert.assertNotNull("Failed to create directory " + deviceJsonDir + " on device ", 339*b7c941bbSAndroid Build Coastguard Worker getDevice().executeAdbCommand("shell", "mkdir", "-p", deviceJsonDir)); 340*b7c941bbSAndroid Build Coastguard Worker Assert.assertNotNull("Failed to create directory " + deviceSamplesDir + " on device ", 341*b7c941bbSAndroid Build Coastguard Worker getDevice().executeAdbCommand("shell", "mkdir", "-p", deviceSamplesDir)); 342*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("Failed to push json files to " + deviceJsonDir + " on device ", 343*b7c941bbSAndroid Build Coastguard Worker getDevice().pushDir(new File(sHostWorkDir.getPath() + "/json/"), deviceJsonDir)); 344*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("Failed to push mp4 files to " + deviceSamplesDir + " on device ", 345*b7c941bbSAndroid Build Coastguard Worker getDevice().pushDir(new File(sHostWorkDir.getPath() + "/samples/"), 346*b7c941bbSAndroid Build Coastguard Worker deviceSamplesDir)); 347*b7c941bbSAndroid Build Coastguard Worker 348*b7c941bbSAndroid Build Coastguard Worker sIsTestSetUpDone = true; 349*b7c941bbSAndroid Build Coastguard Worker } 350*b7c941bbSAndroid Build Coastguard Worker containsJson(String jsonName, List<Object[]> params)351*b7c941bbSAndroid Build Coastguard Worker public static boolean containsJson(String jsonName, List<Object[]> params) { 352*b7c941bbSAndroid Build Coastguard Worker for (Object[] param : params) { 353*b7c941bbSAndroid Build Coastguard Worker if (param[0].equals(jsonName)) { 354*b7c941bbSAndroid Build Coastguard Worker return true; 355*b7c941bbSAndroid Build Coastguard Worker } 356*b7c941bbSAndroid Build Coastguard Worker } 357*b7c941bbSAndroid Build Coastguard Worker return false; 358*b7c941bbSAndroid Build Coastguard Worker } 359*b7c941bbSAndroid Build Coastguard Worker 360*b7c941bbSAndroid Build Coastguard Worker /** 361*b7c941bbSAndroid Build Coastguard Worker * Verify the video encoding quality requirements for the performance class 14 devices. 362*b7c941bbSAndroid Build Coastguard Worker */ 363*b7c941bbSAndroid Build Coastguard Worker @CddTest(requirements = {"2.2.7.1/5.8/H-1-1"}) 364*b7c941bbSAndroid Build Coastguard Worker @Test testEncoding()365*b7c941bbSAndroid Build Coastguard Worker public void testEncoding() throws Exception { 366*b7c941bbSAndroid Build Coastguard Worker Assume.assumeFalse("Skipping due to quick run mode", 367*b7c941bbSAndroid Build Coastguard Worker mQuickCheck && !containsJson(mJsonName, QUICK_RUN_PARAMS)); 368*b7c941bbSAndroid Build Coastguard Worker Assume.assumeFalse("Skipping avc encoder tests", 369*b7c941bbSAndroid Build Coastguard Worker mSkipAvc && (containsJson(mJsonName, AVC_VBR_B0_PARAMS) || containsJson(mJsonName, 370*b7c941bbSAndroid Build Coastguard Worker AVC_VBR_B3_PARAMS))); 371*b7c941bbSAndroid Build Coastguard Worker Assume.assumeFalse("Skipping hevc encoder tests", 372*b7c941bbSAndroid Build Coastguard Worker mSkipHevc && (containsJson(mJsonName, HEVC_VBR_B0_PARAMS) || containsJson(mJsonName, 373*b7c941bbSAndroid Build Coastguard Worker HEVC_VBR_B3_PARAMS))); 374*b7c941bbSAndroid Build Coastguard Worker Assume.assumeFalse("Skipping b-frame tests", 375*b7c941bbSAndroid Build Coastguard Worker mSkipB && (containsJson(mJsonName, AVC_VBR_B3_PARAMS) || containsJson(mJsonName, 376*b7c941bbSAndroid Build Coastguard Worker HEVC_VBR_B3_PARAMS))); 377*b7c941bbSAndroid Build Coastguard Worker Assume.assumeFalse("Skipping non b-frame tests", 378*b7c941bbSAndroid Build Coastguard Worker mSkipP && (containsJson(mJsonName, AVC_VBR_B0_PARAMS) || containsJson(mJsonName, 379*b7c941bbSAndroid Build Coastguard Worker HEVC_VBR_B0_PARAMS))); 380*b7c941bbSAndroid Build Coastguard Worker 381*b7c941bbSAndroid Build Coastguard Worker // set up test environment 382*b7c941bbSAndroid Build Coastguard Worker sLock.lock(); 383*b7c941bbSAndroid Build Coastguard Worker try { 384*b7c941bbSAndroid Build Coastguard Worker if (!sIsTestSetUpDone) setupTestEnv(); 385*b7c941bbSAndroid Build Coastguard Worker sCondition.signalAll(); 386*b7c941bbSAndroid Build Coastguard Worker } finally { 387*b7c941bbSAndroid Build Coastguard Worker sLock.unlock(); 388*b7c941bbSAndroid Build Coastguard Worker } 389*b7c941bbSAndroid Build Coastguard Worker 390*b7c941bbSAndroid Build Coastguard Worker // transcode input 391*b7c941bbSAndroid Build Coastguard Worker runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, DEVICE_SIDE_TEST_CLASS, "testTranscode"); 392*b7c941bbSAndroid Build Coastguard Worker 393*b7c941bbSAndroid Build Coastguard Worker // copy the encoded output from the device to the host. 394*b7c941bbSAndroid Build Coastguard Worker String outDir = "output_" + mJsonName.substring(0, mJsonName.indexOf('.')); 395*b7c941bbSAndroid Build Coastguard Worker File outHostPath = new File(sHostWorkDir, outDir); 396*b7c941bbSAndroid Build Coastguard Worker try { 397*b7c941bbSAndroid Build Coastguard Worker if (!outHostPath.isDirectory()) { 398*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("Failed to create directory : " + outHostPath.getAbsolutePath(), 399*b7c941bbSAndroid Build Coastguard Worker outHostPath.mkdirs()); 400*b7c941bbSAndroid Build Coastguard Worker } 401*b7c941bbSAndroid Build Coastguard Worker } catch (SecurityException e) { 402*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.e("Unable to establish output host directory : " + outHostPath.getPath()); 403*b7c941bbSAndroid Build Coastguard Worker } 404*b7c941bbSAndroid Build Coastguard Worker String outDevPath = getDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE) + "/veq/output/" 405*b7c941bbSAndroid Build Coastguard Worker + outDir; 406*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("Failed to pull mp4 files from " + outDevPath 407*b7c941bbSAndroid Build Coastguard Worker + " to " + outHostPath.getPath(), getDevice().pullDir(outDevPath, outHostPath)); 408*b7c941bbSAndroid Build Coastguard Worker getDevice().deleteFile(outDevPath); 409*b7c941bbSAndroid Build Coastguard Worker 410*b7c941bbSAndroid Build Coastguard Worker // Parse json file 411*b7c941bbSAndroid Build Coastguard Worker String jsonPath = sHostWorkDir.getPath() + "/json/" + mJsonName; 412*b7c941bbSAndroid Build Coastguard Worker String jsonString = 413*b7c941bbSAndroid Build Coastguard Worker new String(Files.readAllBytes(Paths.get(jsonPath)), StandardCharsets.UTF_8); 414*b7c941bbSAndroid Build Coastguard Worker JSONArray jsonArray = new JSONArray(jsonString); 415*b7c941bbSAndroid Build Coastguard Worker JSONObject obj = jsonArray.getJSONObject(0); 416*b7c941bbSAndroid Build Coastguard Worker String refFileName = obj.getString("RefFileName"); 417*b7c941bbSAndroid Build Coastguard Worker int fps = obj.getInt("FrameRate"); 418*b7c941bbSAndroid Build Coastguard Worker int frameCount = obj.getInt("FrameCount"); 419*b7c941bbSAndroid Build Coastguard Worker int clipDuration = frameCount / fps; 420*b7c941bbSAndroid Build Coastguard Worker 421*b7c941bbSAndroid Build Coastguard Worker // Compute Vmaf 422*b7c941bbSAndroid Build Coastguard Worker try (FileWriter writer = new FileWriter(outHostPath.getPath() + "/" + "all_vmafs.txt")) { 423*b7c941bbSAndroid Build Coastguard Worker JSONArray codecConfigs = obj.getJSONArray("CodecConfigs"); 424*b7c941bbSAndroid Build Coastguard Worker int th = Runtime.getRuntime().availableProcessors() / 2; 425*b7c941bbSAndroid Build Coastguard Worker th = Math.min(Math.max(1, th), 8); 426*b7c941bbSAndroid Build Coastguard Worker String filter = 427*b7c941bbSAndroid Build Coastguard Worker "[0:v]setpts=PTS-STARTPTS[reference];[1:v]setpts=PTS-STARTPTS[distorted];" 428*b7c941bbSAndroid Build Coastguard Worker + "[distorted][reference]libvmaf=feature=name=psnr:model=version" 429*b7c941bbSAndroid Build Coastguard Worker + "=vmaf_v0.6.1:n_threads=" + th; 430*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < codecConfigs.length(); i++) { 431*b7c941bbSAndroid Build Coastguard Worker JSONObject codecConfig = codecConfigs.getJSONObject(i); 432*b7c941bbSAndroid Build Coastguard Worker String outputName = codecConfig.getString("EncodedFileName"); 433*b7c941bbSAndroid Build Coastguard Worker outputName = outputName.substring(0, outputName.lastIndexOf(".")); 434*b7c941bbSAndroid Build Coastguard Worker String outputVmafPath = outDir + "/" + outputName + ".txt"; 435*b7c941bbSAndroid Build Coastguard Worker String cmd = "./bin/ffmpeg"; 436*b7c941bbSAndroid Build Coastguard Worker cmd += " -hide_banner"; 437*b7c941bbSAndroid Build Coastguard Worker cmd += " -r " + fps; 438*b7c941bbSAndroid Build Coastguard Worker cmd += " -i " + "samples/" + refFileName + " -an"; // reference video 439*b7c941bbSAndroid Build Coastguard Worker cmd += " -r " + fps; 440*b7c941bbSAndroid Build Coastguard Worker cmd += " -i " + outDir + "/" + outputName + ".mp4" + " -an"; // distorted video 441*b7c941bbSAndroid Build Coastguard Worker cmd += " -filter_complex " + "\"" + filter + "\""; 442*b7c941bbSAndroid Build Coastguard Worker cmd += " -f null -"; 443*b7c941bbSAndroid Build Coastguard Worker cmd += " > " + outputVmafPath + " 2>&1"; 444*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("ffmpeg command : " + cmd); 445*b7c941bbSAndroid Build Coastguard Worker int result = runCommand(cmd, sHostWorkDir); 446*b7c941bbSAndroid Build Coastguard Worker if (sMpc >= MEDIA_PERFORMANCE_CLASS_14) { 447*b7c941bbSAndroid Build Coastguard Worker Assert.assertEquals("Encountered error during vmaf computation.", 0, result); 448*b7c941bbSAndroid Build Coastguard Worker } else { 449*b7c941bbSAndroid Build Coastguard Worker Assume.assumeTrue("Encountered error during vmaf computation but the " 450*b7c941bbSAndroid Build Coastguard Worker + "test device does not advertise performance class", result == 0); 451*b7c941bbSAndroid Build Coastguard Worker } 452*b7c941bbSAndroid Build Coastguard Worker String vmafLine = ""; 453*b7c941bbSAndroid Build Coastguard Worker try (BufferedReader reader = new BufferedReader( 454*b7c941bbSAndroid Build Coastguard Worker new FileReader(sHostWorkDir.getPath() + "/" + outputVmafPath))) { 455*b7c941bbSAndroid Build Coastguard Worker String token = "VMAF score: "; 456*b7c941bbSAndroid Build Coastguard Worker String line; 457*b7c941bbSAndroid Build Coastguard Worker while ((line = reader.readLine()) != null) { 458*b7c941bbSAndroid Build Coastguard Worker if (line.contains(token)) { 459*b7c941bbSAndroid Build Coastguard Worker line = line.substring(line.indexOf(token)); 460*b7c941bbSAndroid Build Coastguard Worker vmafLine = "VMAF score = " + line.substring(token.length()); 461*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i(vmafLine); 462*b7c941bbSAndroid Build Coastguard Worker break; 463*b7c941bbSAndroid Build Coastguard Worker } 464*b7c941bbSAndroid Build Coastguard Worker } 465*b7c941bbSAndroid Build Coastguard Worker } catch (IOException e) { 466*b7c941bbSAndroid Build Coastguard Worker throw new AssertionError("Unexpected IOException: " + e.getMessage()); 467*b7c941bbSAndroid Build Coastguard Worker } 468*b7c941bbSAndroid Build Coastguard Worker 469*b7c941bbSAndroid Build Coastguard Worker writer.write(vmafLine + "\n"); 470*b7c941bbSAndroid Build Coastguard Worker writer.write("Y4M file = " + refFileName + "\n"); 471*b7c941bbSAndroid Build Coastguard Worker writer.write("MP4 file = " + refFileName + "\n"); 472*b7c941bbSAndroid Build Coastguard Worker File file = new File(outHostPath + "/" + outputName + ".mp4"); 473*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue("output file from device missing", file.exists()); 474*b7c941bbSAndroid Build Coastguard Worker long fileSize = file.length(); 475*b7c941bbSAndroid Build Coastguard Worker writer.write("Filesize = " + fileSize + "\n"); 476*b7c941bbSAndroid Build Coastguard Worker writer.write("FPS = " + fps + "\n"); 477*b7c941bbSAndroid Build Coastguard Worker writer.write("FRAME_COUNT = " + frameCount + "\n"); 478*b7c941bbSAndroid Build Coastguard Worker writer.write("CLIP_DURATION = " + clipDuration + "\n"); 479*b7c941bbSAndroid Build Coastguard Worker long totalBits = fileSize * 8; 480*b7c941bbSAndroid Build Coastguard Worker long totalBits_kbps = totalBits / 1000; 481*b7c941bbSAndroid Build Coastguard Worker long bitrate_kbps = totalBits_kbps / clipDuration; 482*b7c941bbSAndroid Build Coastguard Worker writer.write("Bitrate kbps = " + bitrate_kbps + "\n"); 483*b7c941bbSAndroid Build Coastguard Worker } 484*b7c941bbSAndroid Build Coastguard Worker } catch (IOException e) { 485*b7c941bbSAndroid Build Coastguard Worker throw new AssertionError("Unexpected IOException: " + e.getMessage()); 486*b7c941bbSAndroid Build Coastguard Worker } 487*b7c941bbSAndroid Build Coastguard Worker 488*b7c941bbSAndroid Build Coastguard Worker // bd rate verification 489*b7c941bbSAndroid Build Coastguard Worker String refJsonFilePath = sHostWorkDir.getPath() + "/json/" + mJsonName; 490*b7c941bbSAndroid Build Coastguard Worker String testVmafFilePath = sHostWorkDir.getPath() + "/" + outDir + "/" + "all_vmafs.txt"; 491*b7c941bbSAndroid Build Coastguard Worker String resultFilePath = sHostWorkDir.getPath() + "/" + outDir + "/result.txt"; 492*b7c941bbSAndroid Build Coastguard Worker int result = verifyBdRate(refJsonFilePath, testVmafFilePath, resultFilePath); 493*b7c941bbSAndroid Build Coastguard Worker if (sMpc >= MEDIA_PERFORMANCE_CLASS_14) { 494*b7c941bbSAndroid Build Coastguard Worker Assert.assertEquals("bd rate validation failed.", 0, result); 495*b7c941bbSAndroid Build Coastguard Worker } else { 496*b7c941bbSAndroid Build Coastguard Worker Assume.assumeTrue("bd rate validation failed but the test device does not " 497*b7c941bbSAndroid Build Coastguard Worker + "advertise performance class", result == 0); 498*b7c941bbSAndroid Build Coastguard Worker } 499*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("Finished executing the process."); 500*b7c941bbSAndroid Build Coastguard Worker } 501*b7c941bbSAndroid Build Coastguard Worker runCommand(String command, File dir)502*b7c941bbSAndroid Build Coastguard Worker private int runCommand(String command, File dir) throws IOException, InterruptedException { 503*b7c941bbSAndroid Build Coastguard Worker Process p = new ProcessBuilder("/bin/sh", "-c", command) 504*b7c941bbSAndroid Build Coastguard Worker .directory(dir) 505*b7c941bbSAndroid Build Coastguard Worker .redirectErrorStream(true) 506*b7c941bbSAndroid Build Coastguard Worker .redirectOutput(ProcessBuilder.Redirect.INHERIT) 507*b7c941bbSAndroid Build Coastguard Worker .start(); 508*b7c941bbSAndroid Build Coastguard Worker 509*b7c941bbSAndroid Build Coastguard Worker BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); 510*b7c941bbSAndroid Build Coastguard Worker BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); 511*b7c941bbSAndroid Build Coastguard Worker String line; 512*b7c941bbSAndroid Build Coastguard Worker while ((line = stdInput.readLine()) != null || (line = stdError.readLine()) != null) { 513*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i(line + "\n"); 514*b7c941bbSAndroid Build Coastguard Worker } 515*b7c941bbSAndroid Build Coastguard Worker return p.waitFor(); 516*b7c941bbSAndroid Build Coastguard Worker } 517*b7c941bbSAndroid Build Coastguard Worker 518*b7c941bbSAndroid Build Coastguard Worker // Download the indicated file (within the base_url folder) to our desired destination 519*b7c941bbSAndroid Build Coastguard Worker // simple caching -- if file exists, we do not re-download downloadFile(String url, File destDir)520*b7c941bbSAndroid Build Coastguard Worker private void downloadFile(String url, File destDir) { 521*b7c941bbSAndroid Build Coastguard Worker String fileName = url.substring(RES_URL.lastIndexOf('/') + 1); 522*b7c941bbSAndroid Build Coastguard Worker File destination = new File(destDir, fileName); 523*b7c941bbSAndroid Build Coastguard Worker 524*b7c941bbSAndroid Build Coastguard Worker // save bandwidth, also allows a user to manually preload files 525*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("Do we already have a copy of file " + destination.getPath()); 526*b7c941bbSAndroid Build Coastguard Worker if (destination.isFile()) { 527*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("Skipping re-download of file " + destination.getPath()); 528*b7c941bbSAndroid Build Coastguard Worker return; 529*b7c941bbSAndroid Build Coastguard Worker } 530*b7c941bbSAndroid Build Coastguard Worker 531*b7c941bbSAndroid Build Coastguard Worker String cmd = "wget -O " + destination.getPath() + " " + url; 532*b7c941bbSAndroid Build Coastguard Worker LogUtil.CLog.i("wget_cmd = " + cmd); 533*b7c941bbSAndroid Build Coastguard Worker 534*b7c941bbSAndroid Build Coastguard Worker int result = 0; 535*b7c941bbSAndroid Build Coastguard Worker try { 536*b7c941bbSAndroid Build Coastguard Worker result = runCommand(cmd, destDir); 537*b7c941bbSAndroid Build Coastguard Worker } catch (IOException e) { 538*b7c941bbSAndroid Build Coastguard Worker result = -2; 539*b7c941bbSAndroid Build Coastguard Worker } catch (InterruptedException e) { 540*b7c941bbSAndroid Build Coastguard Worker result = -3; 541*b7c941bbSAndroid Build Coastguard Worker } 542*b7c941bbSAndroid Build Coastguard Worker Assert.assertEquals("download file failed.\n", 0, result); 543*b7c941bbSAndroid Build Coastguard Worker } 544*b7c941bbSAndroid Build Coastguard Worker runDeviceTests(String pkgName, @Nullable String testClassName, @Nullable String testMethodName)545*b7c941bbSAndroid Build Coastguard Worker private void runDeviceTests(String pkgName, @Nullable String testClassName, 546*b7c941bbSAndroid Build Coastguard Worker @Nullable String testMethodName) throws DeviceNotAvailableException { 547*b7c941bbSAndroid Build Coastguard Worker RemoteAndroidTestRunner testRunner = getTestRunner(pkgName, testClassName, testMethodName); 548*b7c941bbSAndroid Build Coastguard Worker CollectingTestListener listener = new CollectingTestListener(); 549*b7c941bbSAndroid Build Coastguard Worker Assert.assertTrue(getDevice().runInstrumentationTests(testRunner, listener)); 550*b7c941bbSAndroid Build Coastguard Worker assertTestsPassed(listener.getCurrentRunResults()); 551*b7c941bbSAndroid Build Coastguard Worker } 552*b7c941bbSAndroid Build Coastguard Worker getTestRunner(String pkgName, String testClassName, String testMethodName)553*b7c941bbSAndroid Build Coastguard Worker private RemoteAndroidTestRunner getTestRunner(String pkgName, String testClassName, 554*b7c941bbSAndroid Build Coastguard Worker String testMethodName) { 555*b7c941bbSAndroid Build Coastguard Worker if (testClassName != null && testClassName.startsWith(".")) { 556*b7c941bbSAndroid Build Coastguard Worker testClassName = pkgName + testClassName; 557*b7c941bbSAndroid Build Coastguard Worker } 558*b7c941bbSAndroid Build Coastguard Worker RemoteAndroidTestRunner testRunner = 559*b7c941bbSAndroid Build Coastguard Worker new RemoteAndroidTestRunner(pkgName, RUNNER, getDevice().getIDevice()); 560*b7c941bbSAndroid Build Coastguard Worker testRunner.setMaxTimeToOutputResponse(DEFAULT_SHELL_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 561*b7c941bbSAndroid Build Coastguard Worker testRunner.addInstrumentationArg(TEST_TIMEOUT_INST_ARGS_KEY, 562*b7c941bbSAndroid Build Coastguard Worker Long.toString(DEFAULT_TEST_TIMEOUT_MILLIS)); 563*b7c941bbSAndroid Build Coastguard Worker testRunner.addInstrumentationArg(TEST_CONFIG_INST_ARGS_KEY, mJsonName); 564*b7c941bbSAndroid Build Coastguard Worker if (testClassName != null && testMethodName != null) { 565*b7c941bbSAndroid Build Coastguard Worker testRunner.setMethodName(testClassName, testMethodName); 566*b7c941bbSAndroid Build Coastguard Worker } else if (testClassName != null) { 567*b7c941bbSAndroid Build Coastguard Worker testRunner.setClassName(testClassName); 568*b7c941bbSAndroid Build Coastguard Worker } 569*b7c941bbSAndroid Build Coastguard Worker return testRunner; 570*b7c941bbSAndroid Build Coastguard Worker } 571*b7c941bbSAndroid Build Coastguard Worker assertTestsPassed(TestRunResult testRunResult)572*b7c941bbSAndroid Build Coastguard Worker private void assertTestsPassed(TestRunResult testRunResult) { 573*b7c941bbSAndroid Build Coastguard Worker if (testRunResult.isRunFailure()) { 574*b7c941bbSAndroid Build Coastguard Worker throw new AssertionError("Failed to successfully run device tests for " 575*b7c941bbSAndroid Build Coastguard Worker + testRunResult.getName() + ": " + testRunResult.getRunFailureMessage()); 576*b7c941bbSAndroid Build Coastguard Worker } 577*b7c941bbSAndroid Build Coastguard Worker if (testRunResult.getNumTests() != testRunResult.getPassedTests().size()) { 578*b7c941bbSAndroid Build Coastguard Worker for (Map.Entry<TestDescription, TestResult> resultEntry : 579*b7c941bbSAndroid Build Coastguard Worker testRunResult.getTestResults().entrySet()) { 580*b7c941bbSAndroid Build Coastguard Worker if (resultEntry.getValue().getStatus().equals(TestStatus.FAILURE)) { 581*b7c941bbSAndroid Build Coastguard Worker StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n"); 582*b7c941bbSAndroid Build Coastguard Worker errorBuilder.append(resultEntry.getKey().toString()); 583*b7c941bbSAndroid Build Coastguard Worker errorBuilder.append(":\n"); 584*b7c941bbSAndroid Build Coastguard Worker errorBuilder.append(resultEntry.getValue().getStackTrace()); 585*b7c941bbSAndroid Build Coastguard Worker throw new AssertionError(errorBuilder.toString()); 586*b7c941bbSAndroid Build Coastguard Worker } 587*b7c941bbSAndroid Build Coastguard Worker if (resultEntry.getValue().getStatus().equals(TestStatus.ASSUMPTION_FAILURE)) { 588*b7c941bbSAndroid Build Coastguard Worker StringBuilder errorBuilder = 589*b7c941bbSAndroid Build Coastguard Worker new StringBuilder("On-device tests assumption failed:\n"); 590*b7c941bbSAndroid Build Coastguard Worker errorBuilder.append(resultEntry.getKey().toString()); 591*b7c941bbSAndroid Build Coastguard Worker errorBuilder.append(":\n"); 592*b7c941bbSAndroid Build Coastguard Worker errorBuilder.append(resultEntry.getValue().getStackTrace()); 593*b7c941bbSAndroid Build Coastguard Worker Assume.assumeTrue(errorBuilder.toString(), false); 594*b7c941bbSAndroid Build Coastguard Worker } 595*b7c941bbSAndroid Build Coastguard Worker } 596*b7c941bbSAndroid Build Coastguard Worker } 597*b7c941bbSAndroid Build Coastguard Worker } 598*b7c941bbSAndroid Build Coastguard Worker } 599