summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2012-09-24 15:18:41 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-09-24 15:18:42 -0700
commitaae1de9eaba5aa3e2bce68b59aa78f918020f5a8 (patch)
treedc94163f914abda0814140a704beb3a735e3ea70 /services
parent8d452f1c61aa70c4a86c4114532f2c0983120ef8 (diff)
parent018d228ac43a8da7d5f36e45fd105c9baf2490a0 (diff)
downloadframeworks_av-aae1de9eaba5aa3e2bce68b59aa78f918020f5a8.zip
frameworks_av-aae1de9eaba5aa3e2bce68b59aa78f918020f5a8.tar.gz
frameworks_av-aae1de9eaba5aa3e2bce68b59aa78f918020f5a8.tar.bz2
Merge "Camera2: Fix cropRegion sometimes exceeding the sensor array size" into jb-mr1-dev
Diffstat (limited to 'services')
-rw-r--r--services/camera/libcameraservice/camera2/Parameters.cpp132
-rw-r--r--services/camera/libcameraservice/camera2/Parameters.h9
2 files changed, 117 insertions, 24 deletions
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp
index 0a72c5f..82783e3 100644
--- a/services/camera/libcameraservice/camera2/Parameters.cpp
+++ b/services/camera/libcameraservice/camera2/Parameters.cpp
@@ -680,7 +680,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
params.set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
camera_metadata_ro_entry_t maxDigitalZoom =
- staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM, 1, 1);
+ staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM, /*minCount*/1, /*maxCount*/1);
if (!maxDigitalZoom.count) return NO_INIT;
{
@@ -1505,29 +1505,8 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
if (res != OK) return res;
delete[] reqMeteringAreas;
- // Need to convert zoom index into a crop rectangle. The rectangle is
- // chosen to maximize its area on the sensor
-
- camera_metadata_ro_entry_t maxDigitalZoom =
- staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM);
- float zoomIncrement = (maxDigitalZoom.data.f[0] - 1) /
- (NUM_ZOOM_STEPS-1);
- float zoomRatio = 1 + zoomIncrement * zoom;
-
- float zoomLeft, zoomTop, zoomWidth, zoomHeight;
- if (previewWidth >= previewHeight) {
- zoomWidth = fastInfo.arrayWidth / zoomRatio;
- zoomHeight = zoomWidth *
- previewHeight / previewWidth;
- } else {
- zoomHeight = fastInfo.arrayHeight / zoomRatio;
- zoomWidth = zoomHeight *
- previewWidth / previewHeight;
- }
- zoomLeft = (fastInfo.arrayWidth - zoomWidth) / 2;
- zoomTop = (fastInfo.arrayHeight - zoomHeight) / 2;
-
- int32_t reqCropRegion[3] = { zoomLeft, zoomTop, zoomWidth };
+ CropRegion crop = calculateCropRegion();
+ int32_t reqCropRegion[3] = { crop.left, crop.top, crop.width };
res = request->update(ANDROID_SCALER_CROP_REGION,
reqCropRegion, 3);
if (res != OK) return res;
@@ -1880,5 +1859,110 @@ int Parameters::normalizedYToArray(int y) const {
return (y + 1000) * (fastInfo.arrayHeight - 1) / 2000;
}
+Parameters::CropRegion Parameters::calculateCropRegion(void) const {
+
+ float zoomLeft, zoomTop, zoomWidth, zoomHeight;
+
+ // Need to convert zoom index into a crop rectangle. The rectangle is
+ // chosen to maximize its area on the sensor
+
+ camera_metadata_ro_entry_t maxDigitalZoom =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM);
+ // For each zoom step by how many pixels more do we change the zoom
+ float zoomIncrement = (maxDigitalZoom.data.f[0] - 1) /
+ (NUM_ZOOM_STEPS-1);
+ // The desired activeAreaWidth/cropAreaWidth ratio (or height if h>w)
+ // via interpolating zoom step into a zoom ratio
+ float zoomRatio = 1 + zoomIncrement * zoom;
+ ALOG_ASSERT( (zoomRatio >= 1.f && zoomRatio <= maxDigitalZoom.data.f[0]),
+ "Zoom ratio calculated out of bounds. Expected 1 - %f, actual: %f",
+ maxDigitalZoom.data.f[0], zoomRatio);
+
+ ALOGV("Zoom maxDigital=%f, increment=%f, ratio=%f, previewWidth=%d, "
+ "previewHeight=%d, activeWidth=%d, activeHeight=%d",
+ maxDigitalZoom.data.f[0], zoomIncrement, zoomRatio, previewWidth,
+ previewHeight, fastInfo.arrayWidth, fastInfo.arrayHeight);
+
+ /*
+ * Assumption: On the HAL side each stream buffer calculates its crop
+ * rectangle as follows:
+ * cropRect = (zoomLeft, zoomRight,
+ * zoomWidth, zoomHeight * zoomWidth / outputWidth);
+ *
+ * Note that if zoomWidth > bufferWidth, the new cropHeight > zoomHeight
+ * (we can then get into trouble if the cropHeight > arrayHeight).
+ * By selecting the zoomRatio based on the smallest outputRatio, we
+ * guarantee this will never happen.
+ */
+
+ // Enumerate all possible output sizes, select the one with the smallest
+ // aspect ratio
+ float minOutputWidth, minOutputHeight, minOutputRatio;
+ {
+ float outputSizes[][2] = {
+ { previewWidth, previewHeight },
+ { videoWidth, videoHeight },
+ /* don't include jpeg thumbnail size - it's valid for
+ it to be set to (0,0), meaning 'no thumbnail' */
+ // { jpegThumbSize[0], jpegThumbSize[1] },
+ { pictureWidth, pictureHeight },
+ };
+
+ minOutputWidth = outputSizes[0][0];
+ minOutputHeight = outputSizes[0][1];
+ minOutputRatio = minOutputWidth / minOutputHeight;
+ for (unsigned int i = 0;
+ i < sizeof(outputSizes) / sizeof(outputSizes[0]);
+ ++i) {
+
+ float outputWidth = outputSizes[i][0];
+ float outputHeight = outputSizes[i][1];
+ float outputRatio = outputWidth / outputHeight;
+
+ if (minOutputRatio > outputRatio) {
+ minOutputRatio = outputRatio;
+ minOutputWidth = outputWidth;
+ minOutputHeight = outputHeight;
+ }
+
+ // and then use this output ratio instead of preview output ratio
+ ALOGV("Enumerating output ratio %f = %f / %f, min is %f",
+ outputRatio, outputWidth, outputHeight, minOutputRatio);
+ }
+ }
+
+ /* Ensure that the width/height never go out of bounds
+ * by scaling across a diffent dimension if an out-of-bounds
+ * possibility exists.
+ *
+ * e.g. if the previewratio < arrayratio and e.g. zoomratio = 1.0, then by
+ * calculating the zoomWidth from zoomHeight we'll actually get a
+ * zoomheight > arrayheight
+ */
+ float arrayRatio = 1.f * fastInfo.arrayWidth / fastInfo.arrayHeight;
+ if (minOutputRatio >= arrayRatio) {
+ // Adjust the height based on the width
+ zoomWidth = fastInfo.arrayWidth / zoomRatio;
+ zoomHeight = zoomWidth *
+ minOutputHeight / minOutputWidth;
+
+ } else {
+ // Adjust the width based on the height
+ zoomHeight = fastInfo.arrayHeight / zoomRatio;
+ zoomWidth = zoomHeight *
+ minOutputWidth / minOutputHeight;
+ }
+ // centering the zoom area within the active area
+ zoomLeft = (fastInfo.arrayWidth - zoomWidth) / 2;
+ zoomTop = (fastInfo.arrayHeight - zoomHeight) / 2;
+
+ ALOGV("Crop region calculated (x=%d,y=%d,w=%f,h=%f) for zoom=%d",
+ (int32_t)zoomLeft, (int32_t)zoomTop, zoomWidth, zoomHeight, this->zoom);
+
+
+ CropRegion crop = { zoomLeft, zoomTop, zoomWidth, zoomHeight };
+ return crop;
+}
+
}; // namespace camera2
}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/Parameters.h b/services/camera/libcameraservice/camera2/Parameters.h
index f768605..7789ebb 100644
--- a/services/camera/libcameraservice/camera2/Parameters.h
+++ b/services/camera/libcameraservice/camera2/Parameters.h
@@ -190,6 +190,15 @@ struct Parameters {
// Update passed-in request for common parameters
status_t updateRequest(CameraMetadata *request) const;
+ // Calculate the crop region rectangle based on current stream sizes
+ struct CropRegion {
+ float left;
+ float top;
+ float width;
+ float height;
+ };
+ CropRegion calculateCropRegion(void) const;
+
// Static methods for debugging and converting between camera1 and camera2
// parameters