/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.incallui.videosurface.impl; import android.graphics.Matrix; import android.view.TextureView; import com.android.dialer.common.LogUtil; /** Utilities to scale the preview and remote video. */ public class VideoScale { /** * Scales the video in the given view such that the video takes up the entire view. To maintain * aspect ratio the video will be scaled to be larger than the view. */ public static void scaleVideoAndFillView( TextureView textureView, float videoWidth, float videoHeight, float rotationDegrees) { float viewWidth = textureView.getWidth(); float viewHeight = textureView.getHeight(); float viewAspectRatio = viewWidth / viewHeight; float videoAspectRatio = videoWidth / videoHeight; float scaleWidth = 1.0f; float scaleHeight = 1.0f; if (viewAspectRatio > videoAspectRatio) { // Scale to exactly fit the width of the video. The top and bottom will be cropped. float scaleFactor = viewWidth / videoWidth; float desiredScaledHeight = videoHeight * scaleFactor; scaleHeight = desiredScaledHeight / viewHeight; } else { // Scale to exactly fit the height of the video. The sides will be cropped. float scaleFactor = viewHeight / videoHeight; float desiredScaledWidth = videoWidth * scaleFactor; scaleWidth = desiredScaledWidth / viewWidth; } if (rotationDegrees == 90.0f || rotationDegrees == 270.0f) { // We're in landscape mode but the camera feed is still drawing in portrait mode. Normally, // scale of 1.0 means that the video feed stretches to fit the view. In this case the X axis // is scaled to fit the height and the Y axis is scaled to fit the width. float scaleX = scaleWidth; float scaleY = scaleHeight; scaleWidth = viewHeight / viewWidth * scaleY; scaleHeight = viewWidth / viewHeight * scaleX; // This flips the view vertically. Without this the camera feed would be upside down. scaleWidth = scaleWidth * -1.0f; // This flips the view horizontally. Without this the camera feed would be mirrored (left // side would appear on right). scaleHeight = scaleHeight * -1.0f; } LogUtil.i( "VideoScale.scaleVideoAndFillView", "view: %f x %f, video: %f x %f scale: %f x %f, rotation: %f", viewWidth, viewHeight, videoWidth, videoHeight, scaleWidth, scaleHeight, rotationDegrees); Matrix transform = new Matrix(); transform.setScale( scaleWidth, scaleHeight, // This performs the scaling from the horizontal middle of the view. viewWidth / 2.0f, // This perform the scaling from vertical middle of the view. viewHeight / 2.0f); if (rotationDegrees != 0) { transform.postRotate(rotationDegrees, viewWidth / 2.0f, viewHeight / 2.0f); } textureView.setTransform(transform); } /** * Scales the video in the given view such that all of the video is visible. This will result in * black bars on the top and bottom or the sides of the video. */ public static void scaleVideoMaintainingAspectRatio( TextureView textureView, int videoWidth, int videoHeight) { int viewWidth = textureView.getWidth(); int viewHeight = textureView.getHeight(); float scaleWidth = 1.0f; float scaleHeight = 1.0f; if (viewWidth > viewHeight) { // Landscape layout. if (viewHeight * videoWidth > viewWidth * videoHeight) { // Current display height is too much. Correct it. int desiredHeight = viewWidth * videoHeight / videoWidth; scaleWidth = (float) desiredHeight / (float) viewHeight; } else if (viewHeight * videoWidth < viewWidth * videoHeight) { // Current display width is too much. Correct it. int desiredWidth = viewHeight * videoWidth / videoHeight; scaleWidth = (float) desiredWidth / (float) viewWidth; } } else { // Portrait layout. if (viewHeight * videoWidth > viewWidth * videoHeight) { // Current display height is too much. Correct it. int desiredHeight = viewWidth * videoHeight / videoWidth; scaleHeight = (float) desiredHeight / (float) viewHeight; } else if (viewHeight * videoWidth < viewWidth * videoHeight) { // Current display width is too much. Correct it. int desiredWidth = viewHeight * videoWidth / videoHeight; scaleHeight = (float) desiredWidth / (float) viewWidth; } } LogUtil.i( "VideoScale.scaleVideoMaintainingAspectRatio", "view: %d x %d, video: %d x %d scale: %f x %f", viewWidth, viewHeight, videoWidth, videoHeight, scaleWidth, scaleHeight); Matrix transform = new Matrix(); transform.setScale( scaleWidth, scaleHeight, // This performs the scaling from the horizontal middle of the view. viewWidth / 2.0f, // This perform the scaling from vertical middle of the view. viewHeight / 2.0f); textureView.setTransform(transform); } private VideoScale() {} }