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_FormatSurface; 20 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010; 21 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_ALL; 22 import static android.mediav2.common.cts.CodecTestBase.SupportClass.CODEC_OPTIONAL; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assume.assumeTrue; 27 28 import android.media.MediaCodec; 29 import android.media.MediaFormat; 30 import android.mediav2.common.cts.CodecDecoderTestBase; 31 import android.mediav2.common.cts.CodecTestBase; 32 import android.mediav2.common.cts.OutputManager; 33 import android.mediav2.common.cts.OutputSurface; 34 import android.opengl.GLES20; 35 import android.opengl.GLES30; 36 import android.util.Log; 37 38 import androidx.test.filters.LargeTest; 39 40 import com.android.compatibility.common.util.ApiTest; 41 import com.android.compatibility.common.util.CddTest; 42 43 import org.junit.After; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.junit.runners.Parameterized; 47 48 import java.io.IOException; 49 import java.nio.ByteBuffer; 50 import java.util.ArrayList; 51 import java.util.Arrays; 52 import java.util.Collection; 53 import java.util.List; 54 55 import javax.microedition.khronos.opengles.GL10; 56 57 /** 58 * Validates the correctness of color conversion in the decode followed by OpenGL 59 * rendering scenarios. The input video files fed to the decoders contain the pixel 60 * data in compressed YUV format. The output of the decoders is shared with OpenGL 61 * as external textures. And OpenGL outputs RGB pixels. The class validates whether 62 * the conversion of input YUV to output RGB is in accordance with the chosen color 63 * aspects. Video files used in the test do not have any color aspects info coded in 64 * the bitstreams 65 */ 66 @RunWith(Parameterized.class) 67 public class DecodeGlAccuracyTest extends CodecDecoderTestBase { 68 private static final String LOG_TAG = DecodeGlAccuracyTest.class.getSimpleName(); 69 private static final String MEDIA_DIR = WorkDir.getMediaDirString(); 70 71 // Allowed color tolerance to account for differences in the conversion process 72 private static final int ALLOWED_COLOR_DELTA = 8; 73 74 // The test video assets were generated with a set of color bars. 75 // Depending on the color aspects, the values from OpenGL pbuffer 76 // should not differ from the reference color values for the 77 // given color aspects below by more than the allowed tolerance. 78 // 79 // The reference RGB values were computed using the process described below. 80 // 81 // RGB = Transpose(FLOOR_CLIP_PIXEL(CONV_CSC * (Transpose(YUV) - LVL_OFFSET))) 82 // The matrices LVL_OFFSET and CONV_CSC for different color aspects are below. 83 // 84 // YUV values in the 8bit color bar test videos are in COLOR_BARS_YUV below 85 // 86 // The color conversion matrices (CONV_CSC) for the RGB equation above: 87 // MULTIPLY_ROW_WISE_LR = Transpose({255/219, 255/224, 255/224}) 88 // CONV_FLOAT_601_FR = 89 // {{1, 0, 1.402}, 90 // {1, -0.344136, -0.714136}, 91 // {1, 1.772, 0},} 92 // CONV_FLOAT_709_FR = 93 // {{1, 0, 1.5748}, 94 // {1, -0.1873, -0.4681}, 95 // {1, 1.8556, 0},} 96 // CONV_FLOAT_601_LR = MULTIPLY_ROW_WISE_LR . CONV_FLOAT_601_FR 97 // CONV_FLOAT_709_LR = MULTIPLY_ROW_WISE_LR . CONV_FLOAT_709_FR 98 // 99 // The level shift matrices (LVL_OFFSET) for the RGB equation above: 100 // LVL_OFFSET_LR = Transpose({16, 128, 128}) 101 // LVL_OFFSET_FR = Transpose({0, 128, 128}) 102 103 private static final int[][] COLOR_BARS_YUV = new int[][]{ 104 {126, 191, 230}, 105 {98, 104, 204}, 106 {180, 20, 168}, 107 {121, 109, 60}, 108 {114, 179, 172}, 109 {133, 138, 118}, 110 {183, 93, 153}, 111 {203, 20, 33}, 112 {147, 131, 183}, 113 {40, 177, 202}, 114 {170, 82, 96}, 115 }; 116 117 private static final int[][] COLOR_BARS_YUV_10BIT = new int[][]{ 118 {504, 764, 920}, 119 {392, 416, 816}, 120 {720, 80, 672}, 121 {484, 436, 240}, 122 {456, 716, 688}, 123 {532, 552, 472}, 124 {732, 372, 612}, 125 {812, 80, 132}, 126 {588, 524, 732}, 127 {160, 708, 808}, 128 {680, 328, 384}, 129 }; 130 131 // Reference RGB values for 601 Limited Range 132 private static final int[][] COLOR_BARS_601LR = new int[][]{ 133 {255, 17, 252}, 134 {219, 40, 44}, 135 {255, 196, 0}, 136 {11, 182, 81}, 137 {185, 55, 214}, 138 {119, 137, 153}, 139 {235, 183, 119}, 140 {62, 255, 0}, 141 {242, 103, 155}, 142 {148, 0, 126}, 143 {127, 219, 82}, 144 }; 145 146 // Reference RGB values for 601 Limited Range 10BIT 147 private static final int[][] COLOR_BARS_601LR_10BIT = new int[][]{ 148 {1023, 82, 1023}, 149 {870, 173, 189}, 150 {1022, 805, 0}, 151 {55, 742, 337}, 152 {740, 234, 871}, 153 {483, 564, 628}, 154 {940, 754, 497}, 155 {265, 1023, 0}, 156 {964, 428, 636}, 157 {586, 0, 509}, 158 {515, 896, 347}, 159 }; 160 161 // Reference RGB values for 601 Full Range 162 private static final int[][] COLOR_BARS_601FR = new int[][]{ 163 {255, 31, 237}, 164 {204, 51, 55}, 165 {236, 188, 0}, 166 {25, 176, 87}, 167 {175, 65, 204}, 168 {118, 136, 150}, 169 {218, 177, 120}, 170 {69, 255, 11}, 171 {224, 106, 152}, 172 {143, 0, 126}, 173 {125, 208, 88}, 174 }; 175 176 // Reference RGB values for 601 Full Range 10BIT 177 private static final int[][] COLOR_BARS_601FR_10BIT = new int[][]{ 178 {1023, 126, 951}, 179 {818, 208, 222}, 180 {944, 754, 0}, 181 {103, 704, 349}, 182 {703, 260, 818}, 183 {476, 547, 603}, 184 {872, 709, 484}, 185 {279, 1023, 46}, 186 {897, 427, 609}, 187 {575, 0, 507}, 188 {501, 835, 354}, 189 }; 190 191 // Reference RGB values for 709 Limited Range 192 private static final int[][] COLOR_BARS_709LR = new int[][]{ 193 {255, 57, 255}, 194 {234, 57, 42}, 195 {255, 188, 0}, 196 {0, 159, 79}, 197 {194, 77, 219}, 198 {117, 136, 154}, 199 {240, 184, 116}, 200 {43, 255, 0}, 201 {253, 119, 155}, 202 {163, 0, 130}, 203 {120, 202, 78}, 204 }; 205 206 // Reference RGB values for 709 Limited Range 10BIT 207 private static final int[][] COLOR_BARS_709LR_10BIT = new int[][]{ 208 {1023, 242, 1023}, 209 {930, 241, 180}, 210 {1023, 773, 0}, 211 {2, 652, 330}, 212 {774, 320, 890}, 213 {475, 559, 631}, 214 {960, 757, 484}, 215 {190, 1023, 0}, 216 {1008, 492, 637}, 217 {644, 0, 527}, 218 {489, 827, 330}, 219 }; 220 221 // Reference RGB values for 2020 Limited Range 222 private static final int[][] COLOR_BARS_2020LR = new int[][]{ 223 {1023, 201, 1023}, 224 {895, 203, 177}, 225 {1023, 743, 0}, 226 {33, 682, 327}, 227 {754, 305, 896}, 228 {479, 565, 633}, 229 {949, 741, 479}, 230 {234, 1023, 0}, 231 {982, 466, 638}, 232 {610, 0, 533}, 233 {504, 837, 324}, 234 }; 235 236 // Reference RGB values for 2020 Full Range 237 private static final int[][] COLOR_BARS_2020FR = new int[][]{ 238 {1023, 229, 978}, 239 {840, 234, 211}, 240 {956, 700, 0}, 241 {83, 652, 341}, 242 {716, 322, 840}, 243 {473, 548, 607}, 244 {879, 698, 469}, 245 {252, 1023, 0}, 246 {912, 460, 611}, 247 {596, 0, 529}, 248 {491, 783, 334}, 249 }; 250 251 // The test videos were generated with the above color bars. Each bar is of width 16. 252 private static final int COLOR_BAR_WIDTH = 16; 253 private static final int COLOR_BAR_OFFSET_X = 8; 254 private static final int COLOR_BAR_OFFSET_Y = 64; 255 256 private final int mRange; 257 private final int mStandard; 258 private final int mTransferCurve; 259 private final boolean mUseYuvSampling; 260 private final boolean mUseHighBitDepth; 261 262 private int[][] mColorBars; 263 private int mWidth; 264 private int mHeight; 265 private OutputSurface mEGLWindowOutSurface; 266 private int mBadFrames = 0; 267 DecodeGlAccuracyTest(String decoder, String mediaType, String fileName, int range, int standard, int transfer, boolean useHighBitDepth, boolean useYuvSampling, String allTestParams)268 public DecodeGlAccuracyTest(String decoder, String mediaType, String fileName, int range, 269 int standard, int transfer, boolean useHighBitDepth, boolean useYuvSampling, 270 String allTestParams) { 271 super(decoder, mediaType, MEDIA_DIR + fileName, allTestParams); 272 mRange = range; 273 mStandard = standard; 274 mTransferCurve = transfer; 275 mUseYuvSampling = useYuvSampling; 276 mUseHighBitDepth = useHighBitDepth; 277 278 if (!mUseYuvSampling) { 279 mColorBars = COLOR_BARS_601LR; 280 if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) && (mRange 281 == MediaFormat.COLOR_RANGE_LIMITED)) { 282 mColorBars = mUseHighBitDepth ? COLOR_BARS_601LR_10BIT : COLOR_BARS_601LR; 283 } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT601_NTSC) && (mRange 284 == MediaFormat.COLOR_RANGE_FULL)) { 285 mColorBars = mUseHighBitDepth ? COLOR_BARS_601FR_10BIT : COLOR_BARS_601FR; 286 } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT709) && (mRange 287 == MediaFormat.COLOR_RANGE_LIMITED)) { 288 mColorBars = mUseHighBitDepth ? COLOR_BARS_709LR_10BIT : COLOR_BARS_709LR; 289 } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT2020) && (mRange 290 == MediaFormat.COLOR_RANGE_LIMITED)) { 291 mColorBars = COLOR_BARS_2020LR; 292 } else if ((mStandard == MediaFormat.COLOR_STANDARD_BT2020) && (mRange 293 == MediaFormat.COLOR_RANGE_FULL)) { 294 mColorBars = COLOR_BARS_2020FR; 295 } else { 296 Log.e(LOG_TAG, "Unsupported Color Aspects."); 297 } 298 } else { 299 mColorBars = mUseHighBitDepth ? COLOR_BARS_YUV_10BIT : COLOR_BARS_YUV; 300 } 301 } 302 303 @After tearDown()304 public void tearDown() { 305 mSurface = null; 306 if (mEGLWindowOutSurface != null) { 307 mEGLWindowOutSurface.release(); 308 mEGLWindowOutSurface = null; 309 } 310 } 311 312 @Parameterized.Parameters(name = "{index}_{0}_{1}_{3}_{4}_{5}_{6}_{7}") input()313 public static Collection<Object[]> input() { 314 final boolean isEncoder = false; 315 final boolean needAudio = false; 316 final boolean needVideo = true; 317 318 final List<Object[]> argsList = Arrays.asList(new Object[][]{ 319 // mediaType, asset, range, standard, transfer, mUseHighBitDepth 320 // 601LR 321 {MediaFormat.MIMETYPE_VIDEO_AVC, "color_bands_176x176_h264_8bit.mp4", 322 MediaFormat.COLOR_RANGE_LIMITED, 323 MediaFormat.COLOR_STANDARD_BT601_NTSC, 324 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 325 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_8bit.mp4", 326 MediaFormat.COLOR_RANGE_LIMITED, 327 MediaFormat.COLOR_STANDARD_BT601_NTSC, 328 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 329 {MediaFormat.MIMETYPE_VIDEO_VP8, "color_bands_176x176_vp8_8bit.webm", 330 MediaFormat.COLOR_RANGE_LIMITED, 331 MediaFormat.COLOR_STANDARD_BT601_NTSC, 332 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 333 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_8bit.webm", 334 MediaFormat.COLOR_RANGE_LIMITED, 335 MediaFormat.COLOR_STANDARD_BT601_NTSC, 336 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 337 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_8bit.webm", 338 MediaFormat.COLOR_RANGE_LIMITED, 339 MediaFormat.COLOR_STANDARD_BT601_NTSC, 340 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 341 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_10bit.mp4", 342 MediaFormat.COLOR_RANGE_LIMITED, 343 MediaFormat.COLOR_STANDARD_BT601_NTSC, 344 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 345 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_10bit.webm", 346 MediaFormat.COLOR_RANGE_LIMITED, 347 MediaFormat.COLOR_STANDARD_BT601_NTSC, 348 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 349 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_10bit.webm", 350 MediaFormat.COLOR_RANGE_LIMITED, 351 MediaFormat.COLOR_STANDARD_BT601_NTSC, 352 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 353 354 // 601FR 355 {MediaFormat.MIMETYPE_VIDEO_AVC, "color_bands_176x176_h264_8bit_fr.mp4", 356 MediaFormat.COLOR_RANGE_FULL, 357 MediaFormat.COLOR_STANDARD_BT601_NTSC, 358 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 359 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_8bit_fr.mp4", 360 MediaFormat.COLOR_RANGE_FULL, 361 MediaFormat.COLOR_STANDARD_BT601_NTSC, 362 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 363 {MediaFormat.MIMETYPE_VIDEO_VP8, "color_bands_176x176_vp8_8bit_fr.webm", 364 MediaFormat.COLOR_RANGE_FULL, 365 MediaFormat.COLOR_STANDARD_BT601_NTSC, 366 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 367 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_8bit_fr.webm", 368 MediaFormat.COLOR_RANGE_FULL, 369 MediaFormat.COLOR_STANDARD_BT601_NTSC, 370 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 371 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_8bit_fr.webm", 372 MediaFormat.COLOR_RANGE_FULL, 373 MediaFormat.COLOR_STANDARD_BT601_NTSC, 374 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 375 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_10bit_fr.mp4", 376 MediaFormat.COLOR_RANGE_FULL, 377 MediaFormat.COLOR_STANDARD_BT601_NTSC, 378 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 379 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_10bit_fr.webm", 380 MediaFormat.COLOR_RANGE_FULL, 381 MediaFormat.COLOR_STANDARD_BT601_NTSC, 382 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 383 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_10bit_fr.webm", 384 MediaFormat.COLOR_RANGE_FULL, 385 MediaFormat.COLOR_STANDARD_BT601_NTSC, 386 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 387 388 // 709LR 389 {MediaFormat.MIMETYPE_VIDEO_AVC, "color_bands_176x176_h264_8bit.mp4", 390 MediaFormat.COLOR_RANGE_LIMITED, 391 MediaFormat.COLOR_STANDARD_BT709, 392 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 393 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_8bit.mp4", 394 MediaFormat.COLOR_RANGE_LIMITED, 395 MediaFormat.COLOR_STANDARD_BT709, 396 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 397 {MediaFormat.MIMETYPE_VIDEO_VP8, "color_bands_176x176_vp8_8bit.webm", 398 MediaFormat.COLOR_RANGE_LIMITED, 399 MediaFormat.COLOR_STANDARD_BT709, 400 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 401 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_8bit.webm", 402 MediaFormat.COLOR_RANGE_LIMITED, 403 MediaFormat.COLOR_STANDARD_BT709, 404 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 405 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_8bit.webm", 406 MediaFormat.COLOR_RANGE_LIMITED, 407 MediaFormat.COLOR_STANDARD_BT709, 408 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, false}, 409 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_10bit.mp4", 410 MediaFormat.COLOR_RANGE_LIMITED, 411 MediaFormat.COLOR_STANDARD_BT709, 412 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 413 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_10bit.webm", 414 MediaFormat.COLOR_RANGE_LIMITED, 415 MediaFormat.COLOR_STANDARD_BT709, 416 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 417 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_10bit.webm", 418 MediaFormat.COLOR_RANGE_LIMITED, 419 MediaFormat.COLOR_STANDARD_BT709, 420 MediaFormat.COLOR_TRANSFER_SDR_VIDEO, true}, 421 // Note: OpenGL is not required to support 709 FR. So we are not testing it. 422 423 // BT2020LR 424 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_10bit.mp4", 425 MediaFormat.COLOR_RANGE_LIMITED, 426 MediaFormat.COLOR_STANDARD_BT2020, 427 MediaFormat.COLOR_TRANSFER_ST2084, true}, 428 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_10bit.webm", 429 MediaFormat.COLOR_RANGE_LIMITED, 430 MediaFormat.COLOR_STANDARD_BT2020, 431 MediaFormat.COLOR_TRANSFER_ST2084, true}, 432 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_10bit.webm", 433 MediaFormat.COLOR_RANGE_LIMITED, 434 MediaFormat.COLOR_STANDARD_BT2020, 435 MediaFormat.COLOR_TRANSFER_ST2084, true}, 436 437 // BT2020FR 438 {MediaFormat.MIMETYPE_VIDEO_HEVC, "color_bands_176x176_hevc_10bit_fr.mp4", 439 MediaFormat.COLOR_RANGE_FULL, 440 MediaFormat.COLOR_STANDARD_BT2020, 441 MediaFormat.COLOR_TRANSFER_ST2084, true}, 442 {MediaFormat.MIMETYPE_VIDEO_VP9, "color_bands_176x176_vp9_10bit_fr.webm", 443 MediaFormat.COLOR_RANGE_FULL, 444 MediaFormat.COLOR_STANDARD_BT2020, 445 MediaFormat.COLOR_TRANSFER_ST2084, true}, 446 {MediaFormat.MIMETYPE_VIDEO_AV1, "color_bands_176x176_av1_10bit_fr.webm", 447 MediaFormat.COLOR_RANGE_FULL, 448 MediaFormat.COLOR_STANDARD_BT2020, 449 MediaFormat.COLOR_TRANSFER_ST2084, true}, 450 451 }); 452 final List<Object[]> exhaustiveArgsList = new ArrayList<>(); 453 for (Object[] arg : argsList) { 454 int argLength = argsList.get(0).length; 455 boolean[] boolStates = {true, false}; 456 for (boolean useYuvSampling : boolStates) { 457 Object[] testArgs = new Object[argLength + 1]; 458 System.arraycopy(arg, 0, testArgs, 0, argLength); 459 testArgs[argLength] = useYuvSampling; 460 exhaustiveArgsList.add(testArgs); 461 } 462 } 463 return CodecTestBase.prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, 464 false); 465 } 466 isColorClose(int actual, int expected)467 boolean isColorClose(int actual, int expected) { 468 int delta = Math.abs(actual - expected); 469 return (delta <= ALLOWED_COLOR_DELTA); 470 } 471 checkSurfaceFrame(int frameIndex)472 private boolean checkSurfaceFrame(int frameIndex) { 473 ByteBuffer pixelBuf = ByteBuffer.allocateDirect(4); 474 boolean frameFailed = false; 475 for (int i = 0; i < mColorBars.length; i++) { 476 int x = COLOR_BAR_WIDTH * i + COLOR_BAR_OFFSET_X; 477 int y = COLOR_BAR_OFFSET_Y; 478 int r, g, b; 479 if (mUseHighBitDepth) { 480 GLES20.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GLES30.GL_UNSIGNED_INT_2_10_10_10_REV, 481 pixelBuf); 482 r = (pixelBuf.get(1) & 0x03) << 8 | (pixelBuf.get(0) & 0xFF); 483 g = (pixelBuf.get(2) & 0x0F) << 6 | ((pixelBuf.get(1) >> 2) & 0x3F); 484 b = (pixelBuf.get(3) & 0x3F) << 4 | ((pixelBuf.get(2) >> 4) & 0x0F); 485 } else { 486 GLES20.glReadPixels(x, y, 1, 1, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuf); 487 r = pixelBuf.get(0) & 0xff; 488 g = pixelBuf.get(1) & 0xff; 489 b = pixelBuf.get(2) & 0xff; 490 } 491 if (!(isColorClose(r, mColorBars[i][0]) && 492 isColorClose(g, mColorBars[i][1]) && 493 isColorClose(b, mColorBars[i][2]))) { 494 Log.w(LOG_TAG, "Bad frame " + frameIndex + " (rect={" + x + " " + y + "} :rgb=" + 495 r + "," + g + "," + b + " vs. expected " + mColorBars[i][0] + 496 "," + mColorBars[i][1] + "," + mColorBars[i][2] + ")"); 497 frameFailed = true; 498 } 499 } 500 return frameFailed; 501 } 502 dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)503 protected void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) { 504 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 505 mSawOutputEOS = true; 506 } 507 if (ENABLE_LOGS) { 508 Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " + 509 info.size + " timestamp: " + info.presentationTimeUs); 510 } 511 if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 512 mOutputBuff.saveOutPTS(info.presentationTimeUs); 513 mOutputCount++; 514 } 515 mCodec.releaseOutputBuffer(bufferIndex, mSurface != null); 516 if (info.size > 0) { 517 mEGLWindowOutSurface.awaitNewImage(); 518 mEGLWindowOutSurface.drawImage(); 519 if (checkSurfaceFrame(mOutputCount - 1)) mBadFrames++; 520 } 521 } 522 523 /** 524 * The test decodes video assets with color bars and outputs frames to OpenGL input surface. 525 * The OpenGL fragment shader reads the frame buffers as external textures and renders to 526 * a pbuffer. The output RGB values are read and compared against the expected values. 527 */ 528 @CddTest(requirements = {"5.12/C-7-4"}) 529 @ApiTest(apis = {"android.media.MediaFormat#KEY_COLOR_RANGE", 530 "android.media.MediaFormat#KEY_COLOR_STANDARD", 531 "android.media.MediaFormat#KEY_COLOR_TRANSFER"}) 532 @LargeTest 533 @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS) testDecodeGlAccuracyRGB()534 public void testDecodeGlAccuracyRGB() throws IOException, InterruptedException { 535 if (mUseHighBitDepth && !isVendorCodec(mCodecName)) { 536 if (hasSupportForColorFormat(mCodecName, mMediaType, COLOR_FormatYUVP010)) { 537 if (!mUseYuvSampling) { 538 // TODO (b/219748700): Android software codecs work only with BT2020 FR. 539 assumeTrue("Skipping " + mCodecName + " for color range " + mRange 540 + " and color standard " + mStandard, 541 mRange == MediaFormat.COLOR_RANGE_FULL 542 && mStandard == MediaFormat.COLOR_STANDARD_BT2020); 543 } 544 } else { 545 // TODO (b/259321347): Skip yuv sampling in high bit depth cases for software codecs 546 assumeTrue("Skipping " + mCodecName + " for high bit depth YUV sampling tests " 547 + "when codec doesn't support P010", !mUseYuvSampling); 548 } 549 } 550 551 if (mRange != MediaFormat.COLOR_RANGE_LIMITED 552 || mStandard != MediaFormat.COLOR_STANDARD_BT601_NTSC) { 553 // Prior to Android T, only BT601 limited range support was tested. Hence 554 // limit testing other color spaces to devices launching with T 555 assumeTrue("Skipping color range " + mRange + " and color standard " + mStandard + 556 " for devices upgrading to T", 557 FIRST_SDK_IS_AT_LEAST_T && VNDK_IS_AT_LEAST_T); 558 559 // TODO (b/219748700): Android software codecs work only with 601LR. Skip for now. 560 assumeTrue("Skipping " + mCodecName + " for color range " + mRange 561 + " and color standard " + mStandard, 562 isVendorCodec(mCodecName)); 563 } 564 565 MediaFormat format = setUpSource(mTestFile); 566 567 // Set color parameters 568 format.setInteger(MediaFormat.KEY_COLOR_RANGE, mRange); 569 format.setInteger(MediaFormat.KEY_COLOR_STANDARD, mStandard); 570 format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, mTransferCurve); 571 572 // Set the format to surface mode 573 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface); 574 575 mWidth = format.getInteger(MediaFormat.KEY_WIDTH); 576 mHeight = format.getInteger(MediaFormat.KEY_HEIGHT); 577 if (mUseHighBitDepth) { 578 SupportClass supportRequirements = 579 mMediaType.equals(MediaFormat.MIMETYPE_VIDEO_AV1) ? CODEC_ALL : CODEC_OPTIONAL; 580 ArrayList<MediaFormat> formatList = new ArrayList<>(); 581 formatList.add(format); 582 checkFormatSupport(mCodecName, mMediaType, false, formatList, null, 583 supportRequirements); 584 } 585 mEGLWindowOutSurface = 586 new OutputSurface(mWidth, mHeight, mUseHighBitDepth, mUseYuvSampling); 587 588 // If device supports HDR editing, then GL_EXT_YUV_target extension support is mandatory 589 if (mUseYuvSampling) { 590 String message = "Device doesn't support EXT_YUV_target GL extension \n" + mTestConfig 591 + mTestEnv; 592 if (IS_AT_LEAST_T && (IS_HDR_EDITING_SUPPORTED || IS_HLG_EDITING_SUPPORTED)) { 593 assertTrue(message, mEGLWindowOutSurface.getEXTYuvTargetSupported()); 594 } else { 595 assumeTrue(message, mEGLWindowOutSurface.getEXTYuvTargetSupported()); 596 } 597 } 598 599 mSurface = mEGLWindowOutSurface.getSurface(); 600 601 mCodec = MediaCodec.createByCodecName(mCodecName); 602 configureCodec(format, true, true, false); 603 mOutputBuff = new OutputManager(); 604 mCodec.start(); 605 doWork(Integer.MAX_VALUE); 606 queueEOS(); 607 waitForAllOutputs(); 608 validateColorAspects(mCodec.getOutputFormat(), mRange, mStandard, mTransferCurve); 609 mCodec.stop(); 610 mCodec.release(); 611 tearDown(); 612 613 assertEquals("color difference exceeds allowed tolerance in " + mBadFrames + " out of " 614 + mOutputCount + " frames \n" + mTestConfig + mTestEnv, 0, mBadFrames); 615 } 616 } 617 618