1 /* 2 * Copyright (C) 2022 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.mediav2.cts; 18 19 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible; 20 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010; 21 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_ANY; 22 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_HW; 23 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_HW_RECOMMENDED; 24 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_OPTIONAL; 25 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_SHOULD; 26 27 import static org.junit.Assert.assertNotNull; 28 29 import android.media.MediaFormat; 30 import android.mediav2.common.cts.CodecEncoderTestBase; 31 import android.mediav2.common.cts.CodecTestBase; 32 import android.mediav2.common.cts.EncoderConfigParams; 33 import android.mediav2.common.cts.RawResource; 34 35 import androidx.test.filters.LargeTest; 36 37 import com.android.compatibility.common.util.ApiTest; 38 import com.android.compatibility.common.util.CddTest; 39 40 import org.junit.Assume; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.junit.runners.Parameterized; 44 45 import java.io.IOException; 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.Collection; 49 import java.util.List; 50 import java.util.Objects; 51 52 /** 53 * The test verifies encoders present in media codec list in bytebuffer mode. The test feeds raw 54 * input data to the component and receives compressed bitstream from the component. This is 55 * written to an output file using muxer. 56 * <p> 57 * At the end of encoding process, the test enforces following checks :- 58 * <ul> 59 * <li>The minimum PSNR of encoded output is at least the tolerance value.</li> 60 * </ul> 61 */ 62 @RunWith(Parameterized.class) 63 public class VideoEncoderTest extends CodecEncoderTestBase { 64 private final SupportClass mSupportRequirements; 65 private final int mFrameLimit; 66 VideoEncoderTest(String encoder, String mediaType, EncoderConfigParams encCfgParams, SupportClass supportRequirements, @SuppressWarnings("unused") String testLabel, String allTestParams)67 public VideoEncoderTest(String encoder, String mediaType, EncoderConfigParams encCfgParams, 68 SupportClass supportRequirements, @SuppressWarnings("unused") String testLabel, 69 String allTestParams) { 70 super(encoder, mediaType, new EncoderConfigParams[]{encCfgParams}, allTestParams); 71 mSupportRequirements = supportRequirements; 72 mFrameLimit = Math.max(encCfgParams.mFrameRate, 30); 73 } 74 getVideoEncoderCfgParams(String mediaType, int bitRate, int width, int height, int frameRate, int colorFormat, int maxBFrames)75 private static EncoderConfigParams getVideoEncoderCfgParams(String mediaType, int bitRate, 76 int width, int height, int frameRate, int colorFormat, int maxBFrames) { 77 EncoderConfigParams.Builder foreman = 78 new EncoderConfigParams.Builder(mediaType) 79 .setBitRate(bitRate) 80 .setWidth(width) 81 .setHeight(height) 82 .setFrameRate(frameRate) 83 .setColorFormat(colorFormat) 84 .setMaxBFrames(maxBFrames); 85 if (colorFormat == COLOR_FormatYUVP010) { 86 foreman.setProfile(Objects.requireNonNull(PROFILE_HLG_MAP.get(mediaType))[0]); 87 } 88 return foreman.build(); 89 } 90 prepareTestArgs(List<Object[]> args)91 private static List<Object[]> prepareTestArgs(List<Object[]> args) { 92 List<Object[]> argsList = new ArrayList<>(); 93 for (Object[] arg : args) { 94 String mediaType = (String) arg[0]; 95 int bitRate = (int) arg[1]; 96 int width = (int) arg[2]; 97 int height = (int) arg[3]; 98 int frameRate = (int) arg[4]; 99 int colorFormat = (int) arg[5]; 100 int[] maxBFrames = {0, 2}; 101 for (int maxBframe : maxBFrames) { 102 Object[] testArgs = new Object[4]; 103 if (maxBframe != 0) { 104 if (!mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC) 105 && !mediaType.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 106 continue; 107 } 108 } 109 testArgs[0] = arg[0]; 110 testArgs[1] = getVideoEncoderCfgParams(mediaType, bitRate, width, height, frameRate, 111 colorFormat, maxBframe); 112 testArgs[2] = arg[6]; 113 testArgs[3] = String.format("%dkbps_%dx%d_%s_%d-bframes", bitRate / 1000, width, 114 height, colorFormatToString(colorFormat, -1), maxBframe); 115 argsList.add(testArgs); 116 } 117 } 118 return argsList; 119 } 120 getSupportRequirementsDynamic(String mediaType, int width, int height)121 private static SupportClass getSupportRequirementsDynamic(String mediaType, int width, 122 int height) { 123 ArrayList<MediaFormat> formats = new ArrayList<>(); 124 formats.add(MediaFormat.createVideoFormat(mediaType, width, height)); 125 return selectCodecs(mediaType, formats, null, true).size() != 0 ? CODEC_ANY : CODEC_SHOULD; 126 } 127 128 @Parameterized.Parameters(name = "{index}_{0}_{1}_{4}") input()129 public static Collection<Object[]> input() { 130 final boolean isEncoder = true; 131 final boolean needAudio = false; 132 final boolean needVideo = true; 133 List<Object[]> defArgsList = new ArrayList<>(Arrays.asList(new Object[][]{ 134 // mediaType, width, height, bit-rate, frame-rate, color format, support class 135 {MediaFormat.MIMETYPE_VIDEO_H263, 64000, 128, 96, 15, COLOR_FormatYUV420Flexible, 136 CODEC_OPTIONAL}, 137 {MediaFormat.MIMETYPE_VIDEO_H263, 64000, 176, 144, 15, COLOR_FormatYUV420Flexible, 138 CODEC_ANY}, 139 {MediaFormat.MIMETYPE_VIDEO_H263, 128000, 128, 96, 15, COLOR_FormatYUV420Flexible, 140 CODEC_OPTIONAL}, 141 {MediaFormat.MIMETYPE_VIDEO_H263, 128000, 176, 144, 15, COLOR_FormatYUV420Flexible, 142 CODEC_ANY}, 143 144 {MediaFormat.MIMETYPE_VIDEO_MPEG4, 64000, 128, 96, 15, COLOR_FormatYUV420Flexible, 145 CODEC_OPTIONAL}, 146 {MediaFormat.MIMETYPE_VIDEO_MPEG4, 64000, 176, 144, 15, COLOR_FormatYUV420Flexible, 147 CODEC_OPTIONAL}, 148 149 {MediaFormat.MIMETYPE_VIDEO_AVC, 384000, 320, 240, 20, COLOR_FormatYUV420Flexible, 150 CODEC_ANY}, 151 {MediaFormat.MIMETYPE_VIDEO_AVC, 2000000, 720, 480, 30, COLOR_FormatYUV420Flexible, 152 CODEC_ANY}, 153 {MediaFormat.MIMETYPE_VIDEO_AVC, 3000000, 1280, 720, 30, 154 COLOR_FormatYUV420Flexible, getSupportRequirementsDynamic( 155 MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720)}, 156 {MediaFormat.MIMETYPE_VIDEO_AVC, 10000000, 1920, 1080, 30, 157 COLOR_FormatYUV420Flexible, getSupportRequirementsDynamic( 158 MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080)}, 159 160 {MediaFormat.MIMETYPE_VIDEO_VP8, 800000, 320, 180, 30, COLOR_FormatYUV420Flexible, 161 CODEC_ANY}, 162 {MediaFormat.MIMETYPE_VIDEO_VP8, 2000000, 640, 360, 30, COLOR_FormatYUV420Flexible, 163 CODEC_ANY}, 164 {MediaFormat.MIMETYPE_VIDEO_VP8, 4000000, 1280, 720, 30, 165 COLOR_FormatYUV420Flexible, getSupportRequirementsDynamic( 166 MediaFormat.MIMETYPE_VIDEO_VP8, 1280, 720)}, 167 {MediaFormat.MIMETYPE_VIDEO_VP8, 10000000, 1920, 1080, 30, 168 COLOR_FormatYUV420Flexible, getSupportRequirementsDynamic( 169 MediaFormat.MIMETYPE_VIDEO_VP8, 1920, 1080)}, 170 171 {MediaFormat.MIMETYPE_VIDEO_VP9, 1600000, 720, 480, 30, COLOR_FormatYUV420Flexible, 172 CODEC_ANY}, 173 {MediaFormat.MIMETYPE_VIDEO_VP9, 4000000, 1280, 720, 30, COLOR_FormatYUV420Flexible, 174 CODEC_HW_RECOMMENDED}, 175 {MediaFormat.MIMETYPE_VIDEO_VP9, 5000000, 1920, 1080, 30, 176 COLOR_FormatYUV420Flexible, CODEC_HW_RECOMMENDED}, 177 {MediaFormat.MIMETYPE_VIDEO_VP9, 20000000, 3840, 2160, 30, 178 COLOR_FormatYUV420Flexible, CODEC_HW_RECOMMENDED}, 179 180 {MediaFormat.MIMETYPE_VIDEO_HEVC, 1000000, 512, 512, 30, 181 COLOR_FormatYUV420Flexible, CODEC_ANY}, 182 {MediaFormat.MIMETYPE_VIDEO_HEVC, 1600000, 720, 480, 30, 183 COLOR_FormatYUV420Flexible, CODEC_HW_RECOMMENDED}, 184 {MediaFormat.MIMETYPE_VIDEO_HEVC, 4000000, 1280, 720, 30, 185 COLOR_FormatYUV420Flexible, CODEC_HW_RECOMMENDED}, 186 {MediaFormat.MIMETYPE_VIDEO_HEVC, 5000000, 1920, 1080, 30, 187 COLOR_FormatYUV420Flexible, CODEC_HW_RECOMMENDED}, 188 {MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 3840, 2160, 30, 189 COLOR_FormatYUV420Flexible, CODEC_HW_RECOMMENDED}, 190 191 {MediaFormat.MIMETYPE_VIDEO_AV1, 5000000, 720, 480, 30, 192 COLOR_FormatYUV420Flexible, CODEC_HW}, 193 {MediaFormat.MIMETYPE_VIDEO_AV1, 8000000, 1280, 720, 30, 194 COLOR_FormatYUV420Flexible, CODEC_HW}, 195 {MediaFormat.MIMETYPE_VIDEO_AV1, 16000000, 1920, 1080, 30, 196 COLOR_FormatYUV420Flexible, CODEC_HW}, 197 {MediaFormat.MIMETYPE_VIDEO_AV1, 50000000, 3840, 2160, 30, 198 COLOR_FormatYUV420Flexible, CODEC_SHOULD}, 199 })); 200 // P010 support was added in Android T, hence limit the following tests to Android T and 201 // above 202 if (IS_AT_LEAST_T) { 203 defArgsList.addAll(Arrays.asList(new Object[][]{ 204 {MediaFormat.MIMETYPE_VIDEO_AVC, 384000, 320, 240, 20, COLOR_FormatYUVP010, 205 CODEC_OPTIONAL}, 206 {MediaFormat.MIMETYPE_VIDEO_AVC, 2000000, 720, 480, 30, COLOR_FormatYUVP010, 207 CODEC_OPTIONAL}, 208 {MediaFormat.MIMETYPE_VIDEO_AVC, 3000000, 1280, 720, 30, COLOR_FormatYUVP010, 209 CODEC_OPTIONAL}, 210 {MediaFormat.MIMETYPE_VIDEO_AVC, 10000000, 1920, 1080, 30, 211 COLOR_FormatYUVP010, CODEC_OPTIONAL}, 212 213 {MediaFormat.MIMETYPE_VIDEO_VP9, 1600000, 720, 480, 30, COLOR_FormatYUVP010, 214 CODEC_OPTIONAL}, 215 {MediaFormat.MIMETYPE_VIDEO_VP9, 4000000, 1280, 720, 30, COLOR_FormatYUVP010, 216 CODEC_OPTIONAL}, 217 {MediaFormat.MIMETYPE_VIDEO_VP9, 5000000, 1920, 1080, 30, COLOR_FormatYUVP010, 218 CODEC_OPTIONAL}, 219 {MediaFormat.MIMETYPE_VIDEO_VP9, 20000000, 3840, 2160, 30, 220 COLOR_FormatYUVP010, CODEC_OPTIONAL}, 221 222 {MediaFormat.MIMETYPE_VIDEO_HEVC, 1600000, 720, 480, 30, COLOR_FormatYUVP010, 223 CODEC_OPTIONAL}, 224 {MediaFormat.MIMETYPE_VIDEO_HEVC, 4000000, 1280, 720, 30, COLOR_FormatYUVP010, 225 CODEC_OPTIONAL}, 226 {MediaFormat.MIMETYPE_VIDEO_HEVC, 5000000, 1920, 1080, 30, 227 COLOR_FormatYUVP010, CODEC_OPTIONAL}, 228 {MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 3840, 2160, 30, 229 COLOR_FormatYUVP010, CODEC_OPTIONAL}, 230 231 {MediaFormat.MIMETYPE_VIDEO_AV1, 5000000, 720, 480, 30, COLOR_FormatYUVP010, 232 CODEC_HW}, 233 {MediaFormat.MIMETYPE_VIDEO_AV1, 8000000, 1280, 720, 30, COLOR_FormatYUVP010, 234 CODEC_HW}, 235 {MediaFormat.MIMETYPE_VIDEO_AV1, 16000000, 1920, 1080, 30, 236 COLOR_FormatYUVP010, CODEC_HW}, 237 {MediaFormat.MIMETYPE_VIDEO_AV1, 50000000, 3840, 2160, 30, 238 COLOR_FormatYUVP010, CODEC_SHOULD}, 239 })); 240 } 241 List<Object[]> argsList = prepareTestArgs(defArgsList); 242 return prepareParamList(argsList, isEncoder, needAudio, needVideo, false); 243 } 244 245 /** 246 * Check description of class {@link VideoEncoderTest} 247 */ 248 @CddTest(requirements = {"5.2.1/C-1-1", "5.2.2/C-1-2", "5.2.2/C-2-1", "5.2.3/C-1-1", 249 "5.2.3/C-1-2", "5.2.3/C-2-1", "5.2.4/C-1-1", "5.2.6/C-2-1"}) 250 @ApiTest(apis = {"MediaCodecInfo.CodecCapabilities#COLOR_FormatYUV420Flexible", 251 "MediaCodecInfo.CodecCapabilities#COLOR_FormatYUVP010"}) 252 @LargeTest 253 @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS) testEncodeAndValidate()254 public void testEncodeAndValidate() throws IOException, InterruptedException { 255 // pre run checks 256 if (mEncCfgParams[0].mInputBitDepth > 8) { 257 Assume.assumeTrue("Codec doesn't support high bit depth profile encoding", 258 doesCodecSupportHDRProfile(mCodecName, mMediaType)); 259 Assume.assumeTrue(mCodecName + " doesn't support " + colorFormatToString( 260 mEncCfgParams[0].mColorFormat, mEncCfgParams[0].mInputBitDepth), 261 hasSupportForColorFormat(mCodecName, mMediaType, 262 mEncCfgParams[0].mColorFormat)); 263 } 264 ArrayList<MediaFormat> formats = new ArrayList<>(); 265 formats.add(mEncCfgParams[0].getFormat()); 266 checkFormatSupport(mCodecName, mMediaType, true, formats, null, mSupportRequirements); 267 268 // encode 269 RawResource res = EncoderInput.getRawResource(mEncCfgParams[0]); 270 assertNotNull("no raw resource found for testing config : " + mActiveEncCfg + mTestConfig 271 + mTestEnv, res); 272 273 boolean muxOutput = true; 274 if (mMediaType.equals(MediaFormat.MIMETYPE_VIDEO_AV1) && CodecTestBase.IS_BEFORE_U) { 275 muxOutput = false; 276 } 277 encodeToMemory(mCodecName, mEncCfgParams[0], res, mFrameLimit, false, muxOutput); 278 279 // validate output 280 if (muxOutput) { 281 validateEncodedPSNR(res, mMediaType, mMuxedOutputFile, true, mIsLoopBack, 282 ACCEPTABLE_WIRELESS_TX_QUALITY); 283 } 284 } 285 } 286