Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 2bfba7b

Browse files
authored
[camera] android-rework part 3: Android exposure related features (#3797)
Adds exposure related features containing the implementation to handle auto exposure, exposure lock, exposure offset and exposure point via the Android Camera2 API. This is the third PR in a series of pull-requests which will gradually introduce changes from PR #3651, making it easier to review the code (as discussed with @stuartmorgan).
1 parent f7ee663 commit 2bfba7b

File tree

15 files changed

+1134
-40
lines changed

15 files changed

+1134
-40
lines changed

packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeature.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* @param <T>
1818
*/
1919
public abstract class CameraFeature<T> {
20+
2021
protected final CameraProperties cameraProperties;
2122

2223
protected CameraFeature(@NonNull CameraProperties cameraProperties) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.camera.features;
6+
7+
/** Represents a point on an x/y axis. */
8+
public class Point {
9+
public final Double x;
10+
public final Double y;
11+
12+
public Point(Double x, Double y) {
13+
this.x = x;
14+
this.y = y;
15+
}
16+
}

packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/autofocus/FocusMode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ public enum FocusMode {
1717

1818
public static FocusMode getValueForString(String modeStr) {
1919
for (FocusMode value : values()) {
20-
if (value.strValue.equals(modeStr)) return value;
20+
if (value.strValue.equals(modeStr)) {
21+
return value;
22+
}
2123
}
2224
return null;
2325
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.camera.features.exposurelock;
6+
7+
import android.hardware.camera2.CaptureRequest;
8+
import io.flutter.plugins.camera.CameraProperties;
9+
import io.flutter.plugins.camera.features.CameraFeature;
10+
11+
/** Controls whether or not the exposure mode is currently locked or automatically metering. */
12+
public class ExposureLockFeature extends CameraFeature<ExposureMode> {
13+
14+
private ExposureMode currentSetting = ExposureMode.auto;
15+
16+
/**
17+
* Creates a new instance of the {@see ExposureLockFeature}.
18+
*
19+
* @param cameraProperties Collection of the characteristics for the current camera device.
20+
*/
21+
public ExposureLockFeature(CameraProperties cameraProperties) {
22+
super(cameraProperties);
23+
}
24+
25+
@Override
26+
public String getDebugName() {
27+
return "ExposureLockFeature";
28+
}
29+
30+
@Override
31+
public ExposureMode getValue() {
32+
return currentSetting;
33+
}
34+
35+
@Override
36+
public void setValue(ExposureMode value) {
37+
this.currentSetting = value;
38+
}
39+
40+
// Available on all devices.
41+
@Override
42+
public boolean checkIsSupported() {
43+
return true;
44+
}
45+
46+
@Override
47+
public void updateBuilder(CaptureRequest.Builder requestBuilder) {
48+
if (!checkIsSupported()) {
49+
return;
50+
}
51+
52+
requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, currentSetting == ExposureMode.locked);
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.camera.features.exposurelock;
6+
7+
// Mirrors exposure_mode.dart
8+
public enum ExposureMode {
9+
auto("auto"),
10+
locked("locked");
11+
12+
private final String strValue;
13+
14+
ExposureMode(String strValue) {
15+
this.strValue = strValue;
16+
}
17+
18+
/**
19+
* Tries to convert the supplied string into an {@see ExposureMode} enum value.
20+
*
21+
* <p>When the supplied string doesn't match a valid {@see ExposureMode} enum value, null is
22+
* returned.
23+
*
24+
* @param modeStr String value to convert into an {@see ExposureMode} enum value.
25+
* @return Matching {@see ExposureMode} enum value, or null if no match is found.
26+
*/
27+
public static ExposureMode getValueForString(String modeStr) {
28+
for (ExposureMode value : values()) {
29+
if (value.strValue.equals(modeStr)) {
30+
return value;
31+
}
32+
}
33+
return null;
34+
}
35+
36+
@Override
37+
public String toString() {
38+
return strValue;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.camera.features.exposureoffset;
6+
7+
import android.hardware.camera2.CaptureRequest;
8+
import android.util.Range;
9+
import androidx.annotation.NonNull;
10+
import io.flutter.plugins.camera.CameraProperties;
11+
import io.flutter.plugins.camera.features.CameraFeature;
12+
13+
/** Controls the exposure offset making the resulting image brighter or darker. */
14+
public class ExposureOffsetFeature extends CameraFeature<Double> {
15+
16+
private double currentSetting = 0;
17+
18+
/**
19+
* Creates a new instance of the {@link ExposureOffsetFeature}.
20+
*
21+
* @param cameraProperties Collection of the characteristics for the current camera device.
22+
*/
23+
public ExposureOffsetFeature(CameraProperties cameraProperties) {
24+
super(cameraProperties);
25+
}
26+
27+
@Override
28+
public String getDebugName() {
29+
return "ExposureOffsetFeature";
30+
}
31+
32+
@Override
33+
public Double getValue() {
34+
return currentSetting;
35+
}
36+
37+
@Override
38+
public void setValue(@NonNull Double value) {
39+
double stepSize = getExposureOffsetStepSize();
40+
this.currentSetting = value / stepSize;
41+
}
42+
43+
// Available on all devices.
44+
@Override
45+
public boolean checkIsSupported() {
46+
return true;
47+
}
48+
49+
@Override
50+
public void updateBuilder(CaptureRequest.Builder requestBuilder) {
51+
if (!checkIsSupported()) {
52+
return;
53+
}
54+
55+
requestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, (int) currentSetting);
56+
}
57+
58+
/**
59+
* Returns the minimum exposure offset.
60+
*
61+
* @return double Minimum exposure offset.
62+
*/
63+
public double getMinExposureOffset() {
64+
Range<Integer> range = cameraProperties.getControlAutoExposureCompensationRange();
65+
double minStepped = range == null ? 0 : range.getLower();
66+
double stepSize = getExposureOffsetStepSize();
67+
return minStepped * stepSize;
68+
}
69+
70+
/**
71+
* Returns the maximum exposure offset.
72+
*
73+
* @return double Maximum exposure offset.
74+
*/
75+
public double getMaxExposureOffset() {
76+
Range<Integer> range = cameraProperties.getControlAutoExposureCompensationRange();
77+
double maxStepped = range == null ? 0 : range.getUpper();
78+
double stepSize = getExposureOffsetStepSize();
79+
return maxStepped * stepSize;
80+
}
81+
82+
/**
83+
* Returns the smallest step by which the exposure compensation can be changed.
84+
*
85+
* <p>Example: if this has a value of 0.5, then an aeExposureCompensation setting of -2 means that
86+
* the actual AE offset is -1. More details can be found in the official Android documentation:
87+
* https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#CONTROL_AE_COMPENSATION_STEP
88+
*
89+
* @return double Smallest step by which the exposure compensation can be changed.
90+
*/
91+
public double getExposureOffsetStepSize() {
92+
return cameraProperties.getControlAutoExposureCompensationStep();
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.camera.features.exposurepoint;
6+
7+
import android.hardware.camera2.CaptureRequest;
8+
import android.hardware.camera2.params.MeteringRectangle;
9+
import android.util.Log;
10+
import androidx.annotation.NonNull;
11+
import io.flutter.plugins.camera.CameraProperties;
12+
import io.flutter.plugins.camera.features.CameraFeature;
13+
import io.flutter.plugins.camera.features.Point;
14+
import io.flutter.plugins.camera.types.CameraRegions;
15+
16+
/** Exposure point controls where in the frame exposure metering will come from. */
17+
public class ExposurePointFeature extends CameraFeature<Point> {
18+
19+
private final CameraRegions cameraRegions;
20+
private Point currentSetting = new Point(0.0, 0.0);
21+
22+
/**
23+
* Creates a new instance of the {@link ExposurePointFeature}.
24+
*
25+
* @param cameraProperties Collection of the characteristics for the current camera device.
26+
* @param cameraRegions Utility class to assist in calculating exposure boundaries.
27+
*/
28+
public ExposurePointFeature(CameraProperties cameraProperties, CameraRegions cameraRegions) {
29+
super(cameraProperties);
30+
this.cameraRegions = cameraRegions;
31+
}
32+
33+
@Override
34+
public String getDebugName() {
35+
return "ExposurePointFeature";
36+
}
37+
38+
@Override
39+
public Point getValue() {
40+
return currentSetting;
41+
}
42+
43+
@Override
44+
public void setValue(@NonNull Point value) {
45+
this.currentSetting = value;
46+
47+
if (value.x == null || value.y == null) {
48+
cameraRegions.resetAutoExposureMeteringRectangle();
49+
} else {
50+
cameraRegions.setAutoExposureMeteringRectangleFromPoint(value.x, value.y);
51+
}
52+
}
53+
54+
// Whether or not this camera can set the exposure point.
55+
@Override
56+
public boolean checkIsSupported() {
57+
Integer supportedRegions = cameraProperties.getControlMaxRegionsAutoExposure();
58+
return supportedRegions != null && supportedRegions > 0;
59+
}
60+
61+
@Override
62+
public void updateBuilder(CaptureRequest.Builder requestBuilder) {
63+
if (!checkIsSupported()) {
64+
return;
65+
}
66+
67+
MeteringRectangle aeRect = null;
68+
try {
69+
aeRect = cameraRegions.getAEMeteringRectangle();
70+
} catch (Exception e) {
71+
Log.w("Camera", "Unable to retrieve the Auto Exposure metering rectangle.", e);
72+
}
73+
74+
requestBuilder.set(
75+
CaptureRequest.CONTROL_AE_REGIONS,
76+
aeRect == null ? null : new MeteringRectangle[] {aeRect});
77+
}
78+
}

0 commit comments

Comments
 (0)