Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* @param <T>
*/
public abstract class CameraFeature<T> {

protected final CameraProperties cameraProperties;

protected CameraFeature(@NonNull CameraProperties cameraProperties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ public enum FocusMode {

public static FocusMode getValueForString(String modeStr) {
for (FocusMode value : values()) {
if (value.strValue.equals(modeStr)) return value;
if (value.strValue.equals(modeStr)) {
return value;
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.features.CameraFeature;

/**
* Exposure lock controls whether or not exposure mode is currenty locked or automatically metering.
*/
/** Controls whether or not the exposure mode is currently locked or automatically metering. */
public class ExposureLockFeature extends CameraFeature<ExposureMode> {

private ExposureMode currentSetting = ExposureMode.auto;

/**
* Creates a new instance of the {@see ExposureLockFeature}.
*
* @param cameraProperties Collection of the characteristics for the current camera device.
*/
public ExposureLockFeature(CameraProperties cameraProperties) {
super(cameraProperties);
}
Expand Down Expand Up @@ -45,14 +49,6 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) {
return;
}

switch (currentSetting) {
case locked:
requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
break;
case auto:
default:
requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
break;
}
requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, currentSetting == ExposureMode.locked);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,20 @@ public enum ExposureMode {
this.strValue = strValue;
}

/**
* Tries to convert the supplied string into an {@see ExposureMode} enum value.
*
* <p>When the supplied string doesn't match a valid {@see ExposureMode} enum value, null is
* returned.
*
* @param modeStr String value to convert into an {@see ExposureMode} enum value.
* @return Matching {@see ExposureMode} enum value, or null if no match is found.
*/
public static ExposureMode getValueForString(String modeStr) {
for (ExposureMode value : values()) {
if (value.strValue.equals(modeStr)) return value;
if (value.strValue.equals(modeStr)) {
return value;
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@

import android.hardware.camera2.CaptureRequest;
import android.util.Range;
import androidx.annotation.NonNull;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.features.CameraFeature;

/** Exposure offset makes the image brighter or darker. */
public class ExposureOffsetFeature extends CameraFeature<ExposureOffsetValue> {
private ExposureOffsetValue currentSetting;
private final double min;
private final double max;
/** Controls the exposure offset making the resulting image brighter or darker. */
public class ExposureOffsetFeature extends CameraFeature<Double> {

private double currentSetting = 0;

/**
* Creates a new instance of the {@link ExposureOffsetFeature}.
*
* @param cameraProperties Collection of the characteristics for the current camera device.
*/
public ExposureOffsetFeature(CameraProperties cameraProperties) {
super(cameraProperties);

this.min = getMinExposureOffset();
this.max = getMaxExposureOffset();

// Initial offset of 0
this.currentSetting = new ExposureOffsetValue(this.min, this.max, 0);
}

@Override
Expand All @@ -31,14 +30,14 @@ public String getDebugName() {
}

@Override
public ExposureOffsetValue getValue() {
public Double getValue() {
return currentSetting;
}

@Override
public void setValue(ExposureOffsetValue value) {
public void setValue(@NonNull Double value) {
double stepSize = getExposureOffsetStepSize();
this.currentSetting = new ExposureOffsetValue(min, max, (value.value / stepSize));
this.currentSetting = value / stepSize;
}

// Available on all devices.
Expand All @@ -53,41 +52,41 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) {
return;
}

requestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, (int) currentSetting.value);
requestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, (int) currentSetting);
}

/**
* Return the minimum exposure offset double value.
* Returns the minimum exposure offset value, in counts of {@link #getExposureOffsetStepSize}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value is multiplied by stepSize, so this seems wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was strongly influenced by the documentation from the Android Camera2 API when I documented this method.

Here this mention:

Maximum and minimum exposure compensation values for android.control.aeExposureCompensation, in counts of android.control.aeCompensationStep, that are supported by this camera device.

I am not saying this would be necessarily correct or the best, just wanted to quickly verify with you before I update it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow. You're pointing to the documentation for the exposure range, which is line 64 here. This method doesn't return that, it returns that multiplied by the step size (line 67). If you take step counts, and multiply by step sizes, you don't have step counts any more. You have the actual exposure value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right, I completely read the Android documentation wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

*
* @return
* @return double Minimum exposure offset value.
*/
private double getMinExposureOffset() {
public double getMinExposureOffset() {
Range<Integer> range = cameraProperties.getControlAutoExposureCompensationRange();
double minStepped = range == null ? 0 : range.getLower();
double stepSize = getExposureOffsetStepSize();
return minStepped * stepSize;
}

/**
* Return the max exposure offset double value.
* Returns the maximum exposure offset value, in counts of {@link #getExposureOffsetStepSize}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

*
* @return
* @return double Maximum exposure offset value.
*/
private double getMaxExposureOffset() {
public double getMaxExposureOffset() {
Range<Integer> range = cameraProperties.getControlAutoExposureCompensationRange();
double maxStepped = range == null ? 0 : range.getUpper();
double stepSize = getExposureOffsetStepSize();
return maxStepped * stepSize;
}

/**
* Returns the exposure offset step size. This is the smallest amount which the exposure offset
* can be changed.
* Returns the smallest step by which the exposure compensation can be changed.
*
* <p>Example: if this has a value of 0.5, then an aeExposureCompensation setting of -2 means that
* the actual AE offset is -1.
* the actual AE offset is -1. More details can be found in the official Android documentation:
* https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#CONTROL_AE_COMPENSATION_STEP
*
* @return
* @return double Smallest step by which the exposure compensation can be changed.
*/
public double getExposureOffsetStepSize() {
return cameraProperties.getControlAutoExposureCompensationStep();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.features.CameraFeature;
import io.flutter.plugins.camera.features.Point;
import io.flutter.plugins.camera.features.regionboundaries.CameraRegions;
import java.util.concurrent.Callable;
import io.flutter.plugins.camera.types.CameraRegions;

/** Exposure point controls where in the frame exposure metering will come from. */
public class ExposurePointFeature extends CameraFeature<Point> {
// Used later to always get the correct camera regions instance.
private final Callable<CameraRegions> getCameraRegions;

private final CameraRegions cameraRegions;
private Point currentSetting = new Point(0.0, 0.0);

public ExposurePointFeature(
CameraProperties cameraProperties, Callable<CameraRegions> getCameraRegions) {
/**
* Creates a new instance of the {@link ExposurePointFeature}.
*
* @param cameraProperties Collection of the characteristics for the current camera device.
* @param cameraRegions Utility class to assist in calculating exposure boundaries.
*/
public ExposurePointFeature(CameraProperties cameraProperties, CameraRegions cameraRegions) {
super(cameraProperties);
this.getCameraRegions = getCameraRegions;
this.cameraRegions = cameraRegions;
}

@Override
Expand All @@ -40,14 +44,10 @@ public Point getValue() {
public void setValue(@NonNull Point value) {
this.currentSetting = value;

try {
if (value.x == null || value.y == null) {
getCameraRegions.call().resetAutoExposureMeteringRectangle();
} else {
getCameraRegions.call().setAutoExposureMeteringRectangleFromPoint(value.x, value.y);
}
} catch (Exception e) {
e.printStackTrace();
if (value.x == null || value.y == null) {
cameraRegions.resetAutoExposureMeteringRectangle();
} else {
cameraRegions.setAutoExposureMeteringRectangleFromPoint(value.x, value.y);
}
}

Expand All @@ -64,14 +64,15 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) {
return;
}

MeteringRectangle aeRect;
MeteringRectangle aeRect = null;
try {
aeRect = getCameraRegions.call().getAEMeteringRectangle();
requestBuilder.set(
CaptureRequest.CONTROL_AE_REGIONS,
aeRect == null ? null : new MeteringRectangle[] {aeRect});
aeRect = cameraRegions.getAEMeteringRectangle();
} catch (Exception e) {
Log.w("Camera", "Unable to retrieve the Auto Exposure metering rectangle.", e);
}

requestBuilder.set(
CaptureRequest.CONTROL_AE_REGIONS,
aeRect == null ? null : new MeteringRectangle[] {aeRect});
}
}

This file was deleted.

Loading