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