1df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin/* 2df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Copyright (C) 2014 The Android Open Source Project 3df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 4df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License"); 5df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * you may not use this file except in compliance with the License. 6df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * You may obtain a copy of the License at 7df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 8df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * http://www.apache.org/licenses/LICENSE-2.0 9df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 10df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Unless required by applicable law or agreed to in writing, software 11df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS, 12df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * See the License for the specific language governing permissions and 14df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * limitations under the License. 15df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 16df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 17df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinpackage android.hardware.camera2.legacy; 18df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 19df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.graphics.Matrix; 207ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.graphics.Point; 21df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.graphics.Rect; 22df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.graphics.RectF; 23df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.hardware.Camera; 247ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.hardware.Camera.Area; 257ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.hardware.camera2.legacy.ParameterUtils.MeteringData; 267ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.hardware.camera2.legacy.ParameterUtils.ZoomData; 277ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.hardware.camera2.params.Face; 287ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkinimport android.hardware.camera2.params.MeteringRectangle; 29df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.hardware.camera2.utils.ListUtils; 30df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.hardware.camera2.utils.ParamsUtils; 31df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.hardware.camera2.utils.SizeAreaComparator; 32df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.util.Size; 33df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.util.SizeF; 34df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 35df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.util.Log; 36df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 37df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport java.util.ArrayList; 38df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport java.util.Arrays; 39df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport java.util.List; 40df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 41df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport static com.android.internal.util.Preconditions.*; 42df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 43df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin/** 44df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Various utilities for dealing with camera API1 parameters. 45df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 460a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin@SuppressWarnings("deprecation") 47df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinpublic class ParameterUtils { 487ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Upper/left minimal point of a normalized rectangle */ 497ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static final int NORMALIZED_RECTANGLE_MIN = -1000; 507ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Lower/right maximal point of a normalized rectangle */ 517ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static final int NORMALIZED_RECTANGLE_MAX = 1000; 527ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** The default normalized rectangle spans the entire size of the preview viewport */ 537ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static final Rect NORMALIZED_RECTANGLE_DEFAULT = new Rect( 547ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin NORMALIZED_RECTANGLE_MIN, 557ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin NORMALIZED_RECTANGLE_MIN, 567ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin NORMALIZED_RECTANGLE_MAX, 577ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin NORMALIZED_RECTANGLE_MAX); 587ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** The default normalized area uses the default normalized rectangle with a weight=1 */ 597ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static final Camera.Area CAMERA_AREA_DEFAULT = 607ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin new Camera.Area(new Rect(NORMALIZED_RECTANGLE_DEFAULT), 617ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /*weight*/1); 627ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Empty rectangle {@code 0x0+0,0} */ 637ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static final Rect RECTANGLE_EMPTY = 647ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin new Rect(/*left*/0, /*top*/0, /*right*/0, /*bottom*/0); 657ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 667ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 677ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate effective/reported zoom data from a user-specified crop region. 687ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 697ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static class ZoomData { 707ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Zoom index used by {@link Camera.Parameters#setZoom} */ 717ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final int zoomIndex; 727ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Effective crop-region given the zoom index, coordinates relative to active-array */ 737ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final Rect previewCrop; 747ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Reported crop-region given the zoom index, coordinates relative to active-array */ 757ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final Rect reportedCrop; 767ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 777ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public ZoomData(int zoomIndex, Rect previewCrop, Rect reportedCrop) { 787ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.zoomIndex = zoomIndex; 797ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.previewCrop = previewCrop; 807ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.reportedCrop = reportedCrop; 817ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 827ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 837ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 847ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 857ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate effective/reported metering data from a user-specified metering region. 867ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 877ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static class MeteringData { 887ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 897ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * The metering area scaled to the range of [-1000, 1000]. 907ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>Values outside of this range are clipped to be within the range.</p> 917ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 927ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final Camera.Area meteringArea; 937ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 947ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Effective preview metering region, coordinates relative to active-array. 957ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 967ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>Clipped to fit inside of the (effective) preview crop region.</p> 977ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 987ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final Rect previewMetering; 997ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 1007ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Reported metering region, coordinates relative to active-array. 1017ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1027ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>Clipped to fit inside of the (reported) resulting crop region.</p> 1037ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 1047ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final Rect reportedMetering; 1057ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1067ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public MeteringData(Area meteringArea, Rect previewMetering, Rect reportedMetering) { 1077ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.meteringArea = meteringArea; 1087ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.previewMetering = previewMetering; 1097ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.reportedMetering = reportedMetering; 1107ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 1117ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 1127ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1137ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 1147ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * A weighted rectangle is an arbitrary rectangle (the coordinate system is unknown) with an 1157ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * arbitrary weight. 1167ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1177ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>The user of this class must know what the coordinate system ahead of time; it's 1187ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * then possible to convert to a more concrete type such as a metering rectangle or a face. 1197ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * </p> 1207ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1217ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>When converting to a more concrete type, out-of-range values are clipped; this prevents 1227ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * possible illegal argument exceptions being thrown at runtime.</p> 1237ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 1247ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static class WeightedRectangle { 1257ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Arbitrary rectangle (the range is user-defined); never {@code null}. */ 1267ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final Rect rect; 1277ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** Arbitrary weight (the range is user-defined). */ 1287ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public final int weight; 1297ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1307ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 1317ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Create a new weighted-rectangle from a non-{@code null} rectangle; the {@code weight} 1327ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * can be unbounded. 1337ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 1347ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public WeightedRectangle(Rect rect, int weight) { 1357ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.rect = checkNotNull(rect, "rect must not be null"); 1367ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin this.weight = weight; 1377ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 1387ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1397ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 1407ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Convert to a metering rectangle, clipping any of the values to stay within range. 1417ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1427ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>If values are clipped, a warning is printed to logcat.</p> 1437ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1447ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @return a new metering rectangle 1457ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 1467ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public MeteringRectangle toMetering() { 1477ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int weight = clip(this.weight, 1487ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin MeteringRectangle.METERING_WEIGHT_MIN, 1497ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin MeteringRectangle.METERING_WEIGHT_MAX, 1507ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin rect, 1517ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "weight"); 1527ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1537ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int x = clipLower(rect.left, /*lo*/0, rect, "left"); 1547ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int y = clipLower(rect.top, /*lo*/0, rect, "top"); 1557ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int w = clipLower(rect.width(), /*lo*/0, rect, "width"); 1567ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int h = clipLower(rect.height(), /*lo*/0, rect, "height"); 1577ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1587ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return new MeteringRectangle(x, y, w, h, weight); 1597ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 1607ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1617ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 1627ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Convert to a face; the rect is considered to be the bounds, and the weight 1637ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * is considered to be the score. 1647ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1657ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>If the score is out of range of {@value Face#SCORE_MIN}, {@value Face#SCORE_MAX}, 1667ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * the score is clipped first and a warning is printed to logcat.</p> 1677ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1680a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * <p>If the id is negative, the id is changed to 0 and a warning is printed to 1690a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * logcat.</p> 1700a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * 1717ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>All other parameters are passed-through as-is.</p> 1727ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1737ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @return a new face with the optional features set 1747ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 1757ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public Face toFace( 1767ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int id, Point leftEyePosition, Point rightEyePosition, Point mouthPosition) { 1770a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin int idSafe = clipLower(id, /*lo*/0, rect, "id"); 1787ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int score = clip(weight, 1797ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Face.SCORE_MIN, 1807ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Face.SCORE_MAX, 1817ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin rect, 1827ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "score"); 1837ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1840a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin return new Face(rect, score, idSafe, leftEyePosition, rightEyePosition, mouthPosition); 1857ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 1867ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1877ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 1887ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Convert to a face; the rect is considered to be the bounds, and the weight 1897ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * is considered to be the score. 1907ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1917ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>If the score is out of range of {@value Face#SCORE_MIN}, {@value Face#SCORE_MAX}, 1927ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * the score is clipped first and a warning is printed to logcat.</p> 1937ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1947ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>All other parameters are passed-through as-is.</p> 1957ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 1967ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @return a new face without the optional features 1977ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 1987ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public Face toFace() { 1997ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int score = clip(weight, 2007ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Face.SCORE_MIN, 2017ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Face.SCORE_MAX, 2027ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin rect, 2037ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "score"); 2047ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 2057ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return new Face(rect, score); 2067ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 2077ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 2087ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin private static int clipLower(int value, int lo, Rect rect, String name) { 2097ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return clip(value, lo, /*hi*/Integer.MAX_VALUE, rect, name); 2107ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 2117ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 2127ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin private static int clip(int value, int lo, int hi, Rect rect, String name) { 2137ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (value < lo) { 2147ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.w(TAG, "toMetering - Rectangle " + rect + " " 2157ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin + name + " too small, clip to " + lo); 2167ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin value = lo; 2177ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } else if (value > hi) { 2187ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.w(TAG, "toMetering - Rectangle " + rect + " " 2197ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin + name + " too small, clip to " + hi); 2207ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin value = hi; 2217ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 2227ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 2237ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return value; 2247ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 2257ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 2267ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 227df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static final String TAG = "ParameterUtils"; 228df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 229df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 230df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** getZoomRatios stores zoom ratios in 1/100 increments, e.x. a zoom of 3.2 is 320 */ 231df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static final int ZOOM_RATIO_MULTIPLIER = 100; 232df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 233df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 234df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Convert a camera API1 size into a util size 235df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 236df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static Size convertSize(Camera.Size size) { 237df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(size, "size must not be null"); 238df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 239df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return new Size(size.width, size.height); 240df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 241df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 242df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 243df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Convert a camera API1 list of sizes into a util list of sizes 244df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 245df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static List<Size> convertSizeList(List<Camera.Size> sizeList) { 246df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(sizeList, "sizeList must not be null"); 247df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 248df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin List<Size> sizes = new ArrayList<>(sizeList.size()); 249df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin for (Camera.Size s : sizeList) { 250df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sizes.add(new Size(s.width, s.height)); 251df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 252df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return sizes; 253df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 254df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 255df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 2561dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk * Convert a camera API1 list of sizes into an array of sizes 2571dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk */ 2581dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk public static Size[] convertSizeListToArray(List<Camera.Size> sizeList) { 2591dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk checkNotNull(sizeList, "sizeList must not be null"); 2601dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk 2611dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk Size[] array = new Size[sizeList.size()]; 2621dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk int ctr = 0; 2631dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk for (Camera.Size s : sizeList) { 2641dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk array[ctr++] = new Size(s.width, s.height); 2651dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk } 2661dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk return array; 2671dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk } 2681dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk 2691dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk /** 2701dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk * Check if the camera API1 list of sizes contains a size with the given dimens. 2711dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk */ 2721dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk public static boolean containsSize(List<Camera.Size> sizeList, int width, int height) { 2731dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk checkNotNull(sizeList, "sizeList must not be null"); 2741dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk for (Camera.Size s : sizeList) { 2751dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk if (s.height == height && s.width == width) { 2761dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk return true; 2771dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk } 2781dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk } 2791dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk return false; 2801dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk } 2811dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk 2821dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk /** 283df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Returns the largest supported picture size, as compared by its area. 284df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 285df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static Size getLargestSupportedJpegSizeByArea(Camera.Parameters params) { 286df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(params, "params must not be null"); 287df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 288df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin List<Size> supportedJpegSizes = convertSizeList(params.getSupportedPictureSizes()); 289df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return SizeAreaComparator.findLargestByArea(supportedJpegSizes); 290df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 291df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 292df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 293df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Convert a camera area into a human-readable string. 294df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 295df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static String stringFromArea(Camera.Area area) { 296df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (area == null) { 297df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return null; 298df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else { 299df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin StringBuilder sb = new StringBuilder(); 300df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect r = area.rect; 301df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 302df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.setLength(0); 303df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.append("(["); sb.append(r.left); sb.append(','); 304df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.append(r.top); sb.append("]["); sb.append(r.right); 305df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.append(','); sb.append(r.bottom); sb.append(']'); 306df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 307df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.append(','); 308df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.append(area.weight); 309df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin sb.append(')'); 310df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 311df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return sb.toString(); 312df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 313df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 314df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 315df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 3167ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Convert a camera area list into a human-readable string 3177ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param areaList a list of areas (null is ok) 3187ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 3197ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static String stringFromAreaList(List<Camera.Area> areaList) { 3207ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin StringBuilder sb = new StringBuilder(); 3217ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 3227ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (areaList == null) { 3237ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return null; 3247ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 3257ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 3267ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int i = 0; 3277ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin for (Camera.Area area : areaList) { 3287ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (area == null) { 3297ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin sb.append("null"); 3307ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } else { 3317ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin sb.append(stringFromArea(area)); 3327ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 3337ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 3347ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (i != areaList.size() - 1) { 3357ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin sb.append(", "); 3367ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 3377ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 3387ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin i++; 3397ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 3407ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 3417ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return sb.toString(); 3427ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 3437ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 3447ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 345df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Calculate the closest zoom index for the user-requested crop region by rounding 346df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * up to the closest (largest or equal) possible zoom crop. 347df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 348df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>If the requested crop region exceeds the size of the active array, it is 349df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * shrunk to fit inside of the active array first.</p> 350df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 351df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>Since all api1 camera devices only support a discrete set of zooms, we have 352df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * to translate the per-pixel-granularity requested crop region into a per-zoom-index 353df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * granularity.</p> 354df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 355df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>Furthermore, since the zoom index and zoom levels also depends on the field-of-view 356df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * of the preview, the current preview {@code streamSize} is also used.</p> 357df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 358df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>The calculated crop regions are then written to in-place to {@code reportedCropRegion} 359df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * and {@code previewCropRegion}, in coordinates relative to the active array.</p> 360df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 361df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param params non-{@code null} camera api1 parameters 362df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param activeArray active array dimensions, in sensor space 363df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param streamSize stream size dimensions, in pixels 364df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param cropRegion user-specified crop region, in active array coordinates 365df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param reportedCropRegion (out parameter) what the result for {@code cropRegion} looks like 366df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param previewCropRegion (out parameter) what the visual preview crop is 367df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return 368df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * the zoom index inclusively between 0 and {@code Parameters#getMaxZoom}, 369df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * where 0 means the camera is not zoomed 370df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 371df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @throws NullPointerException if any of the args were {@code null} 372df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 373df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static int getClosestAvailableZoomCrop( 374df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Camera.Parameters params, Rect activeArray, Size streamSize, Rect cropRegion, 375df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /*out*/ 376df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect reportedCropRegion, 377df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect previewCropRegion) { 378df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(params, "params must not be null"); 379df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(activeArray, "activeArray must not be null"); 380df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(streamSize, "streamSize must not be null"); 381df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(reportedCropRegion, "reportedCropRegion must not be null"); 382df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(previewCropRegion, "previewCropRegion must not be null"); 383df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 384df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect actualCrop = new Rect(cropRegion); 385df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 386df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /* 387df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Shrink requested crop region to fit inside of the active array size 388df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 389df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (!actualCrop.intersect(activeArray)) { 390df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Log.w(TAG, "getClosestAvailableZoomCrop - Crop region out of range; " + 391df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin "setting to active array size"); 392df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin actualCrop.set(activeArray); 393df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 394df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 395df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect previewCrop = getPreviewCropRectangleUnzoomed(activeArray, streamSize); 396df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 397df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Make the user-requested crop region the same aspect ratio as the preview stream size 398df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect cropRegionAsPreview = 399df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin shrinkToSameAspectRatioCentered(previewCrop, actualCrop); 400df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 401df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (VERBOSE) { 402df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Log.v(TAG, "getClosestAvailableZoomCrop - actualCrop = " + actualCrop); 403df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Log.v(TAG, 404df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin "getClosestAvailableZoomCrop - previewCrop = " + previewCrop); 405df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Log.v(TAG, 406df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin "getClosestAvailableZoomCrop - cropRegionAsPreview = " + cropRegionAsPreview); 407df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 408df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 409df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /* 410df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Iterate all available zoom rectangles and find the closest zoom index 411df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 412df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect bestReportedCropRegion = null; 413df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect bestPreviewCropRegion = null; 414df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin int bestZoomIndex = -1; 415df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 416df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin List<Rect> availableReportedCropRegions = 417df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin getAvailableZoomCropRectangles(params, activeArray); 418df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin List<Rect> availablePreviewCropRegions = 419df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin getAvailablePreviewZoomCropRectangles(params, activeArray, streamSize); 420df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 421df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (VERBOSE) { 422df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Log.v(TAG, 423df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin "getClosestAvailableZoomCrop - availableReportedCropRegions = " + 424df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin ListUtils.listToString(availableReportedCropRegions)); 425df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Log.v(TAG, 426df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin "getClosestAvailableZoomCrop - availablePreviewCropRegions = " + 427df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin ListUtils.listToString(availablePreviewCropRegions)); 428df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 429df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 430df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (availableReportedCropRegions.size() != availablePreviewCropRegions.size()) { 431df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin throw new AssertionError("available reported/preview crop region size mismatch"); 432df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 433df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 434df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin for (int i = 0; i < availableReportedCropRegions.size(); ++i) { 435df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect currentPreviewCropRegion = availablePreviewCropRegions.get(i); 436df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect currentReportedCropRegion = availableReportedCropRegions.get(i); 437df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 438df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin boolean isBest; 439df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (bestZoomIndex == -1) { 440df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin isBest = true; 441df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else if (currentPreviewCropRegion.width() >= cropRegionAsPreview.width() && 442df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin currentPreviewCropRegion.height() >= cropRegionAsPreview.height()) { 443df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin isBest = true; 444df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else { 445df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin isBest = false; 446df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 447df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 448df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Sizes are sorted largest-to-smallest, so once the available crop is too small, 449df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // we the rest are too small. Furthermore, this is the final best crop, 450df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // since its the largest crop that still fits the requested crop 451df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (isBest) { 452df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin bestPreviewCropRegion = currentPreviewCropRegion; 453df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin bestReportedCropRegion = currentReportedCropRegion; 454df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin bestZoomIndex = i; 455df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else { 456df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin break; 457df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 458df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 459df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 460df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (bestZoomIndex == -1) { 461df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Even in the worst case, we should always at least return 0 here 462df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin throw new AssertionError("Should've found at least one valid zoom index"); 463df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 464df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 465df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Write the rectangles in-place 466df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin reportedCropRegion.set(bestReportedCropRegion); 467df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin previewCropRegion.set(bestPreviewCropRegion); 468df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 469df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return bestZoomIndex; 470df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 471df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 472df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 473df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Calculate the effective crop rectangle for this preview viewport; 474df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * assumes the preview is centered to the sensor and scaled to fit across one of the dimensions 475df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * without skewing. 476df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 477df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>The preview size must be a subset of the active array size; the resulting 478df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * rectangle will also be a subset of the active array rectangle.</p> 479df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 480df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>The unzoomed crop rectangle is calculated only.</p> 481df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 482df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param activeArray active array dimensions, in sensor space 483df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param previewSize size of the preview buffer render target, in pixels (not in sensor space) 484df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return a rectangle which serves as the preview stream's effective crop region (unzoomed), 485df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * in sensor space 486df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 487df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @throws NullPointerException 488df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * if any of the args were {@code null} 489df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @throws IllegalArgumentException 490df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * if {@code previewSize} is wider or taller than {@code activeArray} 491df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 492df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static Rect getPreviewCropRectangleUnzoomed(Rect activeArray, Size previewSize) { 493df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (previewSize.getWidth() > activeArray.width()) { 494df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin throw new IllegalArgumentException("previewSize must not be wider than activeArray"); 495df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else if (previewSize.getHeight() > activeArray.height()) { 496df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin throw new IllegalArgumentException("previewSize must not be taller than activeArray"); 497df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 498df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 499df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float aspectRatioArray = activeArray.width() * 1.0f / activeArray.height(); 500df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float aspectRatioPreview = previewSize.getWidth() * 1.0f / previewSize.getHeight(); 501df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 502df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float cropH, cropW; 503df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (aspectRatioPreview < aspectRatioArray) { 504df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // The new width must be smaller than the height, so scale the width by AR 505df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropH = activeArray.height(); 506df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropW = cropH * aspectRatioPreview; 507df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else { 508df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // The new height must be smaller (or equal) than the width, so scale the height by AR 509df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropW = activeArray.width(); 510df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropH = cropW / aspectRatioPreview; 511df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 512df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 513df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Matrix translateMatrix = new Matrix(); 514df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin RectF cropRect = new RectF(/*left*/0, /*top*/0, cropW, cropH); 515df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 516df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Now center the crop rectangle so its center is in the center of the active array 517df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin translateMatrix.setTranslate(activeArray.exactCenterX(), activeArray.exactCenterY()); 518df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin translateMatrix.postTranslate(-cropRect.centerX(), -cropRect.centerY()); 519df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 520df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin translateMatrix.mapRect(/*inout*/cropRect); 521df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 522df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Round the rect corners towards the nearest integer values 523df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return ParamsUtils.createRect(cropRect); 524df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 525df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 526df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 527df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Shrink the {@code shrinkTarget} rectangle to snugly fit inside of {@code reference}; 528df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * the aspect ratio of {@code shrinkTarget} will change to be the same aspect ratio as 529df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * {@code reference}. 530df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 531df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>At most a single dimension will scale (down). Both dimensions will never be scaled.</p> 532df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 533df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param reference the rectangle whose aspect ratio will be used as the new aspect ratio 534df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param shrinkTarget the rectangle which will be scaled down to have a new aspect ratio 535df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 536df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return a new rectangle, a subset of {@code shrinkTarget}, 537df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * whose aspect ratio will match that of {@code reference} 538df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 539df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static Rect shrinkToSameAspectRatioCentered(Rect reference, Rect shrinkTarget) { 540df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float aspectRatioReference = reference.width() * 1.0f / reference.height(); 541df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float aspectRatioShrinkTarget = shrinkTarget.width() * 1.0f / shrinkTarget.height(); 542df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 543df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float cropH, cropW; 544df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (aspectRatioShrinkTarget < aspectRatioReference) { 545df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // The new width must be smaller than the height, so scale the width by AR 546df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropH = reference.height(); 547df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropW = cropH * aspectRatioShrinkTarget; 548df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } else { 549df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // The new height must be smaller (or equal) than the width, so scale the height by AR 550df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropW = reference.width(); 551df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin cropH = cropW / aspectRatioShrinkTarget; 552df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 553df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 554df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Matrix translateMatrix = new Matrix(); 555df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin RectF shrunkRect = new RectF(shrinkTarget); 556df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 557df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Scale the rectangle down, but keep its center in the same place as before 558df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin translateMatrix.setScale(cropW / reference.width(), cropH / reference.height(), 559df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin shrinkTarget.exactCenterX(), shrinkTarget.exactCenterY()); 560df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 561df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin translateMatrix.mapRect(/*inout*/shrunkRect); 562df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 563df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return ParamsUtils.createRect(shrunkRect); 564df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 565df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 566df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 567df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Get the available 'crop' (zoom) rectangles for this camera that will be reported 568df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * via a {@code CaptureResult} when a zoom is requested. 569df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 570df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>These crops ignores the underlying preview buffer size, and will always be reported 571df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * the same values regardless of what configuration of outputs is used.</p> 572df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 573df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size, 574df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * where each crop rectangle corresponds to a zoom ratio (and is centered at the middle).</p> 575df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 576df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize}, 577df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * by shrinking the rectangle if necessary.</p> 578df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 579df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize} 580df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * = {@code activeArray size}.</p> 581df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 582df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param params non-{@code null} camera api1 parameters 583df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param activeArray active array dimensions, in sensor space 584df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param streamSize stream size dimensions, in pixels 585df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 586df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed 587df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 588df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static List<Rect> getAvailableZoomCropRectangles( 589df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Camera.Parameters params, Rect activeArray) { 590df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(params, "params must not be null"); 591df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(activeArray, "activeArray must not be null"); 592df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 593df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return getAvailableCropRectangles(params, activeArray, ParamsUtils.createSize(activeArray)); 594df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 595df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 596df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 597df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Get the available 'crop' (zoom) rectangles for this camera. 598df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 599df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>This is the effective (real) crop that is applied by the camera api1 device 600df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * when projecting the zoom onto the intermediate preview buffer. Use this when 601df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * deciding which zoom ratio to apply.</p> 602df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 603df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size, 604df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * where each crop rectangle corresponds to a zoom ratio (and is centered at the middle).</p> 605df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 606df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize}, 607df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * by shrinking the rectangle if necessary.</p> 608df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 609df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize} 610df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * = {@code activeArray size}.</p> 611df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 612df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param params non-{@code null} camera api1 parameters 613df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param activeArray active array dimensions, in sensor space 614df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param streamSize stream size dimensions, in pixels 615df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 616df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed 617df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 618df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static List<Rect> getAvailablePreviewZoomCropRectangles(Camera.Parameters params, 619df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect activeArray, Size previewSize) { 620df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(params, "params must not be null"); 621df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(activeArray, "activeArray must not be null"); 622df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(previewSize, "previewSize must not be null"); 623df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 624df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return getAvailableCropRectangles(params, activeArray, previewSize); 625df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 626df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 627df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 628df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Get the available 'crop' (zoom) rectangles for this camera. 629df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 630df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size, 631df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * where each crop rectangle corresponds to a zoom ratio (and is centered at the middle).</p> 632df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 633df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize}, 634df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * by shrinking the rectangle if necessary.</p> 635df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 636df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize} 637df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * = {@code activeArray size}.</p> 638df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 639df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param params non-{@code null} camera api1 parameters 640df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param activeArray active array dimensions, in sensor space 641df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param streamSize stream size dimensions, in pixels 642df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 643df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed 644df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 645df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static List<Rect> getAvailableCropRectangles(Camera.Parameters params, 646df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect activeArray, Size streamSize) { 647df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(params, "params must not be null"); 648df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(activeArray, "activeArray must not be null"); 649df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(streamSize, "streamSize must not be null"); 650df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 651df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // TODO: change all uses of Rect activeArray to Size activeArray, 652df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // since we want the crop to be active-array relative, not pixel-array relative 653df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 654df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect unzoomedStreamCrop = getPreviewCropRectangleUnzoomed(activeArray, streamSize); 655df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 656df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (!params.isZoomSupported()) { 657df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Trivial case: No zoom -> only support the full size as the crop region 658df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return new ArrayList<>(Arrays.asList(unzoomedStreamCrop)); 659df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 660df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 661df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin List<Rect> zoomCropRectangles = new ArrayList<>(params.getMaxZoom() + 1); 662df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Matrix scaleMatrix = new Matrix(); 663df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin RectF scaledRect = new RectF(); 664df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 665df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin for (int zoom : params.getZoomRatios()) { 666df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float shrinkRatio = ZOOM_RATIO_MULTIPLIER * 1.0f / zoom; // normalize to 1.0 and smaller 667df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 668df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // set scaledRect to unzoomedStreamCrop 669df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin ParamsUtils.convertRectF(unzoomedStreamCrop, /*out*/scaledRect); 670df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 671df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin scaleMatrix.setScale( 672df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin shrinkRatio, shrinkRatio, 673df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin activeArray.exactCenterX(), 674df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin activeArray.exactCenterY()); 675df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 676df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin scaleMatrix.mapRect(scaledRect); 677df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 678df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin Rect intRect = ParamsUtils.createRect(scaledRect); 679df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 680df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin // Round the rect corners towards the nearest integer values 681df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin zoomCropRectangles.add(intRect); 682df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 683df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 684df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return zoomCropRectangles; 685df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 686df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 687df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 688df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Get the largest possible zoom ratio (normalized to {@code 1.0f} and higher) 689df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * that the camera can support. 690df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 691df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * <p>If the camera does not support zoom, it always returns {@code 1.0f}.</p> 692df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 693df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param params non-{@code null} camera api1 parameters 694df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return normalized max zoom ratio, at least {@code 1.0f} 695df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 696df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin public static float getMaxZoomRatio(Camera.Parameters params) { 697df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin if (!params.isZoomSupported()) { 698df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return 1.0f; // no zoom 699df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 700df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 701df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin List<Integer> zoomRatios = params.getZoomRatios(); // sorted smallest->largest 702df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin int zoom = zoomRatios.get(zoomRatios.size() - 1); // largest zoom ratio 703df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float zoomRatio = zoom * 1.0f / ZOOM_RATIO_MULTIPLIER; // normalize to 1.0 and smaller 704df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 705df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return zoomRatio; 706df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 707df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 708df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin /** 709df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * Returns the component-wise zoom ratio (each greater or equal than {@code 1.0}); 710df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * largest values means more zoom. 711df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 712df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param activeArraySize active array size of the sensor (e.g. max jpeg size) 713df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @param cropSize size of the crop/zoom 714df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 715df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @return {@link SizeF} with width/height being the component-wise zoom ratio 716df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * 717df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @throws NullPointerException if any of the args were {@code null} 718df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin * @throws IllegalArgumentException if any component of {@code cropSize} was {@code 0} 719df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin */ 720df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private static SizeF getZoomRatio(Size activeArraySize, Size cropSize) { 721df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(activeArraySize, "activeArraySize must not be null"); 722df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkNotNull(cropSize, "cropSize must not be null"); 723df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkArgumentPositive(cropSize.getWidth(), "cropSize.width must be positive"); 724df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin checkArgumentPositive(cropSize.getHeight(), "cropSize.height must be positive"); 725df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 726df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float zoomRatioWidth = activeArraySize.getWidth() * 1.0f / cropSize.getWidth(); 727df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin float zoomRatioHeight = activeArraySize.getHeight() * 1.0f / cropSize.getHeight(); 728df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 729df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin return new SizeF(zoomRatioWidth, zoomRatioHeight); 730df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 731df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin 7327ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 7337ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Convert the user-specified crop region into zoom data; which can be used 7347ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * to set the parameters to a specific zoom index, or to report back to the user what the 7357ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * actual zoom was, or for other calculations requiring the current preview crop region. 7367ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7377ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>None of the parameters are mutated.</p> 7387ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7397ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param activeArraySize active array size of the sensor (e.g. max jpeg size) 7407ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param cropRegion the user-specified crop region 7417ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param previewSize the current preview size (in pixels) 7427ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param params the current camera parameters (not mutated) 7437ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7447ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @return the zoom index, and the effective/reported crop regions (relative to active array) 7457ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 7467ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static ZoomData convertScalerCropRegion(Rect activeArraySize, Rect 7477ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin cropRegion, Size previewSize, Camera.Parameters params) { 7487ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect activeArraySizeOnly = new Rect( 7497ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /*left*/0, /*top*/0, 7507ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin activeArraySize.width(), activeArraySize.height()); 7517ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7527ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect userCropRegion = cropRegion; 7537ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7547ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (userCropRegion == null) { 7557ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin userCropRegion = activeArraySizeOnly; 7567ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 7577ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7587ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (VERBOSE) { 7597ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.v(TAG, "convertScalerCropRegion - user crop region was " + userCropRegion); 7607ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 7617ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7627ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin final Rect reportedCropRegion = new Rect(); 7637ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin final Rect previewCropRegion = new Rect(); 7647ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin final int zoomIdx = ParameterUtils.getClosestAvailableZoomCrop(params, activeArraySizeOnly, 7657ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin previewSize, userCropRegion, 7667ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /*out*/reportedCropRegion, /*out*/previewCropRegion); 7677ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7687ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (VERBOSE) { 7697ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.v(TAG, "convertScalerCropRegion - zoom calculated to: " + 7707ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "zoomIndex = " + zoomIdx + 7717ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin ", reported crop region = " + reportedCropRegion + 7727ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin ", preview crop region = " + previewCropRegion); 7737ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 7747ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7757ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return new ZoomData(zoomIdx, previewCropRegion, reportedCropRegion); 7767ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 7777ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 7787ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 7797ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate the actual/effective/reported normalized rectangle data from a metering 7807ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * rectangle. 7817ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7827ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>If any of the rectangles are out-of-range of their intended bounding box, 7837ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * the {@link #RECTANGLE_EMPTY empty rectangle} is substituted instead 7847ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * (with a weight of {@code 0}).</p> 7857ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7867ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>The metering rectangle is bound by the crop region (effective/reported respectively). 7877ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * The metering {@link Camera.Area area} is bound by {@code [-1000, 1000]}.</p> 7887ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7897ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>No parameters are mutated; returns the new metering data.</p> 7907ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7917ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param activeArraySize active array size of the sensor (e.g. max jpeg size) 7927ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param meteringRect the user-specified metering rectangle 7937ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param zoomData the calculated zoom data corresponding to this request 7947ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 7957ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @return the metering area, the reported/effective metering rectangles 7967ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 7977ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static MeteringData convertMeteringRectangleToLegacy( 7987ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect activeArray, MeteringRectangle meteringRect, ZoomData zoomData) { 7997ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect previewCrop = zoomData.previewCrop; 8007ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8017ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin float scaleW = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f / 8027ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin previewCrop.width(); 8037ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin float scaleH = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f / 8047ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin previewCrop.height(); 8057ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8067ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Matrix transform = new Matrix(); 8077ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Move the preview crop so that top,left is at (0,0), otherwise after scaling 8087ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // the corner bounds will be outside of [-1000, 1000] 8097ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin transform.setTranslate(-previewCrop.left, -previewCrop.top); 8107ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Scale into [0, 2000] range about the center of the preview 8117ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin transform.postScale(scaleW, scaleH); 8127ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Move so that top left of a typical rect is at [-1000, -1000] 8137ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin transform.postTranslate(/*dx*/NORMALIZED_RECTANGLE_MIN, /*dy*/NORMALIZED_RECTANGLE_MIN); 8147ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8157ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /* 8167ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate the preview metering region (effective), and the camera1 api 8177ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * normalized metering region. 8187ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 8197ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect normalizedRegionUnbounded = ParamsUtils.mapRect(transform, meteringRect.getRect()); 8207ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8217ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /* 8227ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Try to intersect normalized area with [-1000, 1000] rectangle; otherwise 8237ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * it's completely out of range 8247ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 8257ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect normalizedIntersected = new Rect(normalizedRegionUnbounded); 8267ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8277ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Camera.Area meteringArea; 8287ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (!normalizedIntersected.intersect(NORMALIZED_RECTANGLE_DEFAULT)) { 8297ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.w(TAG, 8307ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "convertMeteringRectangleToLegacy - metering rectangle too small, " + 8317ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "no metering will be done"); 8327ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin normalizedIntersected.set(RECTANGLE_EMPTY); 8337ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin meteringArea = new Camera.Area(RECTANGLE_EMPTY, 8347ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin MeteringRectangle.METERING_WEIGHT_DONT_CARE); 8357ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } else { 8367ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin meteringArea = new Camera.Area(normalizedIntersected, 8377ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin meteringRect.getMeteringWeight()); 8387ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 8397ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8407ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /* 8417ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate effective preview metering region 8427ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 8437ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect previewMetering = meteringRect.getRect(); 8447ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (!previewMetering.intersect(previewCrop)) { 8457ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin previewMetering.set(RECTANGLE_EMPTY); 8467ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 8477ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8487ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /* 8497ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate effective reported metering region 8507ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * - Transform the calculated metering area back into active array space 8517ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * - Clip it to be a subset of the reported crop region 8527ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 8537ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect reportedMetering; 8547ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin { 8557ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Camera.Area normalizedAreaUnbounded = new Camera.Area( 8567ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin normalizedRegionUnbounded, meteringRect.getMeteringWeight()); 8577ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin WeightedRectangle reportedMeteringRect = convertCameraAreaToActiveArrayRectangle( 8587ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin activeArray, zoomData, normalizedAreaUnbounded, /*usePreviewCrop*/false); 8597ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin reportedMetering = reportedMeteringRect.rect; 8607ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 8617ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8627ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (VERBOSE) { 8637ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.v(TAG, String.format( 8647ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, " + 8657ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "previewCrop = %s, meteringArea = %s, previewMetering = %s, " + 8667ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "reportedMetering = %s, normalizedRegionUnbounded = %s", 8677ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin activeArray, meteringRect, 8687ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin previewCrop, stringFromArea(meteringArea), previewMetering, 8697ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin reportedMetering, normalizedRegionUnbounded)); 8707ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 8717ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8727ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return new MeteringData(meteringArea, previewMetering, reportedMetering); 8737ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 8747ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8757ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /** 8767ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Convert the normalized camera area from [-1000, 1000] coordinate space 8777ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * into the active array-based coordinate space. 8787ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 8797ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>Values out of range are clipped to be within the resulting (reported) crop 8807ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * region. It is possible to have values larger than the preview crop.</p> 8817ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 8827ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * <p>Weights out of range of [0, 1000] are clipped to be within the range.</p> 8837ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 8847ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param activeArraySize active array size of the sensor (e.g. max jpeg size) 8857ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param zoomData the calculated zoom data corresponding to this request 8867ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @param area the normalized camera area 8877ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * 8887ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * @return the weighed rectangle in active array coordinate space, with the weight 8897ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 8907ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin public static WeightedRectangle convertCameraAreaToActiveArrayRectangle( 8917ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect activeArray, ZoomData zoomData, Camera.Area area) { 8927ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, area, 8937ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /*usePreviewCrop*/true); 8947ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 8957ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 8960a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin /** 8970a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * Convert an api1 face into an active-array based api2 face. 8980a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * 8990a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * <p>Out-of-ranges scores and ids will be clipped to be within range (with a warning).</p> 9000a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * 9010a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * @param face a non-{@code null} api1 face 9020a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * @param activeArraySize active array size of the sensor (e.g. max jpeg size) 9030a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * @param zoomData the calculated zoom data corresponding to this request 9040a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * 9050a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * @return a non-{@code null} api2 face 9060a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * 9070a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin * @throws NullPointerException if the {@code face} was {@code null} 9080a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin */ 9090a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin public static Face convertFaceFromLegacy(Camera.Face face, Rect activeArray, 9100a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin ZoomData zoomData) { 9110a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin checkNotNull(face, "face must not be null"); 9120a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9130a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Face api2Face; 9140a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9150a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Camera.Area fakeArea = new Camera.Area(face.rect, /*weight*/1); 9160a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9170a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin WeightedRectangle faceRect = 9180a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, fakeArea); 9190a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9200a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Point leftEye = face.leftEye, rightEye = face.rightEye, mouth = face.mouth; 921000973a163d7400a8f37b7b472acfa6144b0621bRuben Brunk if (leftEye != null && rightEye != null && mouth != null && leftEye.x != -2000 && 922000973a163d7400a8f37b7b472acfa6144b0621bRuben Brunk leftEye.y != -2000 && rightEye.x != -2000 && rightEye.y != -2000 && 923000973a163d7400a8f37b7b472acfa6144b0621bRuben Brunk mouth.x != -2000 && mouth.y != -2000) { 9240a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin leftEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData, 9250a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin leftEye, /*usePreviewCrop*/true); 9260a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin rightEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData, 9270a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin leftEye, /*usePreviewCrop*/true); 9280a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin mouth = convertCameraPointToActiveArrayPoint(activeArray, zoomData, 9290a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin leftEye, /*usePreviewCrop*/true); 9300a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9310a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin api2Face = faceRect.toFace(face.id, leftEye, rightEye, mouth); 9320a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin } else { 9330a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin api2Face = faceRect.toFace(); 9340a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin } 9350a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9360a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin return api2Face; 9370a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin } 9380a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9390a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin private static Point convertCameraPointToActiveArrayPoint( 9400a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Rect activeArray, ZoomData zoomData, Point point, boolean usePreviewCrop) { 9410a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Rect pointedRect = new Rect(point.x, point.y, point.x, point.y); 9420a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Camera.Area pointedArea = new Area(pointedRect, /*weight*/1); 9430a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9440a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin WeightedRectangle adjustedRect = 9450a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin convertCameraAreaToActiveArrayRectangle(activeArray, 9460a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin zoomData, pointedArea, usePreviewCrop); 9470a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9480a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin Point transformedPoint = new Point(adjustedRect.rect.left, adjustedRect.rect.top); 9490a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9500a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin return transformedPoint; 9510a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin } 9520a1ef4dbf39aa3dfae1a91daf972ae3457ce27feIgor Murashkin 9537ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin private static WeightedRectangle convertCameraAreaToActiveArrayRectangle( 9547ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect activeArray, ZoomData zoomData, Camera.Area area, boolean usePreviewCrop) { 9557ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect previewCrop = zoomData.previewCrop; 9567ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect reportedCrop = zoomData.reportedCrop; 9577ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9587ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin float scaleW = previewCrop.width() * 1.0f / 9597ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN); 9607ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin float scaleH = previewCrop.height() * 1.0f / 9617ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN); 9627ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9637ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin /* 9647ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * Calculate the reported metering region from the non-intersected normalized region 9657ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin * by scaling and translating back into active array-relative coordinates. 9667ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin */ 9677ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Matrix transform = new Matrix(); 9687ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9697ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Move top left from (-1000, -1000) to (0, 0) 9707ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin transform.setTranslate(/*dx*/NORMALIZED_RECTANGLE_MAX, /*dy*/NORMALIZED_RECTANGLE_MAX); 9717ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9727ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Scale from [0, 2000] back into the preview rectangle 9737ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin transform.postScale(scaleW, scaleH); 9747ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9757ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Move the rect so that the [-1000,-1000] point ends up at the preview [left, top] 9767ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin transform.postTranslate(previewCrop.left, previewCrop.top); 9777ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9787ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect cropToIntersectAgainst = usePreviewCrop ? previewCrop : reportedCrop; 9797ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9807ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Now apply the transformation backwards to get the reported metering region 9817ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Rect reportedMetering = ParamsUtils.mapRect(transform, area.rect); 9827ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // Intersect it with the crop region, to avoid reporting out-of-bounds 9837ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin // metering regions 9847ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (!reportedMetering.intersect(cropToIntersectAgainst)) { 9857ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin reportedMetering.set(RECTANGLE_EMPTY); 9867ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 9877ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9887ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin int weight = area.weight; 9897ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin if (weight < MeteringRectangle.METERING_WEIGHT_MIN) { 9907ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin Log.w(TAG, 9917ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin "convertCameraAreaToMeteringRectangle - rectangle " 9927ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin + stringFromArea(area) + " has too small weight, clip to 0"); 9937ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin weight = 0; 9947ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 9957ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9967ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin return new WeightedRectangle(reportedMetering, area.weight); 9977ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin } 9987ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 9997ee78d1ee3ee068897b9313af2ed6446675c1be0Igor Murashkin 1000df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin private ParameterUtils() { 1001df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin throw new AssertionError(); 1002df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin } 1003df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin} 1004