Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2016 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 com.android.incallui.videosurface.impl;
     18 
     19 import android.graphics.Matrix;
     20 import android.view.TextureView;
     21 import com.android.dialer.common.LogUtil;
     22 
     23 /** Utilities to scale the preview and remote video. */
     24 public class VideoScale {
     25   /**
     26    * Scales the video in the given view such that the video takes up the entire view. To maintain
     27    * aspect ratio the video will be scaled to be larger than the view.
     28    */
     29   public static void scaleVideoAndFillView(
     30       TextureView textureView, float videoWidth, float videoHeight, float rotationDegrees) {
     31     float viewWidth = textureView.getWidth();
     32     float viewHeight = textureView.getHeight();
     33     float viewAspectRatio = viewWidth / viewHeight;
     34     float videoAspectRatio = videoWidth / videoHeight;
     35     float scaleWidth = 1.0f;
     36     float scaleHeight = 1.0f;
     37 
     38     if (viewAspectRatio > videoAspectRatio) {
     39       // Scale to exactly fit the width of the video. The top and bottom will be cropped.
     40       float scaleFactor = viewWidth / videoWidth;
     41       float desiredScaledHeight = videoHeight * scaleFactor;
     42       scaleHeight = desiredScaledHeight / viewHeight;
     43     } else {
     44       // Scale to exactly fit the height of the video. The sides will be cropped.
     45       float scaleFactor = viewHeight / videoHeight;
     46       float desiredScaledWidth = videoWidth * scaleFactor;
     47       scaleWidth = desiredScaledWidth / viewWidth;
     48     }
     49 
     50     if (rotationDegrees == 90.0f || rotationDegrees == 270.0f) {
     51       // We're in landscape mode but the camera feed is still drawing in portrait mode. Normally,
     52       // scale of 1.0 means that the video feed stretches to fit the view. In this case the X axis
     53       // is scaled to fit the height and the Y axis is scaled to fit the width.
     54       float scaleX = scaleWidth;
     55       float scaleY = scaleHeight;
     56       scaleWidth = viewHeight / viewWidth * scaleY;
     57       scaleHeight = viewWidth / viewHeight * scaleX;
     58 
     59       // This flips the view vertically. Without this the camera feed would be upside down.
     60       scaleWidth = scaleWidth * -1.0f;
     61       // This flips the view horizontally. Without this the camera feed would be mirrored (left
     62       // side would appear on right).
     63       scaleHeight = scaleHeight * -1.0f;
     64     }
     65 
     66     LogUtil.i(
     67         "VideoScale.scaleVideoAndFillView",
     68         "view: %f x %f, video: %f x %f scale: %f x %f, rotation: %f",
     69         viewWidth,
     70         viewHeight,
     71         videoWidth,
     72         videoHeight,
     73         scaleWidth,
     74         scaleHeight,
     75         rotationDegrees);
     76 
     77     Matrix transform = new Matrix();
     78     transform.setScale(
     79         scaleWidth,
     80         scaleHeight,
     81         // This performs the scaling from the horizontal middle of the view.
     82         viewWidth / 2.0f,
     83         // This perform the scaling from vertical middle of the view.
     84         viewHeight / 2.0f);
     85     if (rotationDegrees != 0) {
     86       transform.postRotate(rotationDegrees, viewWidth / 2.0f, viewHeight / 2.0f);
     87     }
     88     textureView.setTransform(transform);
     89   }
     90 
     91   /**
     92    * Scales the video in the given view such that all of the video is visible. This will result in
     93    * black bars on the top and bottom or the sides of the video.
     94    */
     95   public static void scaleVideoMaintainingAspectRatio(
     96       TextureView textureView, int videoWidth, int videoHeight) {
     97     int viewWidth = textureView.getWidth();
     98     int viewHeight = textureView.getHeight();
     99     float scaleWidth = 1.0f;
    100     float scaleHeight = 1.0f;
    101 
    102     if (viewWidth > viewHeight) {
    103       // Landscape layout.
    104       if (viewHeight * videoWidth > viewWidth * videoHeight) {
    105         // Current display height is too much. Correct it.
    106         int desiredHeight = viewWidth * videoHeight / videoWidth;
    107         scaleWidth = (float) desiredHeight / (float) viewHeight;
    108       } else if (viewHeight * videoWidth < viewWidth * videoHeight) {
    109         // Current display width is too much. Correct it.
    110         int desiredWidth = viewHeight * videoWidth / videoHeight;
    111         scaleWidth = (float) desiredWidth / (float) viewWidth;
    112       }
    113     } else {
    114       // Portrait layout.
    115       if (viewHeight * videoWidth > viewWidth * videoHeight) {
    116         // Current display height is too much. Correct it.
    117         int desiredHeight = viewWidth * videoHeight / videoWidth;
    118         scaleHeight = (float) desiredHeight / (float) viewHeight;
    119       } else if (viewHeight * videoWidth < viewWidth * videoHeight) {
    120         // Current display width is too much. Correct it.
    121         int desiredWidth = viewHeight * videoWidth / videoHeight;
    122         scaleHeight = (float) desiredWidth / (float) viewWidth;
    123       }
    124     }
    125 
    126     LogUtil.i(
    127         "VideoScale.scaleVideoMaintainingAspectRatio",
    128         "view: %d x %d, video: %d x %d scale: %f x %f",
    129         viewWidth,
    130         viewHeight,
    131         videoWidth,
    132         videoHeight,
    133         scaleWidth,
    134         scaleHeight);
    135     Matrix transform = new Matrix();
    136     transform.setScale(
    137         scaleWidth,
    138         scaleHeight,
    139         // This performs the scaling from the horizontal middle of the view.
    140         viewWidth / 2.0f,
    141         // This perform the scaling from vertical middle of the view.
    142         viewHeight / 2.0f);
    143     textureView.setTransform(transform);
    144   }
    145 
    146   private VideoScale() {}
    147 }
    148