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    */
scaleVideoAndFillView( TextureView textureView, float videoWidth, float videoHeight, float rotationDegrees)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    */
scaleVideoMaintainingAspectRatio( TextureView textureView, int videoWidth, int videoHeight)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 
VideoScale()146   private VideoScale() {}
147 }
148