summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSol Boucher <solb@google.com>2014-08-28 19:30:49 -0700
committerSol Boucher <solb@google.com>2014-08-29 11:46:52 -0700
commit2569329d6cff25bfe9941df539df14a0aeb4c4f4 (patch)
tree451b8993bb048b78ffa1606ac70c9c0c932e24b0
parent47a01cf05c1e22e76bdf3182461dcfeb71b960bb (diff)
downloadandroid_frameworks_ex-2569329d6cff25bfe9941df539df14a0aeb4c4f4.tar.gz
android_frameworks_ex-2569329d6cff25bfe9941df539df14a0aeb4c4f4.tar.bz2
android_frameworks_ex-2569329d6cff25bfe9941df539df14a0aeb4c4f4.zip
camera2-portability: Touch-to-focus accounting for effective crop
This fixes the calculation of API 2 focus and metering rectangles to account for the effective crop region (after the framework has performed automatic cropping to match the requested output aspect ratio). It also guards against and prints warnings when changing the resolution after having configured the session and surfaces; before, this was merely a silent no-op. Bug: 17187095 Change-Id: I3243bea24d6936d1bba5d556b3846d172ad0defe
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java24
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java59
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java2
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraSettings.java2
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java26
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java37
6 files changed, 144 insertions, 6 deletions
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
index bce1b98..f033226 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
@@ -305,6 +305,10 @@ class AndroidCamera2AgentImpl extends CameraAgent {
break;
}
+ // FIXME: We need to tear down the CameraCaptureSession here
+ // (and unlock the CameraSettings object from our
+ // CameraProxy) so that the preview/photo sizes can be
+ // changed again while no preview is running.
case CameraActions.STOP_PREVIEW: {
if (mCameraState.getState() <
AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
@@ -970,6 +974,26 @@ class AndroidCamera2AgentImpl extends CameraAgent {
return mCapabilities;
}
+ // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
+ // explanation on the STOP_PREVIEW case in the handler.
+ @Override
+ public void setPreviewTexture(SurfaceTexture surfaceTexture) {
+ // Once the Surface has been selected, we configure the session and
+ // are no longer able to change the sizes.
+ getSettings().setSizesLocked(true);
+ super.setPreviewTexture(surfaceTexture);
+ }
+
+ // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
+ // explanation on the STOP_PREVIEW case in the handler.
+ @Override
+ public void setPreviewTextureSync(SurfaceTexture surfaceTexture) {
+ // Once the Surface has been selected, we configure the session and
+ // are no longer able to change the sizes.
+ getSettings().setSizesLocked(true);
+ super.setPreviewTexture(surfaceTexture);
+ }
+
// TODO: Implement
@Override
public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java
index 7f6cffe..0d3ef26 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java
@@ -18,7 +18,9 @@ package com.android.ex.camera2.portability;
import static android.hardware.camera2.CaptureRequest.*;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.params.MeteringRectangle;
@@ -43,8 +45,12 @@ public class AndroidCamera2Settings extends CameraSettings {
private final Builder mTemplateSettings;
private final Camera2RequestSettingsSet mRequestSettings;
+ /** Sensor's active array bounds. */
private final Rect mActiveArray;
+ /** Crop rectangle for digital zoom (measured WRT the active array). */
private final Rect mCropRectangle;
+ /** Bounds of visible preview portion (measured WRT the active array). */
+ private Rect mVisiblePreviewRectangle;
/**
* Create a settings representation that answers queries of unspecified
@@ -84,6 +90,8 @@ public class AndroidCamera2Settings extends CameraSettings {
mActiveArray = activeArray;
mCropRectangle = new Rect(0, 0, activeArray.width(), activeArray.height());
+ mSizesLocked = false;
+
Range<Integer> previewFpsRange = mTemplateSettings.get(CONTROL_AE_TARGET_FPS_RANGE);
if (previewFpsRange != null) {
setPreviewFpsRange(previewFpsRange.getLower(), previewFpsRange.getUpper());
@@ -177,6 +185,8 @@ public class AndroidCamera2Settings extends CameraSettings {
@Override
public void setZoomRatio(float ratio) {
super.setZoomRatio(ratio);
+
+ // Compute the crop rectangle to be passed to the framework
mCropRectangle.set(0, 0,
toIntConstrained(
mActiveArray.width() / mCurrentZoomRatio, 0, mActiveArray.width()),
@@ -184,6 +194,10 @@ public class AndroidCamera2Settings extends CameraSettings {
mActiveArray.height() / mCurrentZoomRatio, 0, mActiveArray.height()));
mCropRectangle.offsetTo((mActiveArray.width() - mCropRectangle.width()) / 2,
(mActiveArray.height() - mCropRectangle.height()) / 2);
+
+ // Compute the effective crop rectangle to be used for computing focus/metering coordinates
+ mVisiblePreviewRectangle =
+ effectiveCropRectFromRequested(mCropRectangle, mCurrentPreviewSize);
}
private boolean matchesTemplateDefault(Key<?> setting) {
@@ -512,4 +526,49 @@ public class AndroidCamera2Settings extends CameraSettings {
mRequestSettings.set(JPEG_GPS_LOCATION, location);
}
}
+
+ /**
+ * Calculate the effective crop rectangle for this preview viewport;
+ * assumes the preview is centered to the sensor and scaled to fit across one of the dimensions
+ * without skewing.
+ *
+ * <p>Assumes the zoom level of the provided desired crop rectangle.</p>
+ *
+ * @param requestedCrop Desired crop rectangle, in active array space.
+ * @param previewSize Size of the preview buffer render target, in pixels (not in sensor space).
+ * @return A rectangle that serves as the preview stream's effective crop region (unzoomed), in
+ * sensor space.
+ *
+ * @throws NullPointerException
+ * If any of the args were {@code null}.
+ */
+ private static Rect effectiveCropRectFromRequested(Rect requestedCrop, Size previewSize) {
+ float aspectRatioArray = requestedCrop.width() * 1.0f / requestedCrop.height();
+ float aspectRatioPreview = previewSize.width() * 1.0f / previewSize.height();
+
+ float cropHeight, cropWidth;
+ if (aspectRatioPreview < aspectRatioArray) {
+ // The new width must be smaller than the height, so scale the width by AR
+ cropHeight = requestedCrop.height();
+ cropWidth = cropHeight * aspectRatioPreview;
+ } else {
+ // The new height must be smaller (or equal) than the width, so scale the height by AR
+ cropWidth = requestedCrop.width();
+ cropHeight = cropWidth / aspectRatioPreview;
+ }
+
+ Matrix translateMatrix = new Matrix();
+ RectF cropRect = new RectF(/*left*/0, /*top*/0, cropWidth, cropHeight);
+
+ // Now center the crop rectangle so its center is in the center of the active array
+ translateMatrix.setTranslate(requestedCrop.exactCenterX(), requestedCrop.exactCenterY());
+ translateMatrix.postTranslate(-cropRect.centerX(), -cropRect.centerY());
+
+ translateMatrix.mapRect(/*inout*/cropRect);
+
+ // Round the rect corners towards the nearest integer values
+ Rect result = new Rect();
+ cropRect.roundOut(result);
+ return result;
+ }
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
index f8a2e38..f9344c2 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
@@ -400,6 +400,7 @@ class AndroidCameraAgentImpl extends CameraAgent {
break;
}
+ // TODO: Lock the CameraSettings object's sizes
case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: {
setPreviewTexture(msg.obj);
break;
@@ -424,6 +425,7 @@ class AndroidCameraAgentImpl extends CameraAgent {
break;
}
+ // TODO: Unlock the CameraSettings object's sizes
case CameraActions.STOP_PREVIEW: {
mCamera.stopPreview();
break;
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraSettings.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraSettings.java
index f5421d6..ee69b54 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraSettings.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraSettings.java
@@ -28,6 +28,8 @@ public class AndroidCameraSettings extends CameraSettings {
public AndroidCameraSettings(CameraCapabilities capabilities, Camera.Parameters params) {
CameraCapabilities.Stringifier stringifier = capabilities.getStringifier();
+ setSizesLocked(false);
+
// Preview
Camera.Size paramPreviewSize = params.getPreviewSize();
setPreviewSize(new Size(paramPreviewSize.width, paramPreviewSize.height));
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java
index df94a41..b624b47 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java
@@ -436,8 +436,24 @@ public abstract class CameraAgent {
/**
* Sets the {@link android.graphics.SurfaceTexture} for preview.
*
+ * <p>Note that, once this operation has been performed, it is no longer
+ * possible to change the preview or photo sizes in the
+ * {@link CameraSettings} instance for this camera, and the mutators for
+ * these fields are allowed to ignore all further invocations until the
+ * preview is stopped with {@link #stopPreview}.</p>
+ *
* @param surfaceTexture The {@link SurfaceTexture} for preview.
- */
+ *
+ * @see CameraSettings#setPhotoSize
+ * @see CameraSettings#setPreviewSize
+ */
+ // XXX: Despite the above documentation about locking the sizes, the API
+ // 1 implementation doesn't currently enforce this at all, although the
+ // Camera class warns that preview sizes shouldn't be changed while a
+ // preview is running. Furthermore, the API 2 implementation doesn't yet
+ // unlock the sizes when stopPreview() is invoked (see related FIXME on
+ // the STOP_PREVIEW case in its handler; in the meantime, changing API 2
+ // sizes would require closing and reopening the camera.
public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
getDispatchThread().runJob(new Runnable() {
@Override
@@ -452,7 +468,15 @@ public abstract class CameraAgent {
* Blocks until a {@link android.graphics.SurfaceTexture} has been set
* for preview.
*
+ * <p>Note that, once this operation has been performed, it is no longer
+ * possible to change the preview or photo sizes in the
+ * {@link CameraSettings} instance for this camera, and the mutators for
+ * these fields are allowed to ignore all further invocations.</p>
+ *
* @param surfaceTexture The {@link SurfaceTexture} for preview.
+ *
+ * @see CameraSettings#setPhotoSize
+ * @see CameraSettings#setPreviewSize
*/
public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
final WaitDoneBundle bundle = new WaitDoneBundle();
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java
index d0600e8..87e9adf 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java
@@ -38,6 +38,7 @@ public abstract class CameraSettings {
protected final Map<String, String> mGeneralSetting = new TreeMap<>();
protected final List<Camera.Area> mMeteringAreas = new ArrayList<>();
protected final List<Camera.Area> mFocusAreas = new ArrayList<>();
+ protected boolean mSizesLocked;
protected int mPreviewFpsRangeMin;
protected int mPreviewFpsRangeMax;
protected int mPreviewFrameRate;
@@ -116,6 +117,7 @@ public abstract class CameraSettings {
mGeneralSetting.putAll(src.mGeneralSetting);
mMeteringAreas.addAll(src.mMeteringAreas);
mFocusAreas.addAll(src.mFocusAreas);
+ mSizesLocked = src.mSizesLocked;
mPreviewFpsRangeMin = src.mPreviewFpsRangeMin;
mPreviewFpsRangeMax = src.mPreviewFpsRangeMax;
mPreviewFrameRate = src.mPreviewFrameRate;
@@ -151,6 +153,19 @@ public abstract class CameraSettings {
mGeneralSetting.put(key, value);
}
+ /**
+ * Changes whether classes outside this class are allowed to set the preview
+ * and photo capture sizes.
+ *
+ * @param locked Whether to prevent changes to these fields.
+ *
+ * @see #setPhotoSize
+ * @see #setPreviewSize
+ */
+ /*package*/ void setSizesLocked(boolean locked) {
+ mSizesLocked = locked;
+ }
+
/** Preview **/
/**
@@ -212,9 +227,16 @@ public abstract class CameraSettings {
/**
* @param previewSize The size to use for preview.
+ * @return Whether the operation was allowed (i.e. the sizes are unlocked).
*/
- public void setPreviewSize(Size previewSize) {
+ public boolean setPreviewSize(Size previewSize) {
+ if (mSizesLocked) {
+ Log.w(TAG, "Attempt to change preview size while locked");
+ return false;
+ }
+
mCurrentPreviewSize = new Size(previewSize);
+ return true;
}
/**
@@ -245,12 +267,17 @@ public abstract class CameraSettings {
}
/**
- * Sets the size for the photo.
- *
- * @param photoSize The photo size.
+ * @param photoSize The size to use for preview.
+ * @return Whether the operation was allowed (i.e. the sizes are unlocked).
*/
- public void setPhotoSize(Size photoSize) {
+ public boolean setPhotoSize(Size photoSize) {
+ if (mSizesLocked) {
+ Log.w(TAG, "Attempt to change photo size while locked");
+ return false;
+ }
+
mCurrentPhotoSize = new Size(photoSize);
+ return true;
}
/**