1 /* 2 * Copyright 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 package com.google.android.exoplayer2.transformer; 17 18 import static androidx.test.core.app.ApplicationProvider.getApplicationContext; 19 import static com.google.android.exoplayer2.transformer.BitmapTestUtil.FIRST_FRAME_PNG_ASSET_STRING; 20 import static com.google.android.exoplayer2.transformer.BitmapTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE; 21 import static com.google.android.exoplayer2.transformer.BitmapTestUtil.ROTATE_90_EXPECTED_OUTPUT_PNG_ASSET_STRING; 22 import static com.google.android.exoplayer2.transformer.BitmapTestUtil.SCALE_NARROW_EXPECTED_OUTPUT_PNG_ASSET_STRING; 23 import static com.google.android.exoplayer2.transformer.BitmapTestUtil.TRANSLATE_RIGHT_EXPECTED_OUTPUT_PNG_ASSET_STRING; 24 import static com.google.common.truth.Truth.assertThat; 25 26 import android.graphics.Bitmap; 27 import android.graphics.Matrix; 28 import android.graphics.SurfaceTexture; 29 import android.opengl.EGLContext; 30 import android.opengl.EGLDisplay; 31 import android.opengl.EGLSurface; 32 import androidx.test.ext.junit.runners.AndroidJUnit4; 33 import com.google.android.exoplayer2.util.GlUtil; 34 import java.io.IOException; 35 import org.checkerframework.checker.nullness.qual.MonotonicNonNull; 36 import org.junit.After; 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 /** 42 * Pixel test for frame processing via {@link AdvancedFrameProcessor}. 43 * 44 * <p>Expected images are taken from an emulator, so tests on different emulators or physical 45 * devices may fail. To test on other devices, please increase the {@link 46 * BitmapTestUtil#MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE} and/or inspect the saved output bitmaps 47 * as recommended in {@link FrameProcessorChainPixelTest}. 48 */ 49 @RunWith(AndroidJUnit4.class) 50 public final class AdvancedFrameProcessorPixelTest { 51 52 static { 53 GlUtil.glAssertionsEnabled = true; 54 } 55 56 private final EGLDisplay eglDisplay = GlUtil.createEglDisplay(); 57 private final EGLContext eglContext = GlUtil.createEglContext(eglDisplay); 58 private @MonotonicNonNull GlFrameProcessor advancedFrameProcessor; 59 private int inputTexId; 60 private int outputTexId; 61 private int width; 62 private int height; 63 64 @Before createTextures()65 public void createTextures() throws IOException { 66 Bitmap inputBitmap = BitmapTestUtil.readBitmap(FIRST_FRAME_PNG_ASSET_STRING); 67 width = inputBitmap.getWidth(); 68 height = inputBitmap.getHeight(); 69 // This surface is needed for focussing a render target, but the tests don't write output to it. 70 // The frame processor's output is written to a framebuffer instead. 71 EGLSurface eglSurface = GlUtil.getEglSurface(eglDisplay, new SurfaceTexture(false)); 72 GlUtil.focusEglSurface(eglDisplay, eglContext, eglSurface, width, height); 73 inputTexId = 74 BitmapTestUtil.createGlTextureFromBitmap( 75 BitmapTestUtil.readBitmap(FIRST_FRAME_PNG_ASSET_STRING)); 76 outputTexId = GlUtil.createTexture(width, height); 77 int frameBuffer = GlUtil.createFboForTexture(outputTexId); 78 GlUtil.focusFramebuffer(eglDisplay, eglContext, eglSurface, frameBuffer, width, height); 79 } 80 81 @After release()82 public void release() { 83 if (advancedFrameProcessor != null) { 84 advancedFrameProcessor.release(); 85 } 86 GlUtil.destroyEglContext(eglDisplay, eglContext); 87 } 88 89 @Test updateProgramAndDraw_noEdits_producesExpectedOutput()90 public void updateProgramAndDraw_noEdits_producesExpectedOutput() throws Exception { 91 String testId = "updateProgramAndDraw_noEdits"; 92 Matrix identityMatrix = new Matrix(); 93 advancedFrameProcessor = new AdvancedFrameProcessor(getApplicationContext(), identityMatrix); 94 advancedFrameProcessor.initialize(inputTexId, width, height); 95 Bitmap expectedBitmap = BitmapTestUtil.readBitmap(FIRST_FRAME_PNG_ASSET_STRING); 96 97 advancedFrameProcessor.updateProgramAndDraw(/* presentationTimeUs= */ 0); 98 Bitmap actualBitmap = 99 BitmapTestUtil.createArgb8888BitmapFromCurrentGlFramebuffer(width, height); 100 101 // TODO(b/207848601): switch to using proper tooling for testing against golden data. 102 float averagePixelAbsoluteDifference = 103 BitmapTestUtil.getAveragePixelAbsoluteDifferenceArgb8888( 104 expectedBitmap, actualBitmap, testId); 105 BitmapTestUtil.saveTestBitmapToCacheDirectory( 106 testId, /* bitmapLabel= */ "actual", actualBitmap, /* throwOnFailure= */ false); 107 assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE); 108 } 109 110 @Test updateProgramAndDraw_translateRight_producesExpectedOutput()111 public void updateProgramAndDraw_translateRight_producesExpectedOutput() throws Exception { 112 String testId = "updateProgramAndDraw_translateRight"; 113 Matrix translateRightMatrix = new Matrix(); 114 translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0); 115 advancedFrameProcessor = 116 new AdvancedFrameProcessor(getApplicationContext(), translateRightMatrix); 117 advancedFrameProcessor.initialize(inputTexId, width, height); 118 Bitmap expectedBitmap = 119 BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_EXPECTED_OUTPUT_PNG_ASSET_STRING); 120 121 advancedFrameProcessor.updateProgramAndDraw(/* presentationTimeUs= */ 0); 122 Bitmap actualBitmap = 123 BitmapTestUtil.createArgb8888BitmapFromCurrentGlFramebuffer(width, height); 124 125 // TODO(b/207848601): switch to using proper tooling for testing against golden data. 126 float averagePixelAbsoluteDifference = 127 BitmapTestUtil.getAveragePixelAbsoluteDifferenceArgb8888( 128 expectedBitmap, actualBitmap, testId); 129 BitmapTestUtil.saveTestBitmapToCacheDirectory( 130 testId, /* bitmapLabel= */ "actual", actualBitmap, /* throwOnFailure= */ false); 131 assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE); 132 } 133 134 @Test updateProgramAndDraw_scaleNarrow_producesExpectedOutput()135 public void updateProgramAndDraw_scaleNarrow_producesExpectedOutput() throws Exception { 136 String testId = "updateProgramAndDraw_scaleNarrow"; 137 Matrix scaleNarrowMatrix = new Matrix(); 138 scaleNarrowMatrix.postScale(.5f, 1.2f); 139 advancedFrameProcessor = new AdvancedFrameProcessor(getApplicationContext(), scaleNarrowMatrix); 140 advancedFrameProcessor.initialize(inputTexId, width, height); 141 Bitmap expectedBitmap = 142 BitmapTestUtil.readBitmap(SCALE_NARROW_EXPECTED_OUTPUT_PNG_ASSET_STRING); 143 144 advancedFrameProcessor.updateProgramAndDraw(/* presentationTimeUs= */ 0); 145 Bitmap actualBitmap = 146 BitmapTestUtil.createArgb8888BitmapFromCurrentGlFramebuffer(width, height); 147 148 // TODO(b/207848601): switch to using proper tooling for testing against golden data. 149 float averagePixelAbsoluteDifference = 150 BitmapTestUtil.getAveragePixelAbsoluteDifferenceArgb8888( 151 expectedBitmap, actualBitmap, testId); 152 BitmapTestUtil.saveTestBitmapToCacheDirectory( 153 testId, /* bitmapLabel= */ "actual", actualBitmap, /* throwOnFailure= */ false); 154 assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE); 155 } 156 157 @Test updateProgramAndDraw_rotate90_producesExpectedOutput()158 public void updateProgramAndDraw_rotate90_producesExpectedOutput() throws Exception { 159 String testId = "updateProgramAndDraw_rotate90"; 160 Matrix rotate90Matrix = new Matrix(); 161 rotate90Matrix.postRotate(/* degrees= */ 90); 162 advancedFrameProcessor = new AdvancedFrameProcessor(getApplicationContext(), rotate90Matrix); 163 advancedFrameProcessor.initialize(inputTexId, width, height); 164 Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_90_EXPECTED_OUTPUT_PNG_ASSET_STRING); 165 166 advancedFrameProcessor.updateProgramAndDraw(/* presentationTimeUs= */ 0); 167 Bitmap actualBitmap = 168 BitmapTestUtil.createArgb8888BitmapFromCurrentGlFramebuffer(width, height); 169 170 // TODO(b/207848601): switch to using proper tooling for testing against golden data. 171 float averagePixelAbsoluteDifference = 172 BitmapTestUtil.getAveragePixelAbsoluteDifferenceArgb8888( 173 expectedBitmap, actualBitmap, testId); 174 BitmapTestUtil.saveTestBitmapToCacheDirectory( 175 testId, /* bitmapLabel= */ "actual", actualBitmap, /* throwOnFailure= */ false); 176 assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE); 177 } 178 } 179