1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.mediapc.cts; 18 19 import static android.mediapc.cts.CodecTestBase.selectCodecs; 20 import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs; 21 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assume.assumeFalse; 25 26 import android.media.MediaFormat; 27 import android.mediapc.cts.common.Utils; 28 import android.os.Build; 29 import android.view.Surface; 30 31 import androidx.test.rule.ActivityTestRule; 32 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Rule; 36 37 import java.util.ArrayList; 38 import java.util.HashMap; 39 import java.util.List; 40 import java.util.Map; 41 42 public class FrameDropTestBase { 43 private static final String LOG_TAG = FrameDropTestBase.class.getSimpleName(); 44 static final boolean[] boolStates = {false, true}; 45 static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC; 46 static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC; 47 static final String VP8 = MediaFormat.MIMETYPE_VIDEO_VP8; 48 static final String VP9 = MediaFormat.MIMETYPE_VIDEO_VP9; 49 static final String AV1 = MediaFormat.MIMETYPE_VIDEO_AV1; 50 static final String AAC = MediaFormat.MIMETYPE_AUDIO_AAC; 51 static final String AAC_LOAD_FILE_NAME = "bbb_1c_128kbps_aac_audio.mp4"; 52 static final String AVC_LOAD_FILE_NAME = "bbb_1280x720_3mbps_30fps_avc.mp4"; 53 static final long DECODE_31S = 31000; // In ms 54 static final int MAX_FRAME_DROP_FOR_30S; 55 // For perf class R, one frame drop per 10 seconds at 30 fps i.e. 3 drops per 30 seconds 56 static final int MAX_FRAME_DROP_FOR_30S_30FPS_PC_R = 3; 57 // For perf class S, two frame drops per 10 seconds at 60 fps i.e. 6 drops per 30 seconds 58 static final int MAX_FRAME_DROP_FOR_30S_60FPS_PC_S = 6; 59 // For perf class T, one frame drop per 10 seconds at 60 fps i.e. 3 drops per 30 seconds 60 static final int MAX_FRAME_DROP_FOR_30S_60FPS_PC_T = 3; 61 62 final String mMime; 63 final String mDecoderName; 64 final boolean mIsAsync; 65 Surface mSurface; 66 67 private LoadStatus mLoadStatus = null; 68 private Thread mTranscodeLoadThread = null; 69 private Thread mAudioPlaybackLoadThread = null; 70 private Exception mTranscodeLoadException = null; 71 private Exception mAudioPlaybackLoadException = null; 72 73 static String AVC_DECODER_NAME; 74 static String AVC_ENCODER_NAME; 75 static String AAC_DECODER_NAME; 76 static Map<String, String> m540p30FpsTestFiles = new HashMap<>(); 77 static Map<String, String> m1080p30FpsTestFiles = new HashMap<>(); 78 static Map<String, String> m540p60FpsTestFiles = new HashMap<>(); 79 static Map<String, String> m1080p60FpsTestFiles = new HashMap<>(); 80 static Map<String, String> m2160p60FpsTestFiles = new HashMap<>(); 81 static { m540p60FpsTestFiles.put(AVC, "bbb_960x540_3mbps_60fps_avc.mp4")82 m540p60FpsTestFiles.put(AVC, "bbb_960x540_3mbps_60fps_avc.mp4"); m540p60FpsTestFiles.put(HEVC, "bbb_960x540_3mbps_60fps_hevc.mp4")83 m540p60FpsTestFiles.put(HEVC, "bbb_960x540_3mbps_60fps_hevc.mp4"); m540p60FpsTestFiles.put(VP8, "bbb_960x540_3mbps_60fps_vp8.webm")84 m540p60FpsTestFiles.put(VP8, "bbb_960x540_3mbps_60fps_vp8.webm"); m540p60FpsTestFiles.put(VP9, "bbb_960x540_3mbps_60fps_vp9.webm")85 m540p60FpsTestFiles.put(VP9, "bbb_960x540_3mbps_60fps_vp9.webm"); m540p60FpsTestFiles.put(AV1, "bbb_960x540_3mbps_60fps_av1.mp4")86 m540p60FpsTestFiles.put(AV1, "bbb_960x540_3mbps_60fps_av1.mp4"); 87 m1080p60FpsTestFiles.put(AVC, "bbb_1920x1080_8mbps_60fps_avc.mp4")88 m1080p60FpsTestFiles.put(AVC, "bbb_1920x1080_8mbps_60fps_avc.mp4"); m1080p60FpsTestFiles.put(HEVC, "bbb_1920x1080_6mbps_60fps_hevc.mp4")89 m1080p60FpsTestFiles.put(HEVC, "bbb_1920x1080_6mbps_60fps_hevc.mp4"); m1080p60FpsTestFiles.put(VP8, "bbb_1920x1080_8mbps_60fps_vp8.webm")90 m1080p60FpsTestFiles.put(VP8, "bbb_1920x1080_8mbps_60fps_vp8.webm"); m1080p60FpsTestFiles.put(VP9, "bbb_1920x1080_6mbps_60fps_vp9.webm")91 m1080p60FpsTestFiles.put(VP9, "bbb_1920x1080_6mbps_60fps_vp9.webm"); m1080p60FpsTestFiles.put(AV1, "bbb_1920x1080_6mbps_60fps_av1.mp4")92 m1080p60FpsTestFiles.put(AV1, "bbb_1920x1080_6mbps_60fps_av1.mp4"); 93 m2160p60FpsTestFiles.put(AVC, "bbb_3840x2160_24mbps_60fps_avc.mp4")94 m2160p60FpsTestFiles.put(AVC, "bbb_3840x2160_24mbps_60fps_avc.mp4"); m2160p60FpsTestFiles.put(HEVC, "bbb_3840x2160_18mbps_60fps_hevc.mkv")95 m2160p60FpsTestFiles.put(HEVC, "bbb_3840x2160_18mbps_60fps_hevc.mkv"); m2160p60FpsTestFiles.put(VP8, "bbb_3840x2160_24mbps_60fps_vp8.webm")96 m2160p60FpsTestFiles.put(VP8, "bbb_3840x2160_24mbps_60fps_vp8.webm"); m2160p60FpsTestFiles.put(VP9, "bbb_3840x2160_18mbps_60fps_vp9.webm")97 m2160p60FpsTestFiles.put(VP9, "bbb_3840x2160_18mbps_60fps_vp9.webm"); 98 // Limit AV1 4k tests to 1080p as per PC14 requirements m2160p60FpsTestFiles.put(AV1, "bbb_1920x1080_6mbps_60fps_av1.mp4")99 m2160p60FpsTestFiles.put(AV1, "bbb_1920x1080_6mbps_60fps_av1.mp4"); 100 m540p30FpsTestFiles.put(AVC, "bbb_960x540_2mbps_30fps_avc.mp4")101 m540p30FpsTestFiles.put(AVC, "bbb_960x540_2mbps_30fps_avc.mp4"); m540p30FpsTestFiles.put(HEVC, "bbb_960x540_2mbps_30fps_hevc.mp4")102 m540p30FpsTestFiles.put(HEVC, "bbb_960x540_2mbps_30fps_hevc.mp4"); m540p30FpsTestFiles.put(VP8, "bbb_960x540_2mbps_30fps_vp8.webm")103 m540p30FpsTestFiles.put(VP8, "bbb_960x540_2mbps_30fps_vp8.webm"); m540p30FpsTestFiles.put(VP9, "bbb_960x540_2mbps_30fps_vp9.webm")104 m540p30FpsTestFiles.put(VP9, "bbb_960x540_2mbps_30fps_vp9.webm"); m540p30FpsTestFiles.put(AV1, "bbb_960x540_2mbps_30fps_av1.mp4")105 m540p30FpsTestFiles.put(AV1, "bbb_960x540_2mbps_30fps_av1.mp4"); 106 m1080p30FpsTestFiles.put(AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4")107 m1080p30FpsTestFiles.put(AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4"); m1080p30FpsTestFiles.put(HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4")108 m1080p30FpsTestFiles.put(HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4"); m1080p30FpsTestFiles.put(VP8, "bbb_1920x1080_6mbps_30fps_vp8.webm")109 m1080p30FpsTestFiles.put(VP8, "bbb_1920x1080_6mbps_30fps_vp8.webm"); m1080p30FpsTestFiles.put(VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm")110 m1080p30FpsTestFiles.put(VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm"); m1080p30FpsTestFiles.put(AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4")111 m1080p30FpsTestFiles.put(AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4"); 112 113 switch (Utils.getPerfClass()) { 114 case Build.VERSION_CODES.TIRAMISU: 115 MAX_FRAME_DROP_FOR_30S = MAX_FRAME_DROP_FOR_30S_60FPS_PC_T; 116 break; 117 case Build.VERSION_CODES.S: 118 MAX_FRAME_DROP_FOR_30S = MAX_FRAME_DROP_FOR_30S_60FPS_PC_S; 119 break; 120 case Build.VERSION_CODES.R: 121 default: 122 MAX_FRAME_DROP_FOR_30S = MAX_FRAME_DROP_FOR_30S_30FPS_PC_R; 123 break; 124 } 125 } 126 127 @Before setUp()128 public void setUp() throws Exception { 129 Utils.assumeDeviceMeetsPerformanceClassPreconditions(); 130 131 ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false); 132 assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty()); 133 AVC_DECODER_NAME = listOfAvcHwDecoders.get(0); 134 135 ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true); 136 assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty()); 137 AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0); 138 139 ArrayList<String> listOfAacDecoders = selectCodecs(AAC, null, null, false); 140 assertFalse("Test requires aac decoder", listOfAacDecoders.isEmpty()); 141 AAC_DECODER_NAME = listOfAacDecoders.get(0); 142 143 createSurface(); 144 startLoad(); 145 } 146 147 @After tearDown()148 public void tearDown() throws Exception { 149 stopLoad(); 150 releaseSurface(); 151 } 152 153 @Rule 154 public ActivityTestRule<TestActivity> mActivityRule = 155 new ActivityTestRule<>(TestActivity.class); 156 FrameDropTestBase(String mimeType, String decoderName, boolean isAsync)157 public FrameDropTestBase(String mimeType, String decoderName, boolean isAsync) { 158 mMime = mimeType; 159 mDecoderName = decoderName; 160 mIsAsync = isAsync; 161 } 162 163 // Returns the list of objects with mimeTypes and their hardware decoders supporting the 164 // given features combining with sync and async modes. prepareArgumentsList(String[] features)165 static List<Object[]> prepareArgumentsList(String[] features) { 166 final List<Object[]> argsList = new ArrayList<>(); 167 final String[] mimesList = new String[] {AVC, HEVC, VP8, VP9, AV1}; 168 for (String mime : mimesList) { 169 MediaFormat format = MediaFormat.createVideoFormat(mime, 1920, 1080); 170 format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); 171 ArrayList<MediaFormat> formats = new ArrayList<>(); 172 formats.add(format); 173 ArrayList<String> listOfDecoders = 174 selectHardwareCodecs(mime, formats, features, false); 175 for (String decoder : listOfDecoders) { 176 for (boolean isAsync : boolStates) { 177 argsList.add(new Object[]{mime, decoder, isAsync}); 178 } 179 } 180 } 181 return argsList; 182 } 183 getAchievedPerfClass(int frameRate, int frameDropCount)184 protected int getAchievedPerfClass(int frameRate, int frameDropCount) { 185 int pc = 0; 186 if (frameRate == 30) { 187 pc = frameDropCount <= MAX_FRAME_DROP_FOR_30S_30FPS_PC_R ? Build.VERSION_CODES.R : 0; 188 } else { 189 pc = frameDropCount <= MAX_FRAME_DROP_FOR_30S_60FPS_PC_T ? Build.VERSION_CODES.TIRAMISU 190 : frameDropCount <= MAX_FRAME_DROP_FOR_30S_60FPS_PC_S ? Build.VERSION_CODES.S 191 : 0; 192 } 193 return pc; 194 } 195 createSurface()196 private void createSurface() throws InterruptedException { 197 mActivityRule.getActivity().waitTillSurfaceIsCreated(); 198 mSurface = mActivityRule.getActivity().getSurface(); 199 assertTrue("Surface created is null.", mSurface != null); 200 assertTrue("Surface created is invalid.", mSurface.isValid()); 201 // As we display 1920x1080 and 960x540 only which are of same aspect ratio, we will 202 // be setting screen params to 1920x1080 203 mActivityRule.getActivity().setScreenParams(1920, 1080, true); 204 } 205 releaseSurface()206 private void releaseSurface() { 207 if (mSurface != null) { 208 mSurface.release(); 209 mSurface = null; 210 } 211 } 212 createTranscodeLoad()213 private Thread createTranscodeLoad() { 214 Thread transcodeLoadThread = new Thread(() -> { 215 try { 216 TranscodeLoad transcodeLoad = new TranscodeLoad(AVC, AVC_LOAD_FILE_NAME, 217 AVC_DECODER_NAME, AVC_ENCODER_NAME, mLoadStatus); 218 transcodeLoad.doTranscode(); 219 } catch (Exception e) { 220 mTranscodeLoadException = e; 221 } 222 }); 223 return transcodeLoadThread; 224 } 225 createAudioPlaybackLoad()226 private Thread createAudioPlaybackLoad() { 227 Thread audioPlaybackLoadThread = new Thread(() -> { 228 try { 229 AudioPlaybackLoad audioPlaybackLoad = new AudioPlaybackLoad(AAC, AAC_LOAD_FILE_NAME, 230 AAC_DECODER_NAME, mLoadStatus); 231 audioPlaybackLoad.doDecodeAndPlayback(); 232 } catch (Exception e) { 233 mAudioPlaybackLoadException = e; 234 } 235 }); 236 return audioPlaybackLoadThread; 237 } 238 startLoad()239 private void startLoad() { 240 // TODO: b/183671436 241 // Start Transcode load (Decoder(720p) + Encoder(720p)) 242 mLoadStatus = new LoadStatus(); 243 mTranscodeLoadThread = createTranscodeLoad(); 244 mTranscodeLoadThread.start(); 245 // Start 128kbps AAC audio playback 246 mAudioPlaybackLoadThread = createAudioPlaybackLoad(); 247 mAudioPlaybackLoadThread.start(); 248 } 249 stopLoad()250 private void stopLoad() throws Exception { 251 if (mLoadStatus != null) { 252 mLoadStatus.setLoadFinished(); 253 } 254 if (mTranscodeLoadThread != null) { 255 mTranscodeLoadThread.join(); 256 mTranscodeLoadThread = null; 257 } 258 if (mAudioPlaybackLoadThread != null) { 259 mAudioPlaybackLoadThread.join(); 260 mAudioPlaybackLoadThread = null; 261 } 262 if (mTranscodeLoadException != null) throw mTranscodeLoadException; 263 if (mAudioPlaybackLoadException != null) throw mAudioPlaybackLoadException; 264 mLoadStatus = null; 265 } 266 } 267