Commit 3aaa88a3 authored by mcasas's avatar mcasas Committed by Commit bot

Image Capture Android: wire color temperature set/get

This CL adds getter/setter for colour temperature for
Android implementation.  JS API uses Kelvin grades,
whereas the platform uses names, so a mapping of
sorts is introduced.

BUG=650675
TEST= by hand using the JS ImageCapture API.

Review-Url: https://codereview.chromium.org/2385833002
Cr-Commit-Position: refs/heads/master@{#422832}
parent cafda50c
......@@ -32,13 +32,17 @@ class PhotoCapabilities {
public final int whiteBalanceMode;
public final int fillLightMode;
public final boolean redEyeReduction;
public final int maxColorTemperature;
public final int minColorTemperature;
public final int currentColorTemperature;
PhotoCapabilities(int maxIso, int minIso, int currentIso, int maxHeight, int minHeight,
int currentHeight, int maxWidth, int minWidth, int currentWidth, int maxZoom,
int minZoom, int currentZoom, int focusMode, int exposureMode,
int maxExposureCompensation, int minExposureCompensation,
int currentExposureCompensation, int whiteBalanceMode, int fillLightMode,
boolean redEyeReduction) {
boolean redEyeReduction, int maxColorTemperature, int minColorTemperature,
int currentColorTemperature) {
this.maxIso = maxIso;
this.minIso = minIso;
this.currentIso = currentIso;
......@@ -59,6 +63,9 @@ class PhotoCapabilities {
this.whiteBalanceMode = whiteBalanceMode;
this.fillLightMode = fillLightMode;
this.redEyeReduction = redEyeReduction;
this.maxColorTemperature = maxColorTemperature;
this.minColorTemperature = minColorTemperature;
this.currentColorTemperature = currentColorTemperature;
}
@CalledByNative
......@@ -161,6 +168,21 @@ class PhotoCapabilities {
return redEyeReduction;
}
@CalledByNative
public int getMinColorTemperature() {
return minColorTemperature;
}
@CalledByNative
public int getMaxColorTemperature() {
return maxColorTemperature;
}
@CalledByNative
public int getCurrentColorTemperature() {
return currentColorTemperature;
}
public static class Builder {
public int maxIso;
public int minIso;
......@@ -182,6 +204,9 @@ class PhotoCapabilities {
public int whiteBalanceMode;
public int fillLightMode;
public boolean redEyeReduction;
public int maxColorTemperature;
public int minColorTemperature;
public int currentColorTemperature;
public Builder() {}
......@@ -285,11 +310,27 @@ class PhotoCapabilities {
return this;
}
public Builder setMaxColorTemperature(int maxColorTemperature) {
this.maxColorTemperature = maxColorTemperature;
return this;
}
public Builder setMinColorTemperature(int minColorTemperature) {
this.minColorTemperature = minColorTemperature;
return this;
}
public Builder setCurrentColorTemperature(int currentColorTemperature) {
this.currentColorTemperature = currentColorTemperature;
return this;
}
public PhotoCapabilities build() {
return new PhotoCapabilities(maxIso, minIso, currentIso, maxHeight, minHeight,
currentHeight, maxWidth, minWidth, currentWidth, maxZoom, minZoom, currentZoom,
focusMode, exposureMode, maxExposureCompensation, minExposureCompensation,
currentExposureCompensation, whiteBalanceMode, fillLightMode, redEyeReduction);
currentExposureCompensation, whiteBalanceMode, fillLightMode, redEyeReduction,
maxColorTemperature, minColorTemperature, currentColorTemperature);
}
}
}
......@@ -68,12 +68,14 @@ public abstract class VideoCapture {
* @param hasRedEyeReduction Indicates if |redEyeReduction| is set.
* @param redEyeReduction Value of red eye reduction for the auto flash setting.
* @param fillLightMode Flash/Torch setting, following AndroidFillLightMode enum.
* @param colorTemperature White Balance reference temperature, valid if whiteBalanceMode is
* manual, and its value is larger than 0.
*/
@CalledByNative
public abstract void setPhotoOptions(int zoom, int focusMode, int exposureMode, int width,
int height, float[] pointsOfInterest2D, boolean hasExposureCompensation,
int exposureCompensation, int whiteBalanceMode, int iso, boolean hasRedEyeReduction,
boolean redEyeReduction, int fillLightMode);
boolean redEyeReduction, int fillLightMode, int colorTemperature);
@CalledByNative
public abstract boolean takePhoto(final long callbackId);
......
......@@ -10,6 +10,7 @@ import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.os.Build;
import android.util.SparseArray;
import org.chromium.base.Log;
import org.chromium.base.annotations.JNINamespace;
......@@ -33,6 +34,27 @@ public abstract class VideoCaptureCamera
private static final String TAG = "VideoCapture";
protected static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
// Map of the equivalent color temperature in Kelvin for the White Balance setting. The
// values are a mixture of educated guesses and data from Android's Camera2 API. The
// temperatures must be ordered increasingly.
private static final SparseArray<String> COLOR_TEMPERATURES_MAP;
static {
COLOR_TEMPERATURES_MAP = new SparseArray<String>();
COLOR_TEMPERATURES_MAP.append(
2850, android.hardware.Camera.Parameters.WHITE_BALANCE_INCANDESCENT);
COLOR_TEMPERATURES_MAP.append(
2940, android.hardware.Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT);
COLOR_TEMPERATURES_MAP.append(
3000, android.hardware.Camera.Parameters.WHITE_BALANCE_TWILIGHT);
COLOR_TEMPERATURES_MAP.append(
4230, android.hardware.Camera.Parameters.WHITE_BALANCE_FLUORESCENT);
COLOR_TEMPERATURES_MAP.append(
6000, android.hardware.Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT);
COLOR_TEMPERATURES_MAP.append(
6504, android.hardware.Camera.Parameters.WHITE_BALANCE_DAYLIGHT);
COLOR_TEMPERATURES_MAP.append(7000, android.hardware.Camera.Parameters.WHITE_BALANCE_SHADE);
};
private final Object mPhotoTakenCallbackLock = new Object();
// Storage of takePicture() callback Id. There can be one such request in flight at most, and
......@@ -75,6 +97,19 @@ public abstract class VideoCaptureCamera
return parameters;
}
private String getClosestWhiteBalance(int colorTemperature) {
int minDiff = Integer.MAX_VALUE;
String matchedTemperature = null;
for (int i = 0; i < COLOR_TEMPERATURES_MAP.size(); ++i) {
final int diff = Math.abs(colorTemperature - COLOR_TEMPERATURES_MAP.keyAt(i));
if (diff >= minDiff) continue;
minDiff = diff;
matchedTemperature = COLOR_TEMPERATURES_MAP.valueAt(i);
}
return matchedTemperature;
}
private class CrErrorCallback implements android.hardware.Camera.ErrorCallback {
@Override
public void onError(int error, android.hardware.Camera camera) {
......@@ -383,7 +418,15 @@ public abstract class VideoCaptureCamera
? AndroidMeteringMode.CONTINUOUS
: AndroidMeteringMode.FIXED;
}
builder.setWhiteBalanceMode(jniExposureMode);
builder.setWhiteBalanceMode(jniWhiteBalanceMode);
builder.setMinColorTemperature(COLOR_TEMPERATURES_MAP.keyAt(0));
builder.setMaxColorTemperature(
COLOR_TEMPERATURES_MAP.keyAt(COLOR_TEMPERATURES_MAP.size() - 1));
if (jniWhiteBalanceMode == AndroidMeteringMode.FIXED) {
final int index = COLOR_TEMPERATURES_MAP.indexOfValue(parameters.getWhiteBalance());
if (index >= 0) builder.setCurrentColorTemperature(COLOR_TEMPERATURES_MAP.keyAt(index));
}
if (parameters.getSupportedFlashModes() == null) {
builder.setFillLightMode(AndroidFillLightMode.NONE);
......@@ -417,7 +460,7 @@ public abstract class VideoCaptureCamera
public void setPhotoOptions(int zoom, int focusMode, int exposureMode, int width, int height,
float[] pointsOfInterest2D, boolean hasExposureCompensation, int exposureCompensation,
int whiteBalanceMode, int iso, boolean hasRedEyeReduction, boolean redEyeReduction,
int fillLightMode) {
int fillLightMode, int colorTemperature) {
android.hardware.Camera.Parameters parameters = getCameraParameters(mCamera);
if (parameters.isZoomSupported() && zoom > 0) {
......@@ -505,6 +548,10 @@ public abstract class VideoCaptureCamera
} else if (whiteBalanceMode == AndroidMeteringMode.FIXED
&& parameters.isAutoWhiteBalanceLockSupported()) {
parameters.setAutoWhiteBalanceLock(true);
if (colorTemperature > 0) {
final String closestSetting = getClosestWhiteBalance(colorTemperature);
if (closestSetting != null) parameters.setWhiteBalance(closestSetting);
}
}
// NONE is only used for getting capabilities, to signify "no flash unit". Ignore it.
......
......@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.util.Range;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import org.chromium.base.Log;
......@@ -112,7 +113,6 @@ public class VideoCaptureCamera2 extends VideoCapture {
private class CrImageReaderListener implements ImageReader.OnImageAvailableListener {
@Override
public void onImageAvailable(ImageReader reader) {
Log.d(TAG, "CrImageReaderListener.onImageAvailable");
try (Image image = reader.acquireLatestImage()) {
if (image == null) return;
......@@ -200,7 +200,6 @@ public class VideoCaptureCamera2 extends VideoCapture {
@Override
public void onImageAvailable(ImageReader reader) {
Log.d(TAG, "CrPhotoReaderListener.onImageAvailable");
try (Image image = reader.acquireLatestImage()) {
if (image == null) {
throw new IllegalStateException();
......@@ -237,6 +236,21 @@ public class VideoCaptureCamera2 extends VideoCapture {
private static final double kNanoSecondsToFps = 1.0E-9;
private static final String TAG = "VideoCapture";
// Map of the equivalent color temperature in Kelvin for the White Balance setting. The
// values are a mixture of educated guesses and data from Android's Camera2 API. The
// temperatures must be ordered increasingly.
private static final SparseIntArray COLOR_TEMPERATURES_MAP;
static {
COLOR_TEMPERATURES_MAP = new SparseIntArray();
COLOR_TEMPERATURES_MAP.append(2850, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT);
COLOR_TEMPERATURES_MAP.append(2940, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT);
COLOR_TEMPERATURES_MAP.append(3000, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT);
COLOR_TEMPERATURES_MAP.append(4230, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT);
COLOR_TEMPERATURES_MAP.append(6000, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT);
COLOR_TEMPERATURES_MAP.append(6504, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT);
COLOR_TEMPERATURES_MAP.append(7000, CameraMetadata.CONTROL_AWB_MODE_SHADE);
};
private static enum CameraState { OPENING, CONFIGURING, STARTED, STOPPED }
private final Object mCameraStateLock = new Object();
......@@ -256,6 +270,7 @@ public class VideoCaptureCamera2 extends VideoCapture {
private MeteringRectangle mAreaOfInterest;
private int mExposureCompensation = 0;
private int mWhiteBalanceMode = AndroidMeteringMode.CONTINUOUS;
private int mColorTemperature = -1;
private int mIso = 0;
private boolean mRedEyeReduction = false;
private int mFillLightMode = AndroidFillLightMode.OFF;
......@@ -399,6 +414,12 @@ public class VideoCaptureCamera2 extends VideoCapture {
CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_OFF);
} else if (mWhiteBalanceMode == AndroidMeteringMode.FIXED) {
requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
if (mColorTemperature > 0) {
final int colorSetting = getClosestWhiteBalance(mColorTemperature);
if (colorSetting != -1) {
requestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, colorSetting);
}
}
}
if (mAreaOfInterest != null) {
......@@ -444,6 +465,19 @@ public class VideoCaptureCamera2 extends VideoCapture {
return closestSize;
}
private int getClosestWhiteBalance(int colorTemperature) {
int minDiff = Integer.MAX_VALUE;
int matchedTemperature = -1;
for (int i = 0; i < COLOR_TEMPERATURES_MAP.size(); ++i) {
final int diff = Math.abs(colorTemperature - COLOR_TEMPERATURES_MAP.keyAt(i));
if (diff >= minDiff) continue;
minDiff = diff;
matchedTemperature = COLOR_TEMPERATURES_MAP.valueAt(i);
}
return matchedTemperature;
}
static boolean isLegacyDevice(Context appContext, int id) {
final CameraCharacteristics cameraCharacteristics =
getCameraCharacteristics(appContext, id);
......@@ -733,6 +767,13 @@ public class VideoCaptureCamera2 extends VideoCapture {
} else {
builder.setWhiteBalanceMode(AndroidMeteringMode.FIXED);
}
builder.setMinColorTemperature(COLOR_TEMPERATURES_MAP.keyAt(0));
builder.setMaxColorTemperature(
COLOR_TEMPERATURES_MAP.keyAt(COLOR_TEMPERATURES_MAP.size() - 1));
final int index = COLOR_TEMPERATURES_MAP.indexOfValue(whiteBalanceMode);
if (index >= 0) {
builder.setCurrentColorTemperature(COLOR_TEMPERATURES_MAP.keyAt(index));
}
if (!cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
builder.setFillLightMode(AndroidFillLightMode.NONE);
......@@ -772,7 +813,7 @@ public class VideoCaptureCamera2 extends VideoCapture {
public void setPhotoOptions(int zoom, int focusMode, int exposureMode, int width, int height,
float[] pointsOfInterest2D, boolean hasExposureCompensation, int exposureCompensation,
int whiteBalanceMode, int iso, boolean hasRedEyeReduction, boolean redEyeReduction,
int fillLightMode) {
int fillLightMode, int colorTemperature) {
final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mContext, mId);
final Rect canvas =
cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
......@@ -790,6 +831,7 @@ public class VideoCaptureCamera2 extends VideoCapture {
if (focusMode != AndroidMeteringMode.NOT_SET) mFocusMode = focusMode;
if (exposureMode != AndroidMeteringMode.NOT_SET) mExposureMode = exposureMode;
if (whiteBalanceMode != AndroidMeteringMode.NOT_SET) mWhiteBalanceMode = whiteBalanceMode;
if (width > 0) mPhotoWidth = width;
if (height > 0) mPhotoHeight = height;
......@@ -805,7 +847,8 @@ public class VideoCaptureCamera2 extends VideoCapture {
// Update |mAreaOfInterest| if the camera supports and there are |pointsOfInterest2D|.
final boolean pointsOfInterestSupported =
cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) > 0
|| cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE) > 0;
|| cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE) > 0
|| cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB) > 0;
if (pointsOfInterestSupported && pointsOfInterest2D.length > 0) {
assert pointsOfInterest2D.length == 1 : "Only 1 point of interest supported";
assert pointsOfInterest2D[0] <= 1.0 && pointsOfInterest2D[0] >= 0.0;
......@@ -835,10 +878,10 @@ public class VideoCaptureCamera2 extends VideoCapture {
/ cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP)
.floatValue());
}
if (whiteBalanceMode != AndroidMeteringMode.NOT_SET) mWhiteBalanceMode = whiteBalanceMode;
if (iso > 0) mIso = iso;
if (hasRedEyeReduction) mRedEyeReduction = redEyeReduction;
if (mWhiteBalanceMode == AndroidMeteringMode.FIXED && colorTemperature > 0) {
mColorTemperature = colorTemperature;
}
if (fillLightMode != AndroidFillLightMode.NOT_SET) mFillLightMode = fillLightMode;
final Handler mainHandler = new Handler(mContext.getMainLooper());
......
......@@ -132,4 +132,22 @@ bool PhotoCapabilities::getRedEyeReduction() const {
object_);
}
int PhotoCapabilities::getMinColorTemperature() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMinColorTemperature(AttachCurrentThread(),
object_);
}
int PhotoCapabilities::getMaxColorTemperature() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getMaxColorTemperature(AttachCurrentThread(),
object_);
}
int PhotoCapabilities::getCurrentColorTemperature() const {
DCHECK(!object_.is_null());
return Java_PhotoCapabilities_getCurrentColorTemperature(
AttachCurrentThread(), object_);
}
} // namespace media
......@@ -62,6 +62,9 @@ class PhotoCapabilities {
AndroidMeteringMode getWhiteBalanceMode() const;
AndroidFillLightMode getFillLightMode() const;
bool getRedEyeReduction() const;
int getMinColorTemperature() const;
int getMaxColorTemperature() const;
int getCurrentColorTemperature() const;
private:
const base::android::ScopedJavaLocalRef<jobject> object_;
......
......@@ -535,7 +535,11 @@ void VideoCaptureDeviceAndroid::DoGetPhotoCapabilities(
photo_capabilities->fill_light_mode =
ToMojomFillLightMode(caps.getFillLightMode());
photo_capabilities->red_eye_reduction = caps.getRedEyeReduction();
photo_capabilities->color_temperature = mojom::Range::New();
photo_capabilities->color_temperature->current =
caps.getCurrentColorTemperature();
photo_capabilities->color_temperature->max = caps.getMaxColorTemperature();
photo_capabilities->color_temperature->min = caps.getMinColorTemperature();
callback.Run(std::move(photo_capabilities));
}
......@@ -595,7 +599,8 @@ void VideoCaptureDeviceAndroid::DoSetPhotoOptions(
settings->has_exposure_compensation, exposure_compensation,
static_cast<int>(white_balance_mode), iso,
settings->has_red_eye_reduction, settings->red_eye_reduction,
static_cast<int>(fill_light_mode));
static_cast<int>(fill_light_mode),
settings->has_color_temperature ? settings->color_temperature : 0);
callback.Run(true);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment