1 /* 2 * libjingle 3 * Copyright 2015 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 package org.webrtc; 29 30 import android.graphics.Point; 31 import android.test.ActivityTestCase; 32 import android.test.suitebuilder.annotation.MediumTest; 33 import android.view.View.MeasureSpec; 34 35 import java.nio.ByteBuffer; 36 import java.util.Arrays; 37 import java.util.List; 38 39 public final class SurfaceViewRendererOnMeasureTest extends ActivityTestCase { 40 /** 41 * List with all possible scaling types. 42 */ 43 private static final List<RendererCommon.ScalingType> scalingTypes = Arrays.asList( 44 RendererCommon.ScalingType.SCALE_ASPECT_FIT, 45 RendererCommon.ScalingType.SCALE_ASPECT_FILL, 46 RendererCommon.ScalingType.SCALE_ASPECT_BALANCED); 47 48 /** 49 * List with MeasureSpec modes. 50 */ 51 private static final List<Integer> measureSpecModes = 52 Arrays.asList(MeasureSpec.EXACTLY, MeasureSpec.AT_MOST); 53 54 /** 55 * Returns a dummy YUV frame. 56 */ 57 static VideoRenderer.I420Frame createFrame(int width, int height, int rotationDegree) { 58 final int[] yuvStrides = new int[] {width, (width + 1) / 2, (width + 1) / 2}; 59 final int[] yuvHeights = new int[] {height, (height + 1) / 2, (height + 1) / 2}; 60 final ByteBuffer[] yuvPlanes = new ByteBuffer[3]; 61 for (int i = 0; i < 3; ++i) { 62 yuvPlanes[i] = ByteBuffer.allocateDirect(yuvStrides[i] * yuvHeights[i]); 63 } 64 return new VideoRenderer.I420Frame(width, height, rotationDegree, yuvStrides, yuvPlanes, 0); 65 } 66 67 /** 68 * Assert onMeasure() with given parameters will result in expected measured size. 69 */ 70 private static void assertMeasuredSize( 71 SurfaceViewRenderer surfaceViewRenderer, RendererCommon.ScalingType scalingType, 72 String frameDimensions, 73 int expectedWidth, int expectedHeight, 74 int widthSpec, int heightSpec) { 75 surfaceViewRenderer.setScalingType(scalingType); 76 surfaceViewRenderer.onMeasure(widthSpec, heightSpec); 77 final int measuredWidth = surfaceViewRenderer.getMeasuredWidth(); 78 final int measuredHeight = surfaceViewRenderer.getMeasuredHeight(); 79 if (measuredWidth != expectedWidth || measuredHeight != expectedHeight) { 80 fail("onMeasure(" 81 + MeasureSpec.toString(widthSpec) + ", " + MeasureSpec.toString(heightSpec) + ")" 82 + " with scaling type " + scalingType 83 + " and frame: " + frameDimensions 84 + " expected measured size " + expectedWidth + "x" + expectedHeight 85 + ", but was " + measuredWidth + "x" + measuredHeight); 86 } 87 } 88 89 /** 90 * Test how SurfaceViewRenderer.onMeasure() behaves when no frame has been delivered. 91 */ 92 @MediumTest 93 public void testNoFrame() { 94 final SurfaceViewRenderer surfaceViewRenderer = 95 new SurfaceViewRenderer(getInstrumentation().getContext()); 96 final String frameDimensions = "null"; 97 98 // Test behaviour before SurfaceViewRenderer.init() is called. 99 for (RendererCommon.ScalingType scalingType : scalingTypes) { 100 for (int measureSpecMode : measureSpecModes) { 101 final int zeroMeasureSize = MeasureSpec.makeMeasureSpec(0, measureSpecMode); 102 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 103 0, 0, zeroMeasureSize, zeroMeasureSize); 104 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 105 1280, 720, 106 MeasureSpec.makeMeasureSpec(1280, measureSpecMode), 107 MeasureSpec.makeMeasureSpec(720, measureSpecMode)); 108 } 109 } 110 111 // Test behaviour after SurfaceViewRenderer.init() is called, but still no frame. 112 surfaceViewRenderer.init((EglBase.Context) null, null); 113 for (RendererCommon.ScalingType scalingType : scalingTypes) { 114 for (int measureSpecMode : measureSpecModes) { 115 final int zeroMeasureSize = MeasureSpec.makeMeasureSpec(0, measureSpecMode); 116 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 117 0, 0, zeroMeasureSize, zeroMeasureSize); 118 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 119 1280, 720, 120 MeasureSpec.makeMeasureSpec(1280, measureSpecMode), 121 MeasureSpec.makeMeasureSpec(720, measureSpecMode)); 122 } 123 } 124 125 surfaceViewRenderer.release(); 126 } 127 128 /** 129 * Test how SurfaceViewRenderer.onMeasure() behaves with a 1280x720 frame. 130 */ 131 @MediumTest 132 public void testFrame1280x720() { 133 final SurfaceViewRenderer surfaceViewRenderer = 134 new SurfaceViewRenderer(getInstrumentation().getContext()); 135 surfaceViewRenderer.init((EglBase.Context) null, null); 136 137 // Test different rotation degress, but same rotated size. 138 for (int rotationDegree : new int[] {0, 90, 180, 270}) { 139 final int rotatedWidth = 1280; 140 final int rotatedHeight = 720; 141 final int unrotatedWidth = (rotationDegree % 180 == 0 ? rotatedWidth : rotatedHeight); 142 final int unrotatedHeight = (rotationDegree % 180 == 0 ? rotatedHeight : rotatedWidth); 143 final VideoRenderer.I420Frame frame = 144 createFrame(unrotatedWidth, unrotatedHeight, rotationDegree); 145 assertEquals(rotatedWidth, frame.rotatedWidth()); 146 assertEquals(rotatedHeight, frame.rotatedHeight()); 147 final String frameDimensions = 148 unrotatedWidth + "x" + unrotatedHeight + " with rotation " + rotationDegree; 149 surfaceViewRenderer.renderFrame(frame); 150 151 // Test forcing to zero size. 152 for (RendererCommon.ScalingType scalingType : scalingTypes) { 153 for (int measureSpecMode : measureSpecModes) { 154 final int zeroMeasureSize = MeasureSpec.makeMeasureSpec(0, measureSpecMode); 155 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 156 0, 0, zeroMeasureSize, zeroMeasureSize); 157 } 158 } 159 160 // Test perfect fit. 161 for (RendererCommon.ScalingType scalingType : scalingTypes) { 162 for (int measureSpecMode : measureSpecModes) { 163 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 164 rotatedWidth, rotatedHeight, 165 MeasureSpec.makeMeasureSpec(rotatedWidth, measureSpecMode), 166 MeasureSpec.makeMeasureSpec(rotatedHeight, measureSpecMode)); 167 } 168 } 169 170 // Force spec size with different aspect ratio than frame aspect ratio. 171 for (RendererCommon.ScalingType scalingType : scalingTypes) { 172 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 173 720, 1280, 174 MeasureSpec.makeMeasureSpec(720, MeasureSpec.EXACTLY), 175 MeasureSpec.makeMeasureSpec(1280, MeasureSpec.EXACTLY)); 176 } 177 178 final float videoAspectRatio = (float) rotatedWidth / rotatedHeight; 179 { 180 // Relax both width and height constraints. 181 final int widthSpec = MeasureSpec.makeMeasureSpec(720, MeasureSpec.AT_MOST); 182 final int heightSpec = MeasureSpec.makeMeasureSpec(1280, MeasureSpec.AT_MOST); 183 for (RendererCommon.ScalingType scalingType : scalingTypes) { 184 final Point expectedSize = 185 RendererCommon.getDisplaySize(scalingType, videoAspectRatio, 720, 1280); 186 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 187 expectedSize.x, expectedSize.y, widthSpec, heightSpec); 188 } 189 } 190 { 191 // Force width to 720, but relax height constraint. This will give the same result as 192 // above, because width is already the limiting factor and will be maxed out. 193 final int widthSpec = MeasureSpec.makeMeasureSpec(720, MeasureSpec.EXACTLY); 194 final int heightSpec = MeasureSpec.makeMeasureSpec(1280, MeasureSpec.AT_MOST); 195 for (RendererCommon.ScalingType scalingType : scalingTypes) { 196 final Point expectedSize = 197 RendererCommon.getDisplaySize(scalingType, videoAspectRatio, 720, 1280); 198 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 199 expectedSize.x, expectedSize.y, widthSpec, heightSpec); 200 } 201 } 202 { 203 // Force height, but relax width constraint. This will force a bad layout size. 204 final int widthSpec = MeasureSpec.makeMeasureSpec(720, MeasureSpec.AT_MOST); 205 final int heightSpec = MeasureSpec.makeMeasureSpec(1280, MeasureSpec.EXACTLY); 206 for (RendererCommon.ScalingType scalingType : scalingTypes) { 207 assertMeasuredSize(surfaceViewRenderer, scalingType, frameDimensions, 208 720, 1280, widthSpec, heightSpec); 209 } 210 } 211 } 212 213 surfaceViewRenderer.release(); 214 } 215 } 216