diff options
author | Igor Murashkin <iam@google.com> | 2012-09-24 15:18:41 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-09-24 15:18:42 -0700 |
commit | aae1de9eaba5aa3e2bce68b59aa78f918020f5a8 (patch) | |
tree | dc94163f914abda0814140a704beb3a735e3ea70 /services | |
parent | 8d452f1c61aa70c4a86c4114532f2c0983120ef8 (diff) | |
parent | 018d228ac43a8da7d5f36e45fd105c9baf2490a0 (diff) | |
download | frameworks_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.cpp | 132 | ||||
-rw-r--r-- | services/camera/libcameraservice/camera2/Parameters.h | 9 |
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 |