private static List<Camera.Area> convertMeteringRegionsToLegacy( Rect activeArray, ParameterUtils.ZoomData zoomData, MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) { if (meteringRegions == null || maxNumMeteringAreas <= 0) { if (maxNumMeteringAreas > 0) { return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT); } else { return null; } } // Add all non-zero weight regions to the list List<MeteringRectangle> meteringRectangleList = new ArrayList<>(); for (MeteringRectangle rect : meteringRegions) { if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) { meteringRectangleList.add(rect); } } if (meteringRectangleList.size() == 0) { Log.w(TAG, "Only received metering rectangles with weight 0."); return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT); } // Ignore any regions beyond our maximum supported count int countMeteringAreas = Math.min(maxNumMeteringAreas, meteringRectangleList.size()); List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas); for (int i = 0; i < countMeteringAreas; ++i) { MeteringRectangle rect = meteringRectangleList.get(i); ParameterUtils.MeteringData meteringData = ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData); meteringAreaList.add(meteringData.meteringArea); } if (maxNumMeteringAreas < meteringRectangleList.size()) { Log.w( TAG, "convertMeteringRegionsToLegacy - Too many requested " + regionName + " regions, ignoring all beyond the first " + maxNumMeteringAreas); } if (VERBOSE) { Log.v( TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = " + ParameterUtils.stringFromAreaList(meteringAreaList)); } return meteringAreaList; }
/** * Calculate the actual/effective/reported normalized rectangle data from a metering rectangle. * * <p>If any of the rectangles are out-of-range of their intended bounding box, the {@link * #RECTANGLE_EMPTY empty rectangle} is substituted instead (with a weight of {@code 0}). * * <p>The metering rectangle is bound by the crop region (effective/reported respectively). The * metering {@link Camera.Area area} is bound by {@code [-1000, 1000]}. * * <p>No parameters are mutated; returns the new metering data. * * @param activeArraySize active array size of the sensor (e.g. max jpeg size) * @param meteringRect the user-specified metering rectangle * @param zoomData the calculated zoom data corresponding to this request * @return the metering area, the reported/effective metering rectangles */ public static MeteringData convertMeteringRectangleToLegacy( Rect activeArray, MeteringRectangle meteringRect, ZoomData zoomData) { Rect previewCrop = zoomData.previewCrop; float scaleW = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f / previewCrop.width(); float scaleH = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f / previewCrop.height(); Matrix transform = new Matrix(); // Move the preview crop so that top,left is at (0,0), otherwise after scaling // the corner bounds will be outside of [-1000, 1000] transform.setTranslate(-previewCrop.left, -previewCrop.top); // Scale into [0, 2000] range about the center of the preview transform.postScale(scaleW, scaleH); // Move so that top left of a typical rect is at [-1000, -1000] transform.postTranslate(/*dx*/ NORMALIZED_RECTANGLE_MIN, /*dy*/ NORMALIZED_RECTANGLE_MIN); /* * Calculate the preview metering region (effective), and the camera1 api * normalized metering region. */ Rect normalizedRegionUnbounded = ParamsUtils.mapRect(transform, meteringRect.getRect()); /* * Try to intersect normalized area with [-1000, 1000] rectangle; otherwise * it's completely out of range */ Rect normalizedIntersected = new Rect(normalizedRegionUnbounded); Camera.Area meteringArea; if (!normalizedIntersected.intersect(NORMALIZED_RECTANGLE_DEFAULT)) { Log.w( TAG, "convertMeteringRectangleToLegacy - metering rectangle too small, " + "no metering will be done"); normalizedIntersected.set(RECTANGLE_EMPTY); meteringArea = new Camera.Area(RECTANGLE_EMPTY, MeteringRectangle.METERING_WEIGHT_DONT_CARE); } else { meteringArea = new Camera.Area(normalizedIntersected, meteringRect.getMeteringWeight()); } /* * Calculate effective preview metering region */ Rect previewMetering = meteringRect.getRect(); if (!previewMetering.intersect(previewCrop)) { previewMetering.set(RECTANGLE_EMPTY); } /* * Calculate effective reported metering region * - Transform the calculated metering area back into active array space * - Clip it to be a subset of the reported crop region */ Rect reportedMetering; { Camera.Area normalizedAreaUnbounded = new Camera.Area(normalizedRegionUnbounded, meteringRect.getMeteringWeight()); WeightedRectangle reportedMeteringRect = convertCameraAreaToActiveArrayRectangle( activeArray, zoomData, normalizedAreaUnbounded, /*usePreviewCrop*/ false); reportedMetering = reportedMeteringRect.rect; } if (VERBOSE) { Log.v( TAG, String.format( "convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, " + "previewCrop = %s, meteringArea = %s, previewMetering = %s, " + "reportedMetering = %s, normalizedRegionUnbounded = %s", activeArray, meteringRect, previewCrop, stringFromArea(meteringArea), previewMetering, reportedMetering, normalizedRegionUnbounded)); } return new MeteringData(meteringArea, previewMetering, reportedMetering); }