下面列出了android.hardware.Camera.Area#android.hardware.camera2.params.MeteringRectangle 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static void mapAf(CameraMetadataNative m,
Rect activeArray, ZoomData zoomData, Camera.Parameters p) {
// control.afMode
m.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(p.getFocusMode()));
// control.afRegions
if (p.getMaxNumFocusAreas() > 0) {
if (DEBUG) {
String focusAreas = p.get("focus-areas");
Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas);
}
MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray,
zoomData, p.getFocusAreas(), "AF");
m.set(CONTROL_AF_REGIONS, meteringRectArray);
}
}
private static MeteringRectangle[] getMeteringRectangles(Rect activeArray, ZoomData zoomData,
List<Camera.Area> meteringAreaList, String regionName) {
List<MeteringRectangle> meteringRectList = new ArrayList<>();
if (meteringAreaList != null) {
for (Camera.Area area : meteringAreaList) {
WeightedRectangle rect =
ParameterUtils.convertCameraAreaToActiveArrayRectangle(
activeArray, zoomData, area);
meteringRectList.add(rect.toMetering());
}
}
if (DEBUG) {
Log.v(TAG,
"Metering rectangles for " + regionName + ": "
+ ListUtils.listToString(meteringRectList));
}
return meteringRectList.toArray(new MeteringRectangle[0]);
}
/**
* Convert to a metering rectangle, clipping any of the values to stay within range.
*
* <p>If values are clipped, a warning is printed to logcat.</p>
*
* @return a new metering rectangle
*/
public MeteringRectangle toMetering() {
int weight = clip(this.weight,
MeteringRectangle.METERING_WEIGHT_MIN,
MeteringRectangle.METERING_WEIGHT_MAX,
rect,
"weight");
int x = clipLower(rect.left, /*lo*/0, rect, "left");
int y = clipLower(rect.top, /*lo*/0, rect, "top");
int w = clipLower(rect.width(), /*lo*/0, rect, "width");
int h = clipLower(rect.height(), /*lo*/0, rect, "height");
return new MeteringRectangle(x, y, w, h, weight);
}
@Override
public void marshal(MeteringRectangle value, ByteBuffer buffer) {
int xMin = value.getX();
int yMin = value.getY();
int xMax = xMin + value.getWidth();
int yMax = yMin + value.getHeight();
int weight = value.getMeteringWeight();
buffer.putInt(xMin);
buffer.putInt(yMin);
buffer.putInt(xMax);
buffer.putInt(yMax);
buffer.putInt(weight);
}
@Override
public MeteringRectangle unmarshal(ByteBuffer buffer) {
int xMin = buffer.getInt();
int yMin = buffer.getInt();
int xMax = buffer.getInt();
int yMax = buffer.getInt();
int weight = buffer.getInt();
int width = xMax - xMin;
int height = yMax - yMin;
return new MeteringRectangle(xMin, yMin, width, height, weight);
}
public void autoFocus(@Nullable AutoFocusCallback cb, MotionEvent pEvent, int screenW, int screenH) {
if (cb != null) {
mAutoFocusCallback = cb;
}
if (sensorArraySize != null) {
final int y = (int) pEvent.getX() / screenW * sensorArraySize.height();
final int x = (int) pEvent.getY() / screenH * sensorArraySize.width();
final int halfTouchWidth = 150;
final int halfTouchHeight = 150;
MeteringRectangle focusAreaTouch = new MeteringRectangle(
Math.max(x - halfTouchWidth, 0),
Math.max(y - halfTouchHeight, 0),
halfTouchWidth * 2,
halfTouchHeight * 2,
MeteringRectangle.METERING_WEIGHT_MAX - 1);
try {
mCaptureSession.stopRepeating();
//Cancel any existing AF trigger (repeated touches, etc.)
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
//Now add a new AF trigger with focus region
if (isMeteringAreaAFSupported) {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusAreaTouch});
}
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewRequestBuilder.setTag("FOCUS_TAG"); //we'll capture this later for resuming the preview!
//Then we ask for a single request (not repeating!)
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException ex) {
Log.d("ASD", "AUTO FOCUS EXCEPTION: " + ex);
}
}
}
private ManualAutoFocusFactory(ManualAutoFocus manualAutoFocus,
Supplier<MeteringRectangle[]> aeMeteringRegion,
Supplier<MeteringRectangle[]> afMeteringRegion)
{
mManualAutoFocus = manualAutoFocus;
mAEMeteringRegion = aeMeteringRegion;
mAFMeteringRegion = afMeteringRegion;
}
/**
* @param cropRegion The current crop region, see
* {@link CaptureRequest#SCALER_CROP_REGION}.
*/
@Override
public MeteringRectangle[] getAERegions(Rect cropRegion)
{
return new MeteringRectangle[]{
regionForNormalizedCoord(mAEPoint, cropRegion)
};
}
/**
* @param cropRegion The current crop region, see
* {@link CaptureRequest#SCALER_CROP_REGION}.
*/
@Override
public MeteringRectangle[] getAFRegions(Rect cropRegion)
{
return new MeteringRectangle[]{
regionForNormalizedCoord(mAFPoint, cropRegion)
};
}
private MeteringRectangle regionForNormalizedCoord(PointF point,
Rect cropRegion)
{
// Compute half side length in pixels.
int minCropEdge = Math.min(cropRegion.width(), cropRegion.height());
int halfSideLength = (int) (0.5f * mSettings3A.getMeteringRegionFraction() * minCropEdge);
// Compute the output MeteringRectangle in sensor space.
// point is normalized to the screen.
// Crop region itself is specified in sensor coordinates (see
// CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE).
// Normalized coordinates, now rotated into sensor space.
PointF nsc = transformPortraitCoordinatesToSensorCoordinates(point);
int xCenterSensor = (int) (cropRegion.left + nsc.x * cropRegion.width());
int yCenterSensor = (int) (cropRegion.top + nsc.y * cropRegion.height());
Rect meteringRegion = new Rect(xCenterSensor - halfSideLength,
yCenterSensor - halfSideLength,
xCenterSensor + halfSideLength,
yCenterSensor + halfSideLength);
// Clamp meteringRegion to cropRegion.
meteringRegion.left = clamp(meteringRegion.left, cropRegion.left,
cropRegion.right);
meteringRegion.top = clamp(meteringRegion.top, cropRegion.top, cropRegion.bottom);
meteringRegion.right = clamp(meteringRegion.right, cropRegion.left,
cropRegion.right);
meteringRegion.bottom = clamp(meteringRegion.bottom, cropRegion.top,
cropRegion.bottom);
return new MeteringRectangle(meteringRegion, mSettings3A.getMeteringWeight());
}
/**
* Compute 3A regions for a sensor-referenced touch coordinate.
* Returns a MeteringRectangle[] with length 1.
*
* @param nx x coordinate of the touch point, in normalized portrait coordinates.
* @param ny y coordinate of the touch point, in normalized portrait coordinates.
* @param fraction Fraction in [0,1]. Multiplied by min(cropRegion.width(), cropRegion.height())
* to determine the side length of the square MeteringRectangle.
* @param cropRegion Crop region of the image.
* @param sensorOrientation sensor orientation as defined by
* CameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION).
*/
private static MeteringRectangle[] regionsForNormalizedCoord(float nx, float ny,
float fraction, final Rect cropRegion, int
sensorOrientation)
{
// Compute half side length in pixels.
int minCropEdge = Math.min(cropRegion.width(), cropRegion.height());
int halfSideLength = (int) (0.5f * fraction * minCropEdge);
// Compute the output MeteringRectangle in sensor space.
// nx, ny is normalized to the screen.
// Crop region itself is specified in sensor coordinates.
// Normalized coordinates, now rotated into sensor space.
PointF nsc = CameraUtil.normalizedSensorCoordsForNormalizedDisplayCoords(
nx, ny, sensorOrientation);
int xCenterSensor = (int) (cropRegion.left + nsc.x * cropRegion.width());
int yCenterSensor = (int) (cropRegion.top + nsc.y * cropRegion.height());
Rect meteringRegion = new Rect(xCenterSensor - halfSideLength,
yCenterSensor - halfSideLength,
xCenterSensor + halfSideLength,
yCenterSensor + halfSideLength);
// Clamp meteringRegion to cropRegion.
meteringRegion.left = CameraUtil.clamp(meteringRegion.left, cropRegion.left, cropRegion.right);
meteringRegion.top = CameraUtil.clamp(meteringRegion.top, cropRegion.top, cropRegion.bottom);
meteringRegion.right = CameraUtil.clamp(meteringRegion.right, cropRegion.left, cropRegion.right);
meteringRegion.bottom = CameraUtil.clamp(meteringRegion.bottom, cropRegion.top, cropRegion.bottom);
return new MeteringRectangle[]{new MeteringRectangle(meteringRegion, CAMERA2_REGION_WEIGHT)};
}
/**
* @Return The weight to use for {@link MeteringRectangle}s for 3A.
*/
public int getMeteringWeight()
{
// TODO Determine the optimal metering region for non-HDR photos.
int weightMin = MeteringRectangle.METERING_WEIGHT_MIN;
int weightRange = MeteringRectangle.METERING_WEIGHT_MAX
- MeteringRectangle.METERING_WEIGHT_MIN;
return (int) (weightMin + GCAM_METERING_REGION_FRACTION * weightRange);
}
public void autoFocus(@Nullable AutoFocusCallback cb, MotionEvent pEvent, int screenW, int screenH) {
if(cb != null) {
mAutoFocusCallback = cb;
}
if(sensorArraySize != null) {
final int y = (int)pEvent.getX() / screenW * sensorArraySize.height();
final int x = (int)pEvent.getY() / screenH * sensorArraySize.width();
final int halfTouchWidth = 150;
final int halfTouchHeight = 150;
MeteringRectangle focusAreaTouch = new MeteringRectangle(
Math.max(x-halfTouchWidth, 0),
Math.max(y-halfTouchHeight, 0),
halfTouchWidth*2,
halfTouchHeight*2,
MeteringRectangle.METERING_WEIGHT_MAX - 1);
try {
mCaptureSession.stopRepeating();
//Cancel any existing AF trigger (repeated touches, etc.)
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
//Now add a new AF trigger with focus region
if(isMeteringAreaAFSupported) {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusAreaTouch});
}
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewRequestBuilder.setTag("FOCUS_TAG"); //we'll capture this later for resuming the preview!
//Then we ask for a single request (not repeating!)
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch(CameraAccessException ex) {
Log.d("ASD", "AUTO FOCUS EXCEPTION: "+ex);
}
}
}
public static MeteringRectangle[] regionsForNormalizedCoord(float nx, float ny,
float fraction, final Rect cropRegion, int sensorOrientation) {
// Compute half side length in pixels.
int minCropEdge = Math.min(cropRegion.width(), cropRegion.height());
int halfSideLength = (int) (0.5f * fraction * minCropEdge);
// Compute the output MeteringRectangle in sensor space.
// nx, ny is normalized to the screen.
// Crop region itself is specified in sensor coordinates.
// Normalized coordinates, now rotated into sensor space.
PointF nsc = CameraUtil.normalizedSensorCoordsForNormalizedDisplayCoords(
nx, ny, sensorOrientation);
int xCenterSensor = (int) (cropRegion.left + nsc.x * cropRegion.width());
int yCenterSensor = (int) (cropRegion.top + nsc.y * cropRegion.height());
Rect meteringRegion = new Rect(xCenterSensor - halfSideLength,
yCenterSensor - halfSideLength,
xCenterSensor + halfSideLength,
yCenterSensor + halfSideLength);
// Clamp meteringRegion to cropRegion.
meteringRegion.left = CameraUtil.clamp(meteringRegion.left, cropRegion.left, cropRegion.right);
meteringRegion.top = CameraUtil.clamp(meteringRegion.top, cropRegion.top, cropRegion.bottom);
meteringRegion.right = CameraUtil.clamp(meteringRegion.right, cropRegion.left, cropRegion.right);
meteringRegion.bottom = CameraUtil.clamp(meteringRegion.bottom, cropRegion.top, cropRegion.bottom);
return new MeteringRectangle[]{new MeteringRectangle(meteringRegion, CAMERA2_REGION_WEIGHT)};
}
private static void mapAe(CameraMetadataNative m,
CameraCharacteristics characteristics,
CaptureRequest request, Rect activeArray, ZoomData zoomData, /*out*/Parameters p) {
// control.aeAntiBandingMode
{
int antiBandingMode = LegacyMetadataMapper.convertAntiBandingModeOrDefault(
p.getAntibanding());
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);
if (DEBUG) {
Log.v(TAG,
"mapAe - android.control.aeLock = " + lock +
", supported = " + p.isAutoExposureLockSupported());
}
Boolean requestLock = request.get(CaptureRequest.CONTROL_AE_LOCK);
if (requestLock != null && requestLock != lock) {
Log.w(TAG,
"mapAe - android.control.aeLock was requested to " + requestLock +
" but resulted in " + lock);
}
}
// control.aeMode, flash.mode, flash.state
mapAeAndFlashMode(m, characteristics, p);
// control.aeState
if (LegacyMetadataMapper.LIE_ABOUT_AE_STATE) {
// Lie to pass CTS temporarily.
// TODO: Implement precapture trigger, after which we can report CONVERGED ourselves
m.set(CONTROL_AE_STATE, CONTROL_AE_STATE_CONVERGED);
}
// control.aeRegions
if (p.getMaxNumMeteringAreas() > 0) {
if (DEBUG) {
String meteringAreas = p.get("metering-areas");
Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas);
}
MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray,
zoomData, p.getMeteringAreas(), "AE");
m.set(CONTROL_AE_REGIONS, meteringRectArray);
}
}
/**
* Calculate the actual/effective/reported normalized rectangle data from a metering
* rectangle.
*
* <p>If any of the rectangles are out-of-range of their intended bounding box,
* the {@link #RECTANGLE_EMPTY empty rectangle} is substituted instead
* (with a weight of {@code 0}).</p>
*
* <p>The metering rectangle is bound by the crop region (effective/reported respectively).
* The metering {@link Camera.Area area} is bound by {@code [-1000, 1000]}.</p>
*
* <p>No parameters are mutated; returns the new metering data.</p>
*
* @param activeArraySize active array size of the sensor (e.g. max jpeg size)
* @param meteringRect the user-specified metering rectangle
* @param zoomData the calculated zoom data corresponding to this request
*
* @return the metering area, the reported/effective metering rectangles
*/
public static MeteringData convertMeteringRectangleToLegacy(
Rect activeArray, MeteringRectangle meteringRect, ZoomData zoomData) {
Rect previewCrop = zoomData.previewCrop;
float scaleW = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f /
previewCrop.width();
float scaleH = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f /
previewCrop.height();
Matrix transform = new Matrix();
// Move the preview crop so that top,left is at (0,0), otherwise after scaling
// the corner bounds will be outside of [-1000, 1000]
transform.setTranslate(-previewCrop.left, -previewCrop.top);
// Scale into [0, 2000] range about the center of the preview
transform.postScale(scaleW, scaleH);
// Move so that top left of a typical rect is at [-1000, -1000]
transform.postTranslate(/*dx*/NORMALIZED_RECTANGLE_MIN, /*dy*/NORMALIZED_RECTANGLE_MIN);
/*
* Calculate the preview metering region (effective), and the camera1 api
* normalized metering region.
*/
Rect normalizedRegionUnbounded = ParamsUtils.mapRect(transform, meteringRect.getRect());
/*
* Try to intersect normalized area with [-1000, 1000] rectangle; otherwise
* it's completely out of range
*/
Rect normalizedIntersected = new Rect(normalizedRegionUnbounded);
Camera.Area meteringArea;
if (!normalizedIntersected.intersect(NORMALIZED_RECTANGLE_DEFAULT)) {
Log.w(TAG,
"convertMeteringRectangleToLegacy - metering rectangle too small, " +
"no metering will be done");
normalizedIntersected.set(RECTANGLE_EMPTY);
meteringArea = new Camera.Area(RECTANGLE_EMPTY,
MeteringRectangle.METERING_WEIGHT_DONT_CARE);
} else {
meteringArea = new Camera.Area(normalizedIntersected,
meteringRect.getMeteringWeight());
}
/*
* Calculate effective preview metering region
*/
Rect previewMetering = meteringRect.getRect();
if (!previewMetering.intersect(previewCrop)) {
previewMetering.set(RECTANGLE_EMPTY);
}
/*
* Calculate effective reported metering region
* - Transform the calculated metering area back into active array space
* - Clip it to be a subset of the reported crop region
*/
Rect reportedMetering;
{
Camera.Area normalizedAreaUnbounded = new Camera.Area(
normalizedRegionUnbounded, meteringRect.getMeteringWeight());
WeightedRectangle reportedMeteringRect = convertCameraAreaToActiveArrayRectangle(
activeArray, zoomData, normalizedAreaUnbounded, /*usePreviewCrop*/false);
reportedMetering = reportedMeteringRect.rect;
}
if (DEBUG) {
Log.v(TAG, String.format(
"convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, " +
"previewCrop = %s, meteringArea = %s, previewMetering = %s, " +
"reportedMetering = %s, normalizedRegionUnbounded = %s",
activeArray, meteringRect,
previewCrop, stringFromArea(meteringArea), previewMetering,
reportedMetering, normalizedRegionUnbounded));
}
return new MeteringData(meteringArea, previewMetering, reportedMetering);
}
private static WeightedRectangle convertCameraAreaToActiveArrayRectangle(
Rect activeArray, ZoomData zoomData, Camera.Area area, boolean usePreviewCrop) {
Rect previewCrop = zoomData.previewCrop;
Rect reportedCrop = zoomData.reportedCrop;
float scaleW = previewCrop.width() * 1.0f /
(NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN);
float scaleH = previewCrop.height() * 1.0f /
(NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN);
/*
* Calculate the reported metering region from the non-intersected normalized region
* by scaling and translating back into active array-relative coordinates.
*/
Matrix transform = new Matrix();
// Move top left from (-1000, -1000) to (0, 0)
transform.setTranslate(/*dx*/NORMALIZED_RECTANGLE_MAX, /*dy*/NORMALIZED_RECTANGLE_MAX);
// Scale from [0, 2000] back into the preview rectangle
transform.postScale(scaleW, scaleH);
// Move the rect so that the [-1000,-1000] point ends up at the preview [left, top]
transform.postTranslate(previewCrop.left, previewCrop.top);
Rect cropToIntersectAgainst = usePreviewCrop ? previewCrop : reportedCrop;
// Now apply the transformation backwards to get the reported metering region
Rect reportedMetering = ParamsUtils.mapRect(transform, area.rect);
// Intersect it with the crop region, to avoid reporting out-of-bounds
// metering regions
if (!reportedMetering.intersect(cropToIntersectAgainst)) {
reportedMetering.set(RECTANGLE_EMPTY);
}
int weight = area.weight;
if (weight < MeteringRectangle.METERING_WEIGHT_MIN) {
Log.w(TAG,
"convertCameraAreaToMeteringRectangle - rectangle "
+ stringFromArea(area) + " has too small weight, clip to 0");
weight = 0;
}
return new WeightedRectangle(reportedMetering, area.weight);
}
protected MarshalerMeteringRectangle(TypeReference<MeteringRectangle> typeReference,
int nativeType) {
super(MarshalQueryableMeteringRectangle.this, typeReference, nativeType);
}
@Override
public Marshaler<MeteringRectangle> createMarshaler(
TypeReference<MeteringRectangle> managedType, int nativeType) {
return new MarshalerMeteringRectangle(managedType, nativeType);
}
@Override
public boolean isTypeMappingSupported(
TypeReference<MeteringRectangle> managedType, int nativeType) {
return nativeType == TYPE_INT32 && MeteringRectangle.class.equals(managedType.getType());
}
@Override
public MeteringRectangle[] getAFRegions(Rect cropRegion)
{
return ZERO_WEIGHT_3A_REGION;
}
@Override
public MeteringRectangle[] getAERegions(Rect cropRegion)
{
return ZERO_WEIGHT_3A_REGION;
}
public Supplier<MeteringRectangle[]> provideAEMeteringRegion()
{
return mAEMeteringRegion;
}
public Supplier<MeteringRectangle[]> provideAFMeteringRegion()
{
return mAFMeteringRegion;
}
@Override
public MeteringRectangle[] get()
{
return mMeteringParameters.get().getAFRegions(mCropRegion.get());
}
@Override
public MeteringRectangle[] get()
{
return mMeteringParameters.get().getAERegions(mCropRegion.get());
}
public static MeteringRectangle[] getZeroWeightRegion()
{
return ZERO_WEIGHT_3A_REGION;
}
/**
* @param lifetime The lifetime of all created objects and their associated
* resources.
* @param cameraCharacteristics
* @param rootTemplate Provides preconfigured request builders to be used for
* all requests to mFrameServer.
* @param cameraCommandExecutor The
* @param templateType The template (e.g. CameraDevice.TEMPLATE_PREVIEW) to
* use for repeating requests.
*/
public BasicCameraFactory(Lifetime lifetime,
OneCameraCharacteristics cameraCharacteristics,
FrameServer frameServer,
RequestBuilder.Factory rootTemplate,
CameraCommandExecutor cameraCommandExecutor,
PreviewCommandFactory previewCommandFactory,
Observable<OneCamera.PhotoCaptureParameters.Flash> flash,
Observable<Integer> exposure,
Observable<Float> zoom,
Observable<Boolean> hdrSceneSetting,
int templateType)
{
RequestTemplate requestTemplate = new RequestTemplate(rootTemplate);
requestTemplate.setParam(
CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
requestTemplate.setParam(
CaptureRequest.CONTROL_AE_MODE, new FlashBasedAEMode(flash, hdrSceneSetting));
requestTemplate.setParam(
CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposure);
Supplier<FaceDetectMode> faceDetectMode = Suppliers.ofInstance(
FaceDetect.getHighestFaceDetectMode(cameraCharacteristics));
requestTemplate.setParam(CaptureRequest.CONTROL_MODE,
new ControlModeSelector(hdrSceneSetting,
faceDetectMode,
cameraCharacteristics.getSupportedHardwareLevel()));
requestTemplate.setParam(
CaptureRequest.CONTROL_SCENE_MODE, new ControlSceneModeSelector(
hdrSceneSetting,
faceDetectMode,
cameraCharacteristics.getSupportedHardwareLevel()));
requestTemplate.setParam(CaptureRequest.STATISTICS_FACE_DETECT_MODE,
new StatisticsFaceDetectMode(faceDetectMode));
Supplier<Rect> cropRegion = new ZoomedCropRegion(
cameraCharacteristics.getSensorInfoActiveArraySize(), zoom);
requestTemplate.setParam(CaptureRequest.SCALER_CROP_REGION, cropRegion);
CameraCommand previewUpdaterCommand =
previewCommandFactory.get(requestTemplate, templateType);
// Use a resetting command to ensure that many rapid settings changes do
// not result in many rapid (>30fps) requests to restart the preview.
mPreviewUpdater = new ResettingRunnableCameraCommand(cameraCommandExecutor,
previewUpdaterCommand);
// Resend the repeating preview request when the zoom or flash state
// changes to apply the new setting.
// Also, de-register these callbacks when the camera is closed (to
// not leak memory).
SafeCloseable zoomCallback = zoom.addCallback(mPreviewUpdater, MoreExecutors
.sameThreadExecutor());
lifetime.add(zoomCallback);
SafeCloseable flashCallback = flash.addCallback(mPreviewUpdater, MoreExecutors
.sameThreadExecutor());
lifetime.add(flashCallback);
SafeCloseable exposureCallback = exposure.addCallback(mPreviewUpdater, MoreExecutors
.sameThreadExecutor());
lifetime.add(exposureCallback);
SafeCloseable hdrCallback = hdrSceneSetting.addCallback(mPreviewUpdater, MoreExecutors
.sameThreadExecutor());
lifetime.add(hdrCallback);
int sensorOrientation = cameraCharacteristics.getSensorOrientation();
ManualAutoFocusFactory manualAutoFocusFactory = ManualAutoFocusFactory.create(new
Lifetime(lifetime), frameServer, cameraCommandExecutor, cropRegion,
sensorOrientation, mPreviewUpdater, requestTemplate,
templateType, new Settings3A(), Executors.newScheduledThreadPool(1),
3 /* afHoldSeconds */);
mManualAutoFocus = manualAutoFocusFactory.provideManualAutoFocus();
Supplier<MeteringRectangle[]> aeRegions =
manualAutoFocusFactory.provideAEMeteringRegion();
Supplier<MeteringRectangle[]> afRegions =
manualAutoFocusFactory.provideAFMeteringRegion();
requestTemplate.setParam(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
requestTemplate.setParam(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
mMeteredZoomedRequestBuilder = requestTemplate;
}
public void focusOnPoint(double x, double y, int width, int height) {
if (mCameraDevice == null || mPreviewRequestBuilder == null) {
return;
}
// 1. 先取相对于view上面的坐标
int previewWidth = mPreviewSize.getWidth();
int previewHeight = mPreviewSize.getHeight();
if (mDisplayRotate == 90 || mDisplayRotate == 270) {
previewWidth = mPreviewSize.getHeight();
previewHeight = mPreviewSize.getWidth();
}
// 2. 计算摄像头取出的图像相对于view放大了多少,以及有多少偏移
double tmp;
double imgScale;
double verticalOffset = 0;
double horizontalOffset = 0;
if (previewHeight * width > previewWidth * height) {
imgScale = width * 1.0 / previewWidth;
verticalOffset = (previewHeight - height / imgScale) / 2;
} else {
imgScale = height * 1.0 / previewHeight;
horizontalOffset = (previewWidth - width / imgScale) / 2;
}
// 3. 将点击的坐标转换为图像上的坐标
x = x / imgScale + horizontalOffset;
y = y / imgScale + verticalOffset;
if (90 == mDisplayRotate) {
tmp = x;
x = y;
y = mPreviewSize.getHeight() - tmp;
} else if (270 == mDisplayRotate) {
tmp = x;
x = mPreviewSize.getWidth() - y;
y = tmp;
}
// 4. 计算取到的图像相对于裁剪区域的缩放系数,以及位移
Rect cropRegion = mPreviewRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION);
if (cropRegion == null) {
Log.w(TAG, "can't get crop region");
cropRegion = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
}
int cropWidth = cropRegion.width();
int cropHeight = cropRegion.height();
if (mPreviewSize.getHeight() * cropWidth > mPreviewSize.getWidth() * cropHeight) {
imgScale = cropHeight * 1.0 / mPreviewSize.getHeight();
verticalOffset = 0;
horizontalOffset = (cropWidth - imgScale * mPreviewSize.getWidth()) / 2;
} else {
imgScale = cropWidth * 1.0 / mPreviewSize.getWidth();
horizontalOffset = 0;
verticalOffset = (cropHeight - imgScale * mPreviewSize.getHeight()) / 2;
}
// 5. 将点击区域相对于图像的坐标,转化为相对于成像区域的坐标
x = x * imgScale + horizontalOffset + cropRegion.left;
y = y * imgScale + verticalOffset + cropRegion.top;
double tapAreaRatio = 0.1;
Rect rect = new Rect();
rect.left = clamp((int) (x - tapAreaRatio / 2 * cropRegion.width()), 0, cropRegion.width());
rect.right = clamp((int) (x + tapAreaRatio / 2 * cropRegion.width()), 0, cropRegion.width());
rect.top = clamp((int) (y - tapAreaRatio / 2 * cropRegion.height()), 0, cropRegion.height());
rect.bottom = clamp((int) (y + tapAreaRatio / 2 * cropRegion.height()), 0, cropRegion.height());
// 6. 设置 AF、AE 的测光区域,即上述得到的 rect
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{new MeteringRectangle
(rect, 1000)});
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[]{new MeteringRectangle
(rect, 1000)});
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata
.CONTROL_AE_PRECAPTURE_TRIGGER_START);
try {
// 7. 发送上述设置的对焦请求,并监听回调
mCaptureSession.capture(mPreviewRequestBuilder.build(), mAfCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
public static MeteringRectangle[] getZeroWeightRegion() {
return ZERO_WEIGHT_3A_REGION;
}