Home | History | Annotate | Download | only in webrtc
      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