This repository was archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[camera] android-rework part 6: Android exposure- and focus point features #4039
Merged
fluttergithubbot
merged 6 commits into
flutter:master
from
Baseflow:camera-android/exposure_focus_point_features
Jun 23, 2021
Merged
Changes from 1 commit
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
f60a0d3
Merge remote-tracking branch 'upstream/master'
BeMacized baae5f6
Add feature classes for exposure- and focus point functionality.
BeMacized 4f169ab
Implemented PR feedback
BeMacized ba3e96b
Implemented PR feedback
BeMacized 50c219f
Merge branch 'master' into camera-android/exposure_focus_point_features
BeMacized 25a7bb0
[camera] Fix native android tests
BeMacized File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add feature classes for exposure- and focus point functionality.
- Loading branch information
commit baae5f6bc22b72f99d1535e448186d354d44f535
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
138 changes: 138 additions & 0 deletions
138
...ages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegionUtils.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| package io.flutter.plugins.camera; | ||
|
|
||
| import android.annotation.TargetApi; | ||
| import android.hardware.camera2.CaptureRequest; | ||
| import android.hardware.camera2.params.MeteringRectangle; | ||
| import android.os.Build; | ||
| import android.util.Size; | ||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.VisibleForTesting; | ||
| import java.util.Arrays; | ||
|
|
||
| /** | ||
| * Utility class offering functions to calculate values regarding the camera boundaries. | ||
| * | ||
| * <p>The functions are used to calculate focus and exposure settings. | ||
| */ | ||
| public final class CameraRegionUtils { | ||
|
|
||
| /** | ||
| * Obtains the boundaries for the currently active camera, that can be used for calculating | ||
| * MeteringRectangle instances required for setting focus or exposure settings. | ||
| * | ||
| * @param cameraProperties - Collection of the characteristics for the current camera device. | ||
| * @param requestBuilder - The request builder for the current capture request. | ||
| * @return The boundaries for the current camera device. | ||
| */ | ||
| public static Size getCameraBoundaries( | ||
| @NonNull CameraProperties cameraProperties, @NonNull CaptureRequest.Builder requestBuilder) { | ||
| // No distortion correction support | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P | ||
| && supportsDistortionCorrection(cameraProperties)) { | ||
| // Get the current distortion correction mode | ||
| Integer distortionCorrectionMode = | ||
| requestBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE); | ||
|
|
||
| // Return the correct boundaries depending on the mode | ||
| android.graphics.Rect rect; | ||
| if (distortionCorrectionMode == null | ||
| || distortionCorrectionMode == CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) { | ||
| rect = cameraProperties.getSensorInfoPreCorrectionActiveArraySize(); | ||
| } else { | ||
| rect = cameraProperties.getSensorInfoActiveArraySize(); | ||
| } | ||
|
|
||
| // Return camera boundaries | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return rect == null ? null : new Size(rect.width(), rect.height()); | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } else { | ||
| // Return camera boundaries | ||
| return cameraProperties.getSensorInfoPixelArraySize(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Converts a point into a {@link MeteringRectangle} with the supplied coordinates as the centre | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * point. | ||
| * | ||
| * <p>Since the Camera API (due to cross-platform constraints) only accepts a point when | ||
| * configuring a specific focus or exposure area and Android requires a rectangle to configure | ||
| * these settings there is a need to convert the point into a rectangle. This method will create | ||
| * the required rectangle with an arbitrarily size that is a 10th of the current viewport and the | ||
| * coordinates as the centre point. | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * | ||
| * @param boundaries - The camera boundaries to calculate the metering rectangle for. | ||
| * @param x x - 1 >= coordinate >= 0 | ||
| * @param y y - 1 >= coordinate >= 0 | ||
| * @return The dimensions of the metering rectangle based on the supplied coordinates and | ||
| * boundaries. | ||
| */ | ||
| public static MeteringRectangle convertPointToMeteringRectangle( | ||
| @NonNull Size boundaries, double x, double y) { | ||
| assert (boundaries.getWidth() > 0 && boundaries.getHeight() > 0); | ||
| assert (x >= 0 && x <= 1); | ||
| assert (y >= 0 && y <= 1); | ||
|
|
||
| // Interpolate the target coordinate | ||
| int targetX = (int) Math.round(x * ((double) (boundaries.getWidth() - 1))); | ||
| int targetY = (int) Math.round(y * ((double) (boundaries.getHeight() - 1))); | ||
| // Since the Camera API only allows Determine the dimensions of the metering rectangle (10th of | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // the viewport) | ||
| int targetWidth = (int) Math.round(((double) boundaries.getWidth()) / 10d); | ||
| int targetHeight = (int) Math.round(((double) boundaries.getHeight()) / 10d); | ||
| // Adjust target coordinate to represent top-left corner of metering rectangle | ||
| targetX -= targetWidth / 2; | ||
| targetY -= targetHeight / 2; | ||
| // Adjust target coordinate as to not fall out of bounds | ||
| if (targetX < 0) targetX = 0; | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (targetY < 0) targetY = 0; | ||
| int maxTargetX = boundaries.getWidth() - 1 - targetWidth; | ||
| int maxTargetY = boundaries.getHeight() - 1 - targetHeight; | ||
| if (targetX > maxTargetX) targetX = maxTargetX; | ||
| if (targetY > maxTargetY) targetY = maxTargetY; | ||
|
|
||
| // Build the metering rectangle | ||
| return MeteringRectangleFactory.create(targetX, targetY, targetWidth, targetHeight, 1); | ||
| } | ||
|
|
||
| @TargetApi(Build.VERSION_CODES.P) | ||
| private static boolean supportsDistortionCorrection(CameraProperties cameraProperties) { | ||
| int[] availableDistortionCorrectionModes = | ||
| cameraProperties.getDistortionCorrectionAvailableModes(); | ||
| if (availableDistortionCorrectionModes == null) { | ||
| availableDistortionCorrectionModes = new int[0]; | ||
| } | ||
| long nonOffModesSupported = | ||
| Arrays.stream(availableDistortionCorrectionModes) | ||
| .filter((value) -> value != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) | ||
| .count(); | ||
| return nonOffModesSupported > 0; | ||
| } | ||
|
|
||
| /** Factory class that assists in creating a {@link MeteringRectangle} instance. */ | ||
| static class MeteringRectangleFactory { | ||
| /** | ||
| * Creates a new instance of the {@link MeteringRectangle} class. | ||
| * | ||
| * <p>This method is visible for testing purposes only and should never be used outside this * | ||
| * class. | ||
| * | ||
| * @param x coordinate >= 0 | ||
| * @param y coordinate >= 0 | ||
| * @param width width >= 0 | ||
| * @param height height >= 0 | ||
| * @param meteringWeight weight between {@value MeteringRectangle#METERING_WEIGHT_MIN} and | ||
| * {@value MeteringRectangle#METERING_WEIGHT_MAX} inclusively | ||
| * @return new instance of the {@link MeteringRectangle} class. | ||
| * @throws IllegalArgumentException if any of the parameters were negative | ||
| */ | ||
| @VisibleForTesting | ||
| public static MeteringRectangle create( | ||
| int x, int y, int width, int height, int meteringWeight) { | ||
| return new MeteringRectangle(x, y, width, height, meteringWeight); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
...ndroid/src/main/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeature.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // Copyright 2019 The Chromium Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| package io.flutter.plugins.camera.features.focuspoint; | ||
|
|
||
| import android.hardware.camera2.CaptureRequest; | ||
| import android.hardware.camera2.params.MeteringRectangle; | ||
| import android.util.Size; | ||
| import io.flutter.plugins.camera.CameraProperties; | ||
| import io.flutter.plugins.camera.CameraRegionUtils; | ||
| import io.flutter.plugins.camera.features.CameraFeature; | ||
| import io.flutter.plugins.camera.features.Point; | ||
|
|
||
| /** Focus point controls where in the frame focus will come from. */ | ||
| public class FocusPointFeature extends CameraFeature<Point> { | ||
|
|
||
| private Size cameraBoundaries; | ||
| private Point focusPoint; | ||
| private MeteringRectangle focusRectangle; | ||
|
|
||
| /** | ||
| * Creates a new instance of the {@link FocusPointFeature}. | ||
| * | ||
| * @param cameraProperties Collection of the characteristics for the current camera device. | ||
| */ | ||
| public FocusPointFeature(CameraProperties cameraProperties) { | ||
| super(cameraProperties); | ||
| } | ||
|
|
||
| /** | ||
| * Sets the camera boundaries that are required for the focus point feature to function. | ||
| * | ||
| * @param cameraBoundaries - The camera boundaries to set. | ||
| */ | ||
| public void setCameraBoundaries(Size cameraBoundaries) { | ||
| this.cameraBoundaries = cameraBoundaries; | ||
| this.buildFocusRectangle(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getDebugName() { | ||
| return "FocusPointFeature"; | ||
| } | ||
|
|
||
| @Override | ||
| public Point getValue() { | ||
| return focusPoint; | ||
| } | ||
|
|
||
| @Override | ||
| public void setValue(Point value) { | ||
| this.focusPoint = value == null || value.x == null || value.y == null ? null : value; | ||
| this.buildFocusRectangle(); | ||
| } | ||
|
|
||
| // Whether or not this camera can set the exposure point. | ||
| @Override | ||
| public boolean checkIsSupported() { | ||
| if (cameraBoundaries == null) return false; | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Integer supportedRegions = cameraProperties.getControlMaxRegionsAutoFocus(); | ||
| return supportedRegions != null && supportedRegions > 0; | ||
| } | ||
|
|
||
| @Override | ||
| public void updateBuilder(CaptureRequest.Builder requestBuilder) { | ||
| if (!checkIsSupported()) { | ||
| return; | ||
| } | ||
| requestBuilder.set( | ||
| CaptureRequest.CONTROL_AF_REGIONS, | ||
| focusRectangle == null ? null : new MeteringRectangle[] {focusRectangle}); | ||
| } | ||
|
|
||
| private void buildFocusRectangle() { | ||
| if (!checkIsSupported()) { | ||
| return; | ||
| } | ||
BeMacized marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (this.focusPoint == null) { | ||
| this.focusRectangle = null; | ||
| } else { | ||
| this.focusRectangle = | ||
| CameraRegionUtils.convertPointToMeteringRectangle( | ||
| this.cameraBoundaries, this.focusPoint.x, this.focusPoint.y); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.