diff options
author | Igor Murashkin <iam@google.com> | 2014-07-09 17:20:23 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2014-07-11 12:59:50 -0700 |
commit | 3e280b4bb23be4e5e66ea6381fd63c74fdbd927e (patch) | |
tree | 274b80cd28fa5a9f41fb03a634f38d21043abc2a /core | |
parent | 7ee78d1ee3ee068897b9313af2ed6446675c1be0 (diff) | |
download | frameworks_base-3e280b4bb23be4e5e66ea6381fd63c74fdbd927e.zip frameworks_base-3e280b4bb23be4e5e66ea6381fd63c74fdbd927e.tar.gz frameworks_base-3e280b4bb23be4e5e66ea6381fd63c74fdbd927e.tar.bz2 |
camera2: (Legacy) Implement ae compensation step ranges and ae/awb locks
Characteristics:
* control.aeCompensationRange
* control.aeCompensationStep
Request/Result:
* control.aeExposureCompensation
* control.aeLock
* control.awbLock
Change-Id: I911616c9cf3e0e9a03a0cb383bcf232cab8ca772
Diffstat (limited to 'core')
4 files changed, 160 insertions, 2 deletions
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java index 149f4c8..d413cbd 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java @@ -355,6 +355,25 @@ public class LegacyMetadataMapper { // Note that AE_MODE_OFF is never available. m.set(CONTROL_AE_AVAILABLE_MODES, aeAvail); } + + /* + * control.aeCompensationRanges + */ + { + int min = p.getMinExposureCompensation(); + int max = p.getMaxExposureCompensation(); + + m.set(CONTROL_AE_COMPENSATION_RANGE, Range.create(min, max)); + } + + /* + * control.aeCompensationStep + */ + { + float step = p.getExposureCompensationStep(); + + m.set(CONTROL_AE_COMPENSATION_STEP, ParamsUtils.createRational(step)); + } } private static void mapControlAwb(CameraMetadataNative m, Camera.Parameters p) { diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java index cc18865..124fa42 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java @@ -30,6 +30,7 @@ import android.util.Size; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import static com.android.internal.util.Preconditions.*; import static android.hardware.camera2.CaptureRequest.*; @@ -153,13 +154,52 @@ public class LegacyRequestMapper { * control */ + // control.aeExposureCompensation + { + Range<Integer> compensationRange = + characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE); + int compensation = getOrDefault(request, + CONTROL_AE_EXPOSURE_COMPENSATION, + /*defaultValue*/0); + + if (!compensationRange.inRange(compensation)) { + Log.w(TAG, + "convertRequestMetadata - control.aeExposureCompensation " + + "is out of range, ignoring value"); + compensation = 0; + } + + params.setExposureCompensation(compensation); + } + + // control.aeLock + { + Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false, + params.isAutoExposureLockSupported(), + /*allowedValue*/false); + + if (aeLock != null) { + params.setAutoExposureLock(aeLock); + } + + // TODO: Don't add control.aeLock to availableRequestKeys if it's not supported + } + // control.aeMode, flash.mode mapAeAndFlashMode(request, /*out*/params); // control.awbLock - Boolean awbLock = request.get(CONTROL_AWB_LOCK); - params.setAutoWhiteBalanceLock(awbLock == null ? false : awbLock); + { + Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false, + params.isAutoWhiteBalanceLockSupported(), + /*allowedValue*/false); + if (awbLock != null) { + params.setAutoWhiteBalanceLock(awbLock); + } + + // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported + } } private static List<Camera.Area> convertMeteringRegionsToLegacy( @@ -275,6 +315,7 @@ public class LegacyRequestMapper { return legacyFps; } + /** Return the value set by the key, or the {@code defaultValue} if no value was set. */ private static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) { checkNotNull(r, "r must not be null"); checkNotNull(key, "key must not be null"); @@ -287,4 +328,29 @@ public class LegacyRequestMapper { return value; } } + + /** + * Return {@code null} if the value is not supported, otherwise return the retrieved key's + * value from the request (or the default value if it wasn't set). + * + * <p>If the fetched value in the request is equivalent to {@code allowedValue}, + * then omit the warning (e.g. turning off AF lock on a camera + * that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p> + * + * <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p. + */ + private static <T> T getIfSupported( + CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported, + T allowedValue) { + T val = getOrDefault(r, key, defaultValue); + + if (!isSupported) { + if (!Objects.equals(val, allowedValue)) { + Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val); + } + return null; + } + + return val; + } } diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java index b592b8c..375e6e0 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java @@ -28,7 +28,9 @@ import android.hardware.camera2.legacy.ParameterUtils.WeightedRectangle; import android.hardware.camera2.legacy.ParameterUtils.ZoomData; import android.hardware.camera2.params.MeteringRectangle; import android.hardware.camera2.utils.ListUtils; +import android.hardware.camera2.utils.ParamsUtils; import android.util.Log; +import android.util.Rational; import android.util.Size; import java.util.ArrayList; @@ -125,6 +127,17 @@ public class LegacyResultMapper { m.set(CONTROL_AE_ANTIBANDING_MODE, antiBandingMode); } + // control.aeExposureCompensation + { + m.set(CONTROL_AE_EXPOSURE_COMPENSATION, p.getExposureCompensation()); + } + + // control.aeLock + { + boolean lock = p.isAutoExposureLockSupported() ? p.getAutoExposureLock() : false; + m.set(CONTROL_AE_LOCK, lock); + } + // control.aeMode, flash.mode mapAeAndFlashMode(m, p); @@ -160,6 +173,13 @@ public class LegacyResultMapper { m.set(CONTROL_AF_REGIONS, meteringRectArray); } + + // control.awbLock + { + boolean lock = p.isAutoWhiteBalanceLockSupported() ? + p.getAutoWhiteBalanceLock() : false; + m.set(CONTROL_AWB_LOCK, lock); + } } private static MeteringRectangle[] getMeteringRectangles(Rect activeArray, ZoomData zoomData, diff --git a/core/java/android/hardware/camera2/utils/ParamsUtils.java b/core/java/android/hardware/camera2/utils/ParamsUtils.java index 6c0fd2d..232a4f6 100644 --- a/core/java/android/hardware/camera2/utils/ParamsUtils.java +++ b/core/java/android/hardware/camera2/utils/ParamsUtils.java @@ -19,6 +19,7 @@ package android.hardware.camera2.utils; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; +import android.util.Rational; import android.util.Size; import static com.android.internal.util.Preconditions.*; @@ -28,6 +29,9 @@ import static com.android.internal.util.Preconditions.*; */ public class ParamsUtils { + /** Arbitrary denominator used to estimate floats as rationals */ + private static final int RATIONAL_DENOMINATOR = 1000000; // 1million + /** * Create a {@link Rect} from a {@code Size} by creating a new rectangle with * left, top = {@code (0, 0)} and right, bottom = {@code (width, height)} @@ -104,6 +108,55 @@ public class ParamsUtils { } /** + * Create a {@link Rational} value by approximating the float value as a rational. + * + * <p>Floating points too large to be represented as an integer will be converted to + * to {@link Integer#MAX_VALUE}; floating points too small to be represented as an integer + * will be converted to {@link Integer#MIN_VALUE}.</p> + * + * @param value a floating point value + * @return the rational representation of the float + */ + public static Rational createRational(float value) { + if (Float.isNaN(value)) { + return Rational.NaN; + } else if (value == Float.POSITIVE_INFINITY) { + return Rational.POSITIVE_INFINITY; + } else if (value == Float.NEGATIVE_INFINITY) { + return Rational.NEGATIVE_INFINITY; + } else if (value == 0.0f) { + return Rational.ZERO; + } + + // normal finite value: approximate it + + /* + * Start out trying to approximate with denominator = 1million, + * but if the numerator doesn't fit into an Int then keep making the denominator + * smaller until it does. + */ + int den = RATIONAL_DENOMINATOR; + float numF; + do { + numF = value * den; + + if ((numF > Integer.MIN_VALUE && numF < Integer.MAX_VALUE) || (den == 1)) { + break; + } + + den /= 10; + } while (true); + + /* + * By float -> int narrowing conversion in JLS 5.1.3, this will automatically become + * MIN_VALUE or MAX_VALUE if numF is too small/large to be represented by an integer + */ + int num = (int) numF; + + return new Rational(num, den); + } + + /** * Convert an integral rectangle ({@code source}) to a floating point rectangle * ({@code destination}) in-place. * |